Rglpk/0000755000176000001440000000000012245405147011365 5ustar ripleyusersRglpk/inst/0000755000176000001440000000000012245352174012343 5ustar ripleyusersRglpk/inst/examples/0000755000176000001440000000000012245352174014161 5ustar ripleyusersRglpk/inst/examples/plan.lp0000644000176000001440000000234612175147600015453 0ustar ripleyusers\* plan.lp *\ Minimize value: .03 bin1 + .08 bin2 + .17 bin3 + .12 bin4 + .15 bin5 + .21 alum + .38 silicon Subject To yield: bin1 + bin2 + bin3 + bin4 + bin5 + alum + silicon = 2000 fe: .15 bin1 + .04 bin2 + .02 bin3 + .04 bin4 + .02 bin5 + .01 alum + .03 silicon <= 60 cu: .03 bin1 + .05 bin2 + .08 bin3 + .02 bin4 + .06 bin5 + .01 alum <= 100 mn: .02 bin1 + .04 bin2 + .01 bin3 + .02 bin4 + .02 bin5 <= 40 mg: .02 bin1 + .03 bin2 + .01 bin5 <= 30 al: .70 bin1 + .75 bin2 + .80 bin3 + .75 bin4 + .80 bin5 + .97 alum >= 1500 si1: .02 bin1 + .06 bin2 + .08 bin3 + .12 bin4 + .02 bin5 + .01 alum + .97 silicon >= 250 si2: .02 bin1 + .06 bin2 + .08 bin3 + .12 bin4 + .02 bin5 + .01 alum + .97 silicon <= 300 Bounds bin1 <= 200 bin2 <= 2500 400 <= bin3 <= 800 100 <= bin4 <= 700 bin5 <= 1500 End \* eof *\ Rglpk/inst/examples/plan.mod0000644000176000001440000000164112175147600015614 0ustar ripleyusers/* plan.mod */ var bin1, >= 0, <= 200; var bin2, >= 0, <= 2500; var bin3, >= 400, <= 800; var bin4, >= 100, <= 700; var bin5, >= 0, <= 1500; var alum, >= 0; var silicon, >= 0; minimize value: .03 * bin1 + .08 * bin2 + .17 * bin3 + .12 * bin4 + .15 * bin5 + .21 * alum + .38 * silicon; subject to yield: bin1 + bin2 + bin3 + bin4 + bin5 + alum + silicon = 2000; fe: .15 * bin1 + .04 * bin2 + .02 * bin3 + .04 * bin4 + .02 * bin5 + .01 * alum + .03 * silicon <= 60; cu: .03 * bin1 + .05 * bin2 + .08 * bin3 + .02 * bin4 + .06 * bin5 + .01 * alum <= 100; mn: .02 * bin1 + .04 * bin2 + .01 * bin3 + .02 * bin4 + .02 * bin5 <= 40; mg: .02 * bin1 + .03 * bin2 + .01 * bin5 <= 30; al: .70 * bin1 + .75 * bin2 + .80 * bin3 + .75 * bin4 + .80 * bin5 + .97 * alum >= 1500; si: 250 <= .02 * bin1 + .06 * bin2 + .08 * bin3 + .12 * bin4 + .02 * bin5 + .01 * alum + .97 * silicon <= 300; end; /* eof */ Rglpk/inst/examples/assign.mod0000644000176000001440000000404512175147600016147 0ustar ripleyusers/* ASSIGN, Assignment Problem */ /* Written in GNU MathProg by Andrew Makhorin */ /* The assignment problem is one of the fundamental combinatorial optimization problems. In its most general form, the problem is as follows: There are a number of agents and a number of tasks. Any agent can be assigned to perform any task, incurring some cost that may vary depending on the agent-task assignment. It is required to perform all tasks by assigning exactly one agent to each task in such a way that the total cost of the assignment is minimized. (From Wikipedia, the free encyclopedia.) */ param m, integer, > 0; /* number of agents */ param n, integer, > 0; /* number of tasks */ set I := 1..m; /* set of agents */ set J := 1..n; /* set of tasks */ param c{i in I, j in J}, >= 0; /* cost of allocating task j to agent i */ var x{i in I, j in J}, >= 0; /* x[i,j] = 1 means task j is assigned to agent i note that variables x[i,j] are binary, however, there is no need to declare them so due to the totally unimodular constraint matrix */ s.t. phi{i in I}: sum{j in J} x[i,j] <= 1; /* each agent can perform at most one task */ s.t. psi{j in J}: sum{i in I} x[i,j] = 1; /* each task must be assigned exactly to one agent */ minimize obj: sum{i in I, j in J} c[i,j] * x[i,j]; /* the objective is to find a cheapest assignment */ solve; printf "\n"; printf "Agent Task Cost\n"; printf{i in I} "%5d %5d %10g\n", i, sum{j in J} j * x[i,j], sum{j in J} c[i,j] * x[i,j]; printf "----------------------\n"; printf " Total: %10g\n", sum{i in I, j in J} c[i,j] * x[i,j]; printf "\n"; data; /* These data correspond to an example from [Christofides]. */ /* Optimal solution is 76 */ param m := 8; param n := 8; param c : 1 2 3 4 5 6 7 8 := 1 13 21 20 12 8 26 22 11 2 12 36 25 41 40 11 4 8 3 35 32 13 36 26 21 13 37 4 34 54 7 8 12 22 11 40 5 21 6 45 18 24 34 12 48 6 42 19 39 15 14 16 28 46 7 16 34 38 3 34 40 22 24 8 26 20 5 17 45 31 37 43 ; end; Rglpk/inst/examples/plan.mps0000644000176000001440000000432612175147600015637 0ustar ripleyusers*000000001111111111222222222233333333334444444444555555555566 *234567890123456789012345678901234567890123456789012345678901 NAME PLAN ROWS N VALUE E YIELD L FE L CU L MN L MG G AL L SI COLUMNS BIN1 VALUE .03000 YIELD 1.00000 FE .15000 CU .03000 MN .02000 MG .02000 AL .70000 SI .02000 BIN2 VALUE .08000 YIELD 1.00000 FE .04000 CU .05000 MN .04000 MG .03000 AL .75000 SI .06000 BIN3 VALUE .17000 YIELD 1.00000 FE .02000 CU .08000 MN .01000 AL .80000 SI .08000 BIN4 VALUE .12000 YIELD 1.00000 FE .04000 CU .02000 MN .02000 AL .75000 SI .12000 BIN5 VALUE .15000 YIELD 1.00000 FE .02000 CU .06000 MN .02000 MG .01000 AL .80000 SI .02000 ALUM VALUE .21000 YIELD 1.00000 FE .01000 CU .01000 AL .97000 SI .01000 SILICON VALUE .38000 YIELD 1.00000 FE .03000 SI .97000 RHS RHS1 YIELD 2000.00000 FE 60.00000 CU 100.00000 MN 40.00000 SI 300.00000 MG 30.00000 AL 1500.00000 RANGES RNG1 SI 50.00000 BOUNDS UP BND1 BIN1 200.00000 UP BIN2 2500.00000 LO BIN3 400.00000 UP BIN3 800.00000 LO BIN4 100.00000 UP BIN4 700.00000 UP BIN5 1500.00000 ENDATA Rglpk/inst/CHANGELOG0000644000176000001440000001064112245336313013554 0ustar ripleyusers2013-11-27 Stefan Theussl * UPDATED: Rglpk now ships with GLPK sources version 4.52.1 * FIXED: handling of bounds passed down from ROI * RELEASE: Rglpk 0.5-2 on CRAN 2013-06-03 Stefan Theussl * UPDATED: Rglpk now ships with GLPK sources version 4.52 * UPDATED: new patches are needed for this GLPK release. * FIXED: Copyright holder statements as demanded by CRAN policy * RELEASE: Rglpk 0.5-1 on CRAN 2013-06-03 Stefan Theussl * UPDATED: Rglpk now ships with GLPK sources version 4.50 * UPDATED: some extra patches are needed for this GLPK release. * RELEASE: Rglpk 0.4-1 on CRAN 2012-09-11 Stefan Theussl * UPDATED: argument list now in the following order: obj, mat, dir, rhs, bounds = NULL, types = NULL, max = FALSE, control = NULL. Currently, control can only be used for setting verbosity level. * UPDATED: use only a subset of file reader example data * FIXED: file reader improvements (C API), thx to ceeboo * RELEASE: Rglpk 0.3-10 on CRAN 2012-09-04 Stefan Theussl * ADDED: example data for file reader function * FIXED: fixing segfault when reading large instances from files * UPDATED: maintainer mail address * RELEASE: Rglpk 0.3-9 on CRAN 2012-01-16 Stefan Theussl * FIXED: gcc 4.5.x warning * RELEASE: Rglpk 0.3-8 on CRAN 2012-01-12 Stefan Theussl * ADDED: added MATHPROG reader support * ADDED: retrieving constraint names from file based instances * RELEASE: Rglpk 0.3-7 on CRAN 2011-12-30 Stefan Theussl * UPDATED: now using packageStartupMessage() * UPDATED: Windows build toolchain changed * UPDATED: configure script now searching for system library * UPDATED: Rglpk now includes GLPK sources of version 4.47 * RELEASE: Rglpk 0.3-7 on CRAN 2010-02-15 Stefan Theussl * FIXED: Further Windows improvements (Makevars.win, Makefile.win) * RELEASE: Rglpk 0.3-5 on CRAN 2010-02-02 Stefan Theussl * FIXED: Now includes a static library for windows * RELEASE: Rglpk 0.3-4 on CRAN 2010-01-28 Stefan Theussl * UPDATED: Rglpk now includes GLPK version 4.42 * FIXED: compile warnings have been fixed in Upstream code * ADDED: Windows support via separate configure script and Makevars * RELEASE: Rglpk 0.3-3 on CRAN 2009-09-07 Stefan Theussl * UPDATED: Rglpk now includes GLPK version 4.39 * FIXED: lower, upper bound conversion in bound_table * ADDED: separate configure script and Makevars due to major changes in upstream code 2009-06-26 Stefan Theussl * REMOVED: sparse matrix support from Rglpk package * ADDED: slam dependency which replaces the old S3 sparse matrix support * RELEASE: Rglpk 0.3-1 on CRAN 2009-03-30 Stefan Theussl * UPDATED: Rglpk now includes GLPK version 4.37 * RELEASE: Rglpk 0.2-9 on CRAN 2009-02-06 Stefan Theussl * UPDATED: Rglpk now includes GLPK version 4.36 * RELEASE: Rglpk 0.2-8 on CRAN 2008-12-08 Stefan Theussl * UPDATED: Rglpk now includes GLPK version 4.34 * RELEASE: Rglpk 0.2-7 on CRAN 2008-11-16 Stefan Theussl * UPDATED: Rglpk now includes GLPK version 4.33 * FIXED: replaced abort() with error() statments * RELEASE: Rglpk 0.2-6 on CRAN 2008-09-27 Stefan Theussl * UPDATED: Rglpk now includes GLPK version 4.31 2008-08-20 Stefan Theussl * RELEASE: Rglpk 0.2-5 on CRAN 2008-08-15 Stefan Theussl * UPDATED: GLPK 4.30 * FIXED: read/write MPS files new low level C routines * ADDED: .onLoad function to initialize default printer in C (Rprintf) * ADDED: GLPK version information printed in R after loading shared library 2008-07-30 Stefan Theussl * FIXED: integer/binary variables are now rounded to reduce failures due to numerical artefacts 2008-07-21 Stefan Theussl * UPDATED: GLPK 4.29 integrated 2008-06-06 Stefan Theussl * RELEASE: Rglpk released to CRAN. It interfaces GLPK version 4.28. Facilities to read MPS and CPLEX-LP format added. Rglpk/src/0000755000176000001440000000000012245352174012155 5ustar ripleyusersRglpk/src/Rglpk_read_file.c0000644000176000001440000001716712245352174015406 0ustar ripleyusers/* These are the interface functions to GLPK's MPS reader/writer Since * 2012-01-11: Rglpk now supports MATHPROG files and retrieves * variables names and constraints names. Thanks to Michael Kapler! * 2012-09-06: A fix to random segfaults introduced with the patch by * Michael has been contributed by Christian Buchta. */ #include "Rglpk.h" #include // pointer to problem object. static glp_prob *lp = NULL; // call destructor from the R level to guarantee that data has been // copied to R data structures. void Rglpk_delete_prob() { extern glp_prob *lp; // delete problem object (if any) if (lp){ glp_delete_prob(lp); lp = NULL; } } // read in all necessary elements for retrieving the LP/MILP void Rglpk_read_file (char **file, int *type, int *lp_direction_of_optimization, int *lp_n_constraints, int *lp_n_objective_vars, int *lp_n_values_in_constraint_matrix, int *lp_n_integer_vars, int *lp_n_binary_vars, char **lp_prob_name, char **lp_obj_name, int *lp_verbosity) { int status; extern glp_prob *lp; glp_tran *tran; const char *str; // Turn on/off Terminal Output if (*lp_verbosity==1) glp_term_out(GLP_ON); else glp_term_out(GLP_OFF); // create problem object if (lp) glp_delete_prob(lp); lp = glp_create_prob(); // read file -> gets stored as an GLPK problem object 'lp' // which file type do we have? switch (*type){ case 1: // Fixed (ancient) MPS Format, param argument currently NULL status = glp_read_mps(lp, GLP_MPS_DECK, NULL, *file); break; case 2: // Free (modern) MPS format, param argument currently NULL status = glp_read_mps(lp, GLP_MPS_FILE, NULL, *file); break; case 3: // CPLEX LP Format status = glp_read_lp(lp, NULL, *file); break; case 4: // MATHPROG Format (based on lpx_read_model function) tran = glp_mpl_alloc_wksp(); status = glp_mpl_read_model(tran, *file, 0); if (!status) { status = glp_mpl_generate(tran, NULL); if (!status) { glp_mpl_build_prob(tran, lp); } } glp_mpl_free_wksp(tran); break; } // if file read successfully glp_read_* returns zero if ( status != 0 ) { glp_delete_prob(lp); lp = NULL; error("Reading file %s failed", *file); } // retrieve problem name str = glp_get_prob_name(lp); if (str){ *lp_prob_name = (char *) str; } // retrieve name of objective function str = glp_get_obj_name(lp); if (str){ *lp_obj_name = (char *) str; } // retrieve optimization direction flag *lp_direction_of_optimization = glp_get_obj_dir(lp); // retrieve number of constraints *lp_n_constraints = glp_get_num_rows(lp); // retrieve number of objective variables *lp_n_objective_vars = glp_get_num_cols(lp); // retrieve number of non-zero elements in constraint matrix *lp_n_values_in_constraint_matrix = glp_get_num_nz(lp); // retrieve number of integer variables *lp_n_integer_vars = glp_get_num_int(lp); // retrieve number of binary variables *lp_n_binary_vars = glp_get_num_bin(lp); } // retrieve all missing values of LP/MILP void Rglpk_retrieve_MP_from_file (char **file, int *type, int *lp_n_constraints, int *lp_n_objective_vars, double *lp_objective_coefficients, int *lp_constraint_matrix_i, int *lp_constraint_matrix_j, double *lp_constraint_matrix_values, int *lp_direction_of_constraints, double *lp_right_hand_side, double *lp_left_hand_side, int *lp_objective_var_is_integer, int *lp_objective_var_is_binary, int *lp_bounds_type, double *lp_bounds_lower, double *lp_bounds_upper, int *lp_ignore_first_row, int *lp_verbosity, char **lp_constraint_names, char **lp_objective_vars_names ) { extern glp_prob *lp; glp_tran *tran; const char *str; int i, j, lp_column_kind, tmp; int ind_offset, status; // Turn on/off Terminal Output if (*lp_verbosity==1) glp_term_out(GLP_ON); else glp_term_out(GLP_OFF); // create problem object if (lp) glp_delete_prob(lp); lp = glp_create_prob(); // read file -> gets stored as an GLPK problem object 'lp' // which file type do we have? switch (*type){ case 1: // Fixed (ancient) MPS Format, param argument currently NULL status = glp_read_mps(lp, GLP_MPS_DECK, NULL, *file); break; case 2: // Free (modern) MPS format, param argument currently NULL status = glp_read_mps(lp, GLP_MPS_FILE, NULL, *file); break; case 3: // CPLEX LP Format status = glp_read_lp(lp, NULL, *file); break; case 4: // MATHPROG Format (based on lpx_read_model function) tran = glp_mpl_alloc_wksp(); status = glp_mpl_read_model(tran, *file, 0); if (!status) { status = glp_mpl_generate(tran, NULL); if (!status) { glp_mpl_build_prob(tran, lp); } } glp_mpl_free_wksp(tran); break; } // if file read successfully glp_read_* returns zero if ( status != 0 ) { glp_delete_prob(lp); lp = NULL; error("Reading file %c failed.", *file); } if(*lp_verbosity==1) Rprintf("Retrieve column specific data ...\n"); if(glp_get_num_cols(lp) != *lp_n_objective_vars) { glp_delete_prob(lp); lp = NULL; error("The number of columns is not as specified"); } // retrieve column specific data (values, bounds and type) for (i = 0; i < *lp_n_objective_vars; i++) { lp_objective_coefficients[i] = glp_get_obj_coef(lp, i+1); // Note that str must not be freed befor we have returned // from the .C call in R! str = glp_get_col_name(lp, i+1); if (str){ lp_objective_vars_names[i] = (char *) str; } lp_bounds_type[i] = glp_get_col_type(lp, i+1); lp_bounds_lower[i] = glp_get_col_lb (lp, i+1); lp_bounds_upper[i] = glp_get_col_ub (lp, i+1); lp_column_kind = glp_get_col_kind(lp, i+1); // set to TRUE if objective variable is integer or binary switch (lp_column_kind){ case GLP_IV: lp_objective_var_is_integer[i] = 1; break; case GLP_BV: lp_objective_var_is_binary[i] = 1; break; } } ind_offset = 0; if(*lp_verbosity==1) Rprintf("Retrieve row specific data ...\n"); if(glp_get_num_rows(lp) != *lp_n_constraints) { glp_delete_prob(lp); lp = NULL; error("The number of rows is not as specified"); } // retrieve row specific data (right hand side, direction of constraints) for (i = *lp_ignore_first_row; i < *lp_n_constraints; i++) { lp_direction_of_constraints[i] = glp_get_row_type(lp, i+1); str = glp_get_row_name(lp, i + 1); if (str) { lp_constraint_names[i] = (char *) str; } // the right hand side. Note we don't allow for double bounded or // free auxiliary variables if( lp_direction_of_constraints[i] == GLP_LO ) lp_right_hand_side[i] = glp_get_row_lb(lp, i+1); if( lp_direction_of_constraints[i] == GLP_UP ) lp_right_hand_side[i] = glp_get_row_ub(lp, i+1); if( lp_direction_of_constraints[i] == GLP_FX ) lp_right_hand_side[i] = glp_get_row_lb(lp, i+1); if( lp_direction_of_constraints[i] == GLP_DB ){ lp_right_hand_side[i] = glp_get_row_ub(lp, i+1); lp_left_hand_side[i] = glp_get_row_lb(lp, i+1); } tmp = glp_get_mat_row(lp, i+1, &lp_constraint_matrix_j[ind_offset-1], &lp_constraint_matrix_values[ind_offset-1]); if (tmp > 0) for (j = 0; j < tmp; j++) lp_constraint_matrix_i[ind_offset+j] = i+1; ind_offset += tmp; } if(*lp_verbosity==1) Rprintf("Done.\n"); } Rglpk/src/Makevars.in0000644000176000001440000000025712245336313014257 0ustar ripleyusersPKG_CPPFLAGS = @GLPK_INCLUDE_PATH@ PKG_LIBS = @GLPK_LIB_PATH@ @GLPK_LIBS@ .PHONY: all @GLPK_TS@ all: $(SHLIB) $(OBJECTS): @GLPK_TS@ GLPK.ts: @(cd GLPK && make) touch $@ Rglpk/src/Rglpk_solve.c0000644000176000001440000000712112245352174014611 0ustar ripleyusers/* This is the GLPK C Interface */ #include "Rglpk.h" #include // this is the solve function called from R void R_glp_solve (int *lp_direction, int *lp_number_of_constraints, int *lp_direction_of_constraints, double *lp_right_hand_side, int *lp_number_of_objective_vars, double *lp_objective_coefficients, int *lp_objective_var_is_integer, int *lp_objective_var_is_binary, int *lp_is_integer, //should be boolean int *lp_number_of_values_in_constraint_matrix, int *lp_constraint_matrix_i, int *lp_constraint_matrix_j, double *lp_constraint_matrix_values, int *lp_bounds_type, double *lp_bounds_lower, double *lp_bounds_upper, double *lp_optimum, double *lp_objective_vars_values, int *lp_verbosity, int *lp_status) { glp_prob *lp; int i, kl, ku; // create problem object lp = glp_create_prob(); // Turn on/off Terminal Output if(*lp_verbosity==1) glp_term_out(GLP_ON); else glp_term_out(GLP_OFF); // direction of optimization if(*lp_direction==1) glp_set_obj_dir(lp, GLP_MAX); else glp_set_obj_dir(lp, GLP_MIN); // is it a mixed integer problem? -- seems to be an R glpk function //if(lp_integer) //lpx_set_class(lp, LPX_MIP); // add rows to the problem object glp_add_rows(lp, *lp_number_of_constraints); for(i = 0; i < *lp_number_of_constraints; i++) switch(lp_direction_of_constraints[i]){ case 1: glp_set_row_bnds(lp, i+1, GLP_UP, 0.0, lp_right_hand_side[i]); break; case 2: glp_set_row_bnds(lp, i+1, GLP_UP, 0.0, lp_right_hand_side[i]); break; case 3: glp_set_row_bnds(lp, i+1, GLP_LO, lp_right_hand_side[i], 0.0); break; case 4: glp_set_row_bnds(lp, i+1, GLP_LO, lp_right_hand_side[i], 0.0); break; case 5: glp_set_row_bnds(lp, i+1, GLP_FX, lp_right_hand_side[i], lp_right_hand_side[i]); break; } // add columns to the problem object glp_add_cols(lp, *lp_number_of_objective_vars); kl = ku = 0; for(i = 0; i < *lp_number_of_objective_vars; i++) { glp_set_col_bnds(lp, i+1, lp_bounds_type[i], lp_bounds_lower[i], lp_bounds_upper[i]); // set objective coefficients and integer if necessary glp_set_obj_coef(lp, i+1, lp_objective_coefficients[i]); if (lp_objective_var_is_integer[i]) glp_set_col_kind(lp, i+1, GLP_IV); if (lp_objective_var_is_binary[i]) glp_set_col_kind(lp, i+1, GLP_BV); } // load the matrix // IMPORTANT: as glp_load_matrix requires triplets as vectors of the // form: ia[1] ... ia[n], we have to pass the pointer to the adress // [-1] of the corresponding vector glp_load_matrix(lp, *lp_number_of_values_in_constraint_matrix, &lp_constraint_matrix_i[-1], &lp_constraint_matrix_j[-1], &lp_constraint_matrix_values[-1]); // run simplex method to solve linear problem glp_simplex(lp, NULL); // retrieve status of optimization *lp_status = glp_get_status(lp); // retrieve optimum *lp_optimum = glp_get_obj_val(lp); // retrieve values of objective vars for(i = 0; i < *lp_number_of_objective_vars; i++) { lp_objective_vars_values[i] = glp_get_col_prim(lp, i+1); } if(*lp_is_integer) { glp_intopt(lp, NULL); // retrieve status of optimization *lp_status = glp_mip_status(lp); // retrieve MIP optimum *lp_optimum = glp_mip_obj_val(lp); // retrieve MIP values of objective vars for(i = 0; i < *lp_number_of_objective_vars; i++){ lp_objective_vars_values[i] = glp_mip_col_val(lp, i+1); } } // delete problem object glp_delete_prob(lp); } Rglpk/src/Rglpk.h0000644000176000001440000000007112245352174013403 0ustar ripleyusers#include "glpk.h" #include #include Rglpk/src/GLPK/0000755000176000001440000000000012245337107012711 5ustar ripleyusersRglpk/src/GLPK/amd/0000755000176000001440000000000012175147600013451 5ustar ripleyusersRglpk/src/GLPK/amd/COPYING0000644000176000001440000006362512175147600014520 0ustar ripleyusers GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! Rglpk/src/GLPK/amd/amd_aat.c0000644000176000001440000001340112245352174015204 0ustar ripleyusers/* ========================================================================= */ /* === AMD_aat ============================================================= */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* AMD_aat: compute the symmetry of the pattern of A, and count the number of * nonzeros each column of A+A' (excluding the diagonal). Assumes the input * matrix has no errors, with sorted columns and no duplicates * (AMD_valid (n, n, Ap, Ai) must be AMD_OK, but this condition is not * checked). */ #include "amd_internal.h" GLOBAL size_t AMD_aat /* returns nz in A+A' */ ( Int n, const Int Ap [ ], const Int Ai [ ], Int Len [ ], /* Len [j]: length of column j of A+A', excl diagonal*/ Int Tp [ ], /* workspace of size n */ double Info [ ] ) { Int p1, p2, p, i, j, pj, pj2, k, nzdiag, nzboth, nz ; double sym ; size_t nzaat ; #ifndef NDEBUG AMD_debug_init ("AMD AAT") ; for (k = 0 ; k < n ; k++) Tp [k] = EMPTY ; ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ; #endif if (Info != (double *) NULL) { /* clear the Info array, if it exists */ for (i = 0 ; i < AMD_INFO ; i++) { Info [i] = EMPTY ; } Info [AMD_STATUS] = AMD_OK ; } for (k = 0 ; k < n ; k++) { Len [k] = 0 ; } nzdiag = 0 ; nzboth = 0 ; nz = Ap [n] ; for (k = 0 ; k < n ; k++) { p1 = Ap [k] ; p2 = Ap [k+1] ; AMD_DEBUG2 (("\nAAT Column: "ID" p1: "ID" p2: "ID"\n", k, p1, p2)) ; /* construct A+A' */ for (p = p1 ; p < p2 ; ) { /* scan the upper triangular part of A */ j = Ai [p] ; if (j < k) { /* entry A (j,k) is in the strictly upper triangular part, * add both A (j,k) and A (k,j) to the matrix A+A' */ Len [j]++ ; Len [k]++ ; AMD_DEBUG3 ((" upper ("ID","ID") ("ID","ID")\n", j,k, k,j)); p++ ; } else if (j == k) { /* skip the diagonal */ p++ ; nzdiag++ ; break ; } else /* j > k */ { /* first entry below the diagonal */ break ; } /* scan lower triangular part of A, in column j until reaching * row k. Start where last scan left off. */ ASSERT (Tp [j] != EMPTY) ; ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ; pj2 = Ap [j+1] ; for (pj = Tp [j] ; pj < pj2 ; ) { i = Ai [pj] ; if (i < k) { /* A (i,j) is only in the lower part, not in upper. * add both A (i,j) and A (j,i) to the matrix A+A' */ Len [i]++ ; Len [j]++ ; AMD_DEBUG3 ((" lower ("ID","ID") ("ID","ID")\n", i,j, j,i)) ; pj++ ; } else if (i == k) { /* entry A (k,j) in lower part and A (j,k) in upper */ pj++ ; nzboth++ ; break ; } else /* i > k */ { /* consider this entry later, when k advances to i */ break ; } } Tp [j] = pj ; } /* Tp [k] points to the entry just below the diagonal in column k */ Tp [k] = p ; } /* clean up, for remaining mismatched entries */ for (j = 0 ; j < n ; j++) { for (pj = Tp [j] ; pj < Ap [j+1] ; pj++) { i = Ai [pj] ; /* A (i,j) is only in the lower part, not in upper. * add both A (i,j) and A (j,i) to the matrix A+A' */ Len [i]++ ; Len [j]++ ; AMD_DEBUG3 ((" lower cleanup ("ID","ID") ("ID","ID")\n", i,j, j,i)) ; } } /* --------------------------------------------------------------------- */ /* compute the symmetry of the nonzero pattern of A */ /* --------------------------------------------------------------------- */ /* Given a matrix A, the symmetry of A is: * B = tril (spones (A), -1) + triu (spones (A), 1) ; * sym = nnz (B & B') / nnz (B) ; * or 1 if nnz (B) is zero. */ if (nz == nzdiag) { sym = 1 ; } else { sym = (2 * (double) nzboth) / ((double) (nz - nzdiag)) ; } nzaat = 0 ; for (k = 0 ; k < n ; k++) { nzaat += Len [k] ; } AMD_DEBUG1 (("AMD nz in A+A', excluding diagonal (nzaat) = %g\n", (double) nzaat)) ; AMD_DEBUG1 ((" nzboth: "ID" nz: "ID" nzdiag: "ID" symmetry: %g\n", nzboth, nz, nzdiag, sym)) ; if (Info != (double *) NULL) { Info [AMD_STATUS] = AMD_OK ; Info [AMD_N] = n ; Info [AMD_NZ] = nz ; Info [AMD_SYMMETRY] = sym ; /* symmetry of pattern of A */ Info [AMD_NZDIAG] = nzdiag ; /* nonzeros on diagonal of A */ Info [AMD_NZ_A_PLUS_AT] = nzaat ; /* nonzeros in A+A' */ } return (nzaat) ; } Rglpk/src/GLPK/amd/amd.h0000644000176000001440000000327612245352174014375 0ustar ripleyusers/* amd.h */ /* Written by Andrew Makhorin . */ #ifndef GLPAMD_H #define GLPAMD_H #define AMD_DATE "May 31, 2007" #define AMD_VERSION_CODE(main, sub) ((main) * 1000 + (sub)) #define AMD_MAIN_VERSION 2 #define AMD_SUB_VERSION 2 #define AMD_SUBSUB_VERSION 0 #define AMD_VERSION AMD_VERSION_CODE(AMD_MAIN_VERSION, AMD_SUB_VERSION) #define AMD_CONTROL 5 #define AMD_INFO 20 #define AMD_DENSE 0 #define AMD_AGGRESSIVE 1 #define AMD_DEFAULT_DENSE 10.0 #define AMD_DEFAULT_AGGRESSIVE 1 #define AMD_STATUS 0 #define AMD_N 1 #define AMD_NZ 2 #define AMD_SYMMETRY 3 #define AMD_NZDIAG 4 #define AMD_NZ_A_PLUS_AT 5 #define AMD_NDENSE 6 #define AMD_MEMORY 7 #define AMD_NCMPA 8 #define AMD_LNZ 9 #define AMD_NDIV 10 #define AMD_NMULTSUBS_LDL 11 #define AMD_NMULTSUBS_LU 12 #define AMD_DMAX 13 #define AMD_OK 0 #define AMD_OUT_OF_MEMORY (-1) #define AMD_INVALID (-2) #define AMD_OK_BUT_JUMBLED 1 #define amd_order _glp_amd_order int amd_order(int n, const int Ap[], const int Ai[], int P[], double Control[], double Info[]); #define amd_2 _glp_amd_2 void amd_2(int n, int Pe[], int Iw[], int Len[], int iwlen, int pfree, int Nv[], int Next[], int Last[], int Head[], int Elen[], int Degree[], int W[], double Control[], double Info[]); #define amd_valid _glp_amd_valid int amd_valid(int n_row, int n_col, const int Ap[], const int Ai[]); #define amd_defaults _glp_amd_defaults void amd_defaults(double Control[]); #define amd_control _glp_amd_control void amd_control(double Control[]); #define amd_info _glp_amd_info void amd_info(double Info[]); #endif /* eof */ Rglpk/src/GLPK/amd/amd_info.c0000644000176000001440000001065612245352174015403 0ustar ripleyusers/* ========================================================================= */ /* === AMD_info ============================================================ */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* User-callable. Prints the output statistics for AMD. See amd.h * for details. If the Info array is not present, nothing is printed. */ #include "amd_internal.h" #define PRI(format,x) { if (x >= 0) { PRINTF ((format, x)) ; }} GLOBAL void AMD_info ( double Info [ ] ) { double n, ndiv, nmultsubs_ldl, nmultsubs_lu, lnz, lnzd ; PRINTF (("\nAMD version %d.%d.%d, %s, results:\n", AMD_MAIN_VERSION, AMD_SUB_VERSION, AMD_SUBSUB_VERSION, AMD_DATE)) ; if (!Info) { return ; } n = Info [AMD_N] ; ndiv = Info [AMD_NDIV] ; nmultsubs_ldl = Info [AMD_NMULTSUBS_LDL] ; nmultsubs_lu = Info [AMD_NMULTSUBS_LU] ; lnz = Info [AMD_LNZ] ; lnzd = (n >= 0 && lnz >= 0) ? (n + lnz) : (-1) ; /* AMD return status */ PRINTF ((" status: ")) ; if (Info [AMD_STATUS] == AMD_OK) { PRINTF (("OK\n")) ; } else if (Info [AMD_STATUS] == AMD_OUT_OF_MEMORY) { PRINTF (("out of memory\n")) ; } else if (Info [AMD_STATUS] == AMD_INVALID) { PRINTF (("invalid matrix\n")) ; } else if (Info [AMD_STATUS] == AMD_OK_BUT_JUMBLED) { PRINTF (("OK, but jumbled\n")) ; } else { PRINTF (("unknown\n")) ; } /* statistics about the input matrix */ PRI (" n, dimension of A: %.20g\n", n); PRI (" nz, number of nonzeros in A: %.20g\n", Info [AMD_NZ]) ; PRI (" symmetry of A: %.4f\n", Info [AMD_SYMMETRY]) ; PRI (" number of nonzeros on diagonal: %.20g\n", Info [AMD_NZDIAG]) ; PRI (" nonzeros in pattern of A+A' (excl. diagonal): %.20g\n", Info [AMD_NZ_A_PLUS_AT]) ; PRI (" # dense rows/columns of A+A': %.20g\n", Info [AMD_NDENSE]) ; /* statistics about AMD's behavior */ PRI (" memory used, in bytes: %.20g\n", Info [AMD_MEMORY]) ; PRI (" # of memory compactions: %.20g\n", Info [AMD_NCMPA]) ; /* statistics about the ordering quality */ PRINTF (("\n" " The following approximate statistics are for a subsequent\n" " factorization of A(P,P) + A(P,P)'. They are slight upper\n" " bounds if there are no dense rows/columns in A+A', and become\n" " looser if dense rows/columns exist.\n\n")) ; PRI (" nonzeros in L (excluding diagonal): %.20g\n", lnz) ; PRI (" nonzeros in L (including diagonal): %.20g\n", lnzd) ; PRI (" # divide operations for LDL' or LU: %.20g\n", ndiv) ; PRI (" # multiply-subtract operations for LDL': %.20g\n", nmultsubs_ldl) ; PRI (" # multiply-subtract operations for LU: %.20g\n", nmultsubs_lu) ; PRI (" max nz. in any column of L (incl. diagonal): %.20g\n", Info [AMD_DMAX]) ; /* total flop counts for various factorizations */ if (n >= 0 && ndiv >= 0 && nmultsubs_ldl >= 0 && nmultsubs_lu >= 0) { PRINTF (("\n" " chol flop count for real A, sqrt counted as 1 flop: %.20g\n" " LDL' flop count for real A: %.20g\n" " LDL' flop count for complex A: %.20g\n" " LU flop count for real A (with no pivoting): %.20g\n" " LU flop count for complex A (with no pivoting): %.20g\n\n", n + ndiv + 2*nmultsubs_ldl, ndiv + 2*nmultsubs_ldl, 9*ndiv + 8*nmultsubs_ldl, ndiv + 2*nmultsubs_lu, 9*ndiv + 8*nmultsubs_lu)) ; } } Rglpk/src/GLPK/amd/amd_internal.h0000644000176000001440000000616412245352174016270 0ustar ripleyusers/* amd_internal.h */ /* Written by Andrew Makhorin . */ #ifndef AMD_INTERNAL_H #define AMD_INTERNAL_H /* AMD will be exceedingly slow when running in debug mode. */ #if 1 #define NDEBUG #endif #include "amd.h" #define _GLPSTD_STDIO #include "env.h" #define Int int #define ID "%d" #define Int_MAX INT_MAX #if 0 /* 15/II-2012 */ /* now this macro is defined in glpenv.h; besides, the definiton below depends on implementation, because size_t is an unsigned type */ #define SIZE_T_MAX ((size_t)(-1)) #endif #define EMPTY (-1) #define FLIP(i) (-(i)-2) #define UNFLIP(i) ((i < EMPTY) ? FLIP (i) : (i)) #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define IMPLIES(p, q) (!(p) || (q)) #define GLOBAL #define AMD_order amd_order #define AMD_defaults amd_defaults #define AMD_control amd_control #define AMD_info amd_info #define AMD_1 amd_1 #define AMD_2 amd_2 #define AMD_valid amd_valid #define AMD_aat amd_aat #define AMD_postorder amd_postorder #define AMD_post_tree amd_post_tree #define AMD_dump amd_dump #define AMD_debug amd_debug #define AMD_debug_init amd_debug_init #define AMD_preprocess amd_preprocess #define amd_malloc xmalloc #if 0 /* 24/V-2009 */ #define amd_free xfree #else #define amd_free(ptr) { if ((ptr) != NULL) xfree(ptr); } #endif #define amd_printf xprintf #define PRINTF(params) { amd_printf params; } #ifndef NDEBUG #define ASSERT(expr) xassert(expr) #define AMD_DEBUG0(params) { PRINTF(params); } #define AMD_DEBUG1(params) { if (AMD_debug >= 1) PRINTF(params); } #define AMD_DEBUG2(params) { if (AMD_debug >= 2) PRINTF(params); } #define AMD_DEBUG3(params) { if (AMD_debug >= 3) PRINTF(params); } #define AMD_DEBUG4(params) { if (AMD_debug >= 4) PRINTF(params); } #else #define ASSERT(expression) #define AMD_DEBUG0(params) #define AMD_DEBUG1(params) #define AMD_DEBUG2(params) #define AMD_DEBUG3(params) #define AMD_DEBUG4(params) #endif #define amd_aat _glp_amd_aat size_t AMD_aat(Int n, const Int Ap[], const Int Ai[], Int Len[], Int Tp[], double Info[]); #define amd_1 _glp_amd_1 void AMD_1(Int n, const Int Ap[], const Int Ai[], Int P[], Int Pinv[], Int Len[], Int slen, Int S[], double Control[], double Info[]); #define amd_postorder _glp_amd_postorder void AMD_postorder(Int nn, Int Parent[], Int Npiv[], Int Fsize[], Int Order[], Int Child[], Int Sibling[], Int Stack[]); #define amd_post_tree _glp_amd_post_tree #ifndef NDEBUG Int AMD_post_tree(Int root, Int k, Int Child[], const Int Sibling[], Int Order[], Int Stack[], Int nn); #else Int AMD_post_tree(Int root, Int k, Int Child[], const Int Sibling[], Int Order[], Int Stack[]); #endif #define amd_preprocess _glp_amd_preprocess void AMD_preprocess(Int n, const Int Ap[], const Int Ai[], Int Rp[], Int Ri[], Int W[], Int Flag[]); #define amd_debug _glp_amd_debug extern Int AMD_debug; #define amd_debug_init _glp_amd_debug_init void AMD_debug_init(char *s); #define amd_dump _glp_amd_dump void AMD_dump(Int n, Int Pe[], Int Iw[], Int Len[], Int iwlen, Int pfree, Int Nv[], Int Next[], Int Last[], Int Head[], Int Elen[], Int Degree[], Int W[], Int nel); #endif /* eof */ Rglpk/src/GLPK/amd/amd_preprocess.c0000644000176000001440000001017712245352174016633 0ustar ripleyusers/* ========================================================================= */ /* === AMD_preprocess ====================================================== */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* Sorts, removes duplicate entries, and transposes from the nonzero pattern of * a column-form matrix A, to obtain the matrix R. The input matrix can have * duplicate entries and/or unsorted columns (AMD_valid (n,Ap,Ai) must not be * AMD_INVALID). * * This input condition is NOT checked. This routine is not user-callable. */ #include "amd_internal.h" /* ========================================================================= */ /* === AMD_preprocess ====================================================== */ /* ========================================================================= */ /* AMD_preprocess does not check its input for errors or allocate workspace. * On input, the condition (AMD_valid (n,n,Ap,Ai) != AMD_INVALID) must hold. */ GLOBAL void AMD_preprocess ( Int n, /* input matrix: A is n-by-n */ const Int Ap [ ], /* size n+1 */ const Int Ai [ ], /* size nz = Ap [n] */ /* output matrix R: */ Int Rp [ ], /* size n+1 */ Int Ri [ ], /* size nz (or less, if duplicates present) */ Int W [ ], /* workspace of size n */ Int Flag [ ] /* workspace of size n */ ) { /* --------------------------------------------------------------------- */ /* local variables */ /* --------------------------------------------------------------------- */ Int i, j, p, p2 ; ASSERT (AMD_valid (n, n, Ap, Ai) != AMD_INVALID) ; /* --------------------------------------------------------------------- */ /* count the entries in each row of A (excluding duplicates) */ /* --------------------------------------------------------------------- */ for (i = 0 ; i < n ; i++) { W [i] = 0 ; /* # of nonzeros in row i (excl duplicates) */ Flag [i] = EMPTY ; /* Flag [i] = j if i appears in column j */ } for (j = 0 ; j < n ; j++) { p2 = Ap [j+1] ; for (p = Ap [j] ; p < p2 ; p++) { i = Ai [p] ; if (Flag [i] != j) { /* row index i has not yet appeared in column j */ W [i]++ ; /* one more entry in row i */ Flag [i] = j ; /* flag row index i as appearing in col j*/ } } } /* --------------------------------------------------------------------- */ /* compute the row pointers for R */ /* --------------------------------------------------------------------- */ Rp [0] = 0 ; for (i = 0 ; i < n ; i++) { Rp [i+1] = Rp [i] + W [i] ; } for (i = 0 ; i < n ; i++) { W [i] = Rp [i] ; Flag [i] = EMPTY ; } /* --------------------------------------------------------------------- */ /* construct the row form matrix R */ /* --------------------------------------------------------------------- */ /* R = row form of pattern of A */ for (j = 0 ; j < n ; j++) { p2 = Ap [j+1] ; for (p = Ap [j] ; p < p2 ; p++) { i = Ai [p] ; if (Flag [i] != j) { /* row index i has not yet appeared in column j */ Ri [W [i]++] = j ; /* put col j in row i */ Flag [i] = j ; /* flag row index i as appearing in col j*/ } } } #ifndef NDEBUG ASSERT (AMD_valid (n, n, Rp, Ri) == AMD_OK) ; for (j = 0 ; j < n ; j++) { ASSERT (W [j] == Rp [j+1]) ; } #endif } Rglpk/src/GLPK/amd/amd_postorder.c0000644000176000001440000001543112245352174016465 0ustar ripleyusers/* ========================================================================= */ /* === AMD_postorder ======================================================= */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* Perform a postordering (via depth-first search) of an assembly tree. */ #include "amd_internal.h" GLOBAL void AMD_postorder ( /* inputs, not modified on output: */ Int nn, /* nodes are in the range 0..nn-1 */ Int Parent [ ], /* Parent [j] is the parent of j, or EMPTY if root */ Int Nv [ ], /* Nv [j] > 0 number of pivots represented by node j, * or zero if j is not a node. */ Int Fsize [ ], /* Fsize [j]: size of node j */ /* output, not defined on input: */ Int Order [ ], /* output post-order */ /* workspaces of size nn: */ Int Child [ ], Int Sibling [ ], Int Stack [ ] ) { Int i, j, k, parent, frsize, f, fprev, maxfrsize, bigfprev, bigf, fnext ; for (j = 0 ; j < nn ; j++) { Child [j] = EMPTY ; Sibling [j] = EMPTY ; } /* --------------------------------------------------------------------- */ /* place the children in link lists - bigger elements tend to be last */ /* --------------------------------------------------------------------- */ for (j = nn-1 ; j >= 0 ; j--) { if (Nv [j] > 0) { /* this is an element */ parent = Parent [j] ; if (parent != EMPTY) { /* place the element in link list of the children its parent */ /* bigger elements will tend to be at the end of the list */ Sibling [j] = Child [parent] ; Child [parent] = j ; } } } #ifndef NDEBUG { Int nels, ff, nchild ; AMD_DEBUG1 (("\n\n================================ AMD_postorder:\n")); nels = 0 ; for (j = 0 ; j < nn ; j++) { if (Nv [j] > 0) { AMD_DEBUG1 (( ""ID" : nels "ID" npiv "ID" size "ID " parent "ID" maxfr "ID"\n", j, nels, Nv [j], Fsize [j], Parent [j], Fsize [j])) ; /* this is an element */ /* dump the link list of children */ nchild = 0 ; AMD_DEBUG1 ((" Children: ")) ; for (ff = Child [j] ; ff != EMPTY ; ff = Sibling [ff]) { AMD_DEBUG1 ((ID" ", ff)) ; ASSERT (Parent [ff] == j) ; nchild++ ; ASSERT (nchild < nn) ; } AMD_DEBUG1 (("\n")) ; parent = Parent [j] ; if (parent != EMPTY) { ASSERT (Nv [parent] > 0) ; } nels++ ; } } } AMD_DEBUG1 (("\n\nGo through the children of each node, and put\n" "the biggest child last in each list:\n")) ; #endif /* --------------------------------------------------------------------- */ /* place the largest child last in the list of children for each node */ /* --------------------------------------------------------------------- */ for (i = 0 ; i < nn ; i++) { if (Nv [i] > 0 && Child [i] != EMPTY) { #ifndef NDEBUG Int nchild ; AMD_DEBUG1 (("Before partial sort, element "ID"\n", i)) ; nchild = 0 ; for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) { ASSERT (f >= 0 && f < nn) ; AMD_DEBUG1 ((" f: "ID" size: "ID"\n", f, Fsize [f])) ; nchild++ ; ASSERT (nchild <= nn) ; } #endif /* find the biggest element in the child list */ fprev = EMPTY ; maxfrsize = EMPTY ; bigfprev = EMPTY ; bigf = EMPTY ; for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) { ASSERT (f >= 0 && f < nn) ; frsize = Fsize [f] ; if (frsize >= maxfrsize) { /* this is the biggest seen so far */ maxfrsize = frsize ; bigfprev = fprev ; bigf = f ; } fprev = f ; } ASSERT (bigf != EMPTY) ; fnext = Sibling [bigf] ; AMD_DEBUG1 (("bigf "ID" maxfrsize "ID" bigfprev "ID" fnext "ID " fprev " ID"\n", bigf, maxfrsize, bigfprev, fnext, fprev)) ; if (fnext != EMPTY) { /* if fnext is EMPTY then bigf is already at the end of list */ if (bigfprev == EMPTY) { /* delete bigf from the element of the list */ Child [i] = fnext ; } else { /* delete bigf from the middle of the list */ Sibling [bigfprev] = fnext ; } /* put bigf at the end of the list */ Sibling [bigf] = EMPTY ; ASSERT (Child [i] != EMPTY) ; ASSERT (fprev != bigf) ; ASSERT (fprev != EMPTY) ; Sibling [fprev] = bigf ; } #ifndef NDEBUG AMD_DEBUG1 (("After partial sort, element "ID"\n", i)) ; for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) { ASSERT (f >= 0 && f < nn) ; AMD_DEBUG1 ((" "ID" "ID"\n", f, Fsize [f])) ; ASSERT (Nv [f] > 0) ; nchild-- ; } ASSERT (nchild == 0) ; #endif } } /* --------------------------------------------------------------------- */ /* postorder the assembly tree */ /* --------------------------------------------------------------------- */ for (i = 0 ; i < nn ; i++) { Order [i] = EMPTY ; } k = 0 ; for (i = 0 ; i < nn ; i++) { if (Parent [i] == EMPTY && Nv [i] > 0) { AMD_DEBUG1 (("Root of assembly tree "ID"\n", i)) ; k = AMD_post_tree (i, k, Child, Sibling, Order, Stack #ifndef NDEBUG , nn #endif ) ; } } } Rglpk/src/GLPK/amd/amd_control.c0000644000176000001440000000370112245352174016121 0ustar ripleyusers/* ========================================================================= */ /* === AMD_control ========================================================= */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* User-callable. Prints the control parameters for AMD. See amd.h * for details. If the Control array is not present, the defaults are * printed instead. */ #include "amd_internal.h" GLOBAL void AMD_control ( double Control [ ] ) { double alpha ; Int aggressive ; if (Control != (double *) NULL) { alpha = Control [AMD_DENSE] ; aggressive = Control [AMD_AGGRESSIVE] != 0 ; } else { alpha = AMD_DEFAULT_DENSE ; aggressive = AMD_DEFAULT_AGGRESSIVE ; } PRINTF (("\nAMD version %d.%d.%d, %s: approximate minimum degree ordering\n" " dense row parameter: %g\n", AMD_MAIN_VERSION, AMD_SUB_VERSION, AMD_SUBSUB_VERSION, AMD_DATE, alpha)) ; if (alpha < 0) { PRINTF ((" no rows treated as dense\n")) ; } else { PRINTF (( " (rows with more than max (%g * sqrt (n), 16) entries are\n" " considered \"dense\", and placed last in output permutation)\n", alpha)) ; } if (aggressive) { PRINTF ((" aggressive absorption: yes\n")) ; } else { PRINTF ((" aggressive absorption: no\n")) ; } PRINTF ((" size of AMD integer: %d\n\n", sizeof (Int))) ; } Rglpk/src/GLPK/amd/README0000644000176000001440000000461712175147600014341 0ustar ripleyusersNOTE: Files in this subdirectory are NOT part of the GLPK package, but are used with GLPK. The original code was modified according to GLPK requirements by Andrew Makhorin . ************************************************************************ AMD Version 2.2, Copyright (C) 2007 by Timothy A. Davis, Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved. Description: AMD is a set of routines for pre-ordering sparse matrices prior to Cholesky or LU factorization, using the approximate minimum degree ordering algorithm. Written in ANSI/ISO C with a MATLAB interface, and in Fortran 77. Authors: Timothy A. Davis (davis at cise.ufl.edu), University of Florida. Patrick R. Amestoy, ENSEEIHT, Toulouse, France. Iain S. Duff, Rutherford Appleton Laboratory, UK. AMD License: Your use or distribution of AMD or any modified version of AMD implies that you agree to this License. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. Permission is hereby granted to use or copy this program under the terms of the GNU LGPL, provided that the Copyright, this License, and the Availability of the original version is retained on all copies. User documentation of any code that uses this code or any modified version of this code must cite the Copyright, this License, the Availability note, and "Used by permission." Permission to modify the code and to distribute modified code is granted, provided the Copyright, this License, and the Availability note are retained, and a notice that the code was modified is included. AMD is available under alternate licences; contact T. Davis for details. Availability: http://www.cise.ufl.edu/research/sparse/amd Rglpk/src/GLPK/amd/amd_order.c0000644000176000001440000001451612245352174015562 0ustar ripleyusers/* ========================================================================= */ /* === AMD_order =========================================================== */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* User-callable AMD minimum degree ordering routine. See amd.h for * documentation. */ #include "amd_internal.h" /* ========================================================================= */ /* === AMD_order =========================================================== */ /* ========================================================================= */ GLOBAL Int AMD_order ( Int n, const Int Ap [ ], const Int Ai [ ], Int P [ ], double Control [ ], double Info [ ] ) { Int *Len, *S, nz, i, *Pinv, info, status, *Rp, *Ri, *Cp, *Ci, ok ; size_t nzaat, slen ; double mem = 0 ; #ifndef NDEBUG AMD_debug_init ("amd") ; #endif /* clear the Info array, if it exists */ info = Info != (double *) NULL ; if (info) { for (i = 0 ; i < AMD_INFO ; i++) { Info [i] = EMPTY ; } Info [AMD_N] = n ; Info [AMD_STATUS] = AMD_OK ; } /* make sure inputs exist and n is >= 0 */ if (Ai == (Int *) NULL || Ap == (Int *) NULL || P == (Int *) NULL || n < 0) { if (info) Info [AMD_STATUS] = AMD_INVALID ; return (AMD_INVALID) ; /* arguments are invalid */ } if (n == 0) { return (AMD_OK) ; /* n is 0 so there's nothing to do */ } nz = Ap [n] ; if (info) { Info [AMD_NZ] = nz ; } if (nz < 0) { if (info) Info [AMD_STATUS] = AMD_INVALID ; return (AMD_INVALID) ; } /* check if n or nz will cause size_t overflow */ if (((size_t) n) >= SIZE_T_MAX / sizeof (Int) || ((size_t) nz) >= SIZE_T_MAX / sizeof (Int)) { if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ; return (AMD_OUT_OF_MEMORY) ; /* problem too large */ } /* check the input matrix: AMD_OK, AMD_INVALID, or AMD_OK_BUT_JUMBLED */ status = AMD_valid (n, n, Ap, Ai) ; if (status == AMD_INVALID) { if (info) Info [AMD_STATUS] = AMD_INVALID ; return (AMD_INVALID) ; /* matrix is invalid */ } /* allocate two size-n integer workspaces */ Len = amd_malloc (n * sizeof (Int)) ; Pinv = amd_malloc (n * sizeof (Int)) ; mem += n ; mem += n ; if (!Len || !Pinv) { /* :: out of memory :: */ amd_free (Len) ; amd_free (Pinv) ; if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ; return (AMD_OUT_OF_MEMORY) ; } if (status == AMD_OK_BUT_JUMBLED) { /* sort the input matrix and remove duplicate entries */ AMD_DEBUG1 (("Matrix is jumbled\n")) ; Rp = amd_malloc ((n+1) * sizeof (Int)) ; Ri = amd_malloc (MAX (nz,1) * sizeof (Int)) ; mem += (n+1) ; mem += MAX (nz,1) ; if (!Rp || !Ri) { /* :: out of memory :: */ amd_free (Rp) ; amd_free (Ri) ; amd_free (Len) ; amd_free (Pinv) ; if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ; return (AMD_OUT_OF_MEMORY) ; } /* use Len and Pinv as workspace to create R = A' */ AMD_preprocess (n, Ap, Ai, Rp, Ri, Len, Pinv) ; Cp = Rp ; Ci = Ri ; } else { /* order the input matrix as-is. No need to compute R = A' first */ Rp = NULL ; Ri = NULL ; Cp = (Int *) Ap ; Ci = (Int *) Ai ; } /* --------------------------------------------------------------------- */ /* determine the symmetry and count off-diagonal nonzeros in A+A' */ /* --------------------------------------------------------------------- */ nzaat = AMD_aat (n, Cp, Ci, Len, P, Info) ; AMD_DEBUG1 (("nzaat: %g\n", (double) nzaat)) ; ASSERT ((MAX (nz-n, 0) <= nzaat) && (nzaat <= 2 * (size_t) nz)) ; /* --------------------------------------------------------------------- */ /* allocate workspace for matrix, elbow room, and 6 size-n vectors */ /* --------------------------------------------------------------------- */ S = NULL ; slen = nzaat ; /* space for matrix */ ok = ((slen + nzaat/5) >= slen) ; /* check for size_t overflow */ slen += nzaat/5 ; /* add elbow room */ for (i = 0 ; ok && i < 7 ; i++) { ok = ((slen + n) > slen) ; /* check for size_t overflow */ slen += n ; /* size-n elbow room, 6 size-n work */ } mem += slen ; ok = ok && (slen < SIZE_T_MAX / sizeof (Int)) ; /* check for overflow */ ok = ok && (slen < Int_MAX) ; /* S[i] for Int i must be OK */ if (ok) { S = amd_malloc (slen * sizeof (Int)) ; } AMD_DEBUG1 (("slen %g\n", (double) slen)) ; if (!S) { /* :: out of memory :: (or problem too large) */ amd_free (Rp) ; amd_free (Ri) ; amd_free (Len) ; amd_free (Pinv) ; if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ; return (AMD_OUT_OF_MEMORY) ; } if (info) { /* memory usage, in bytes. */ Info [AMD_MEMORY] = mem * sizeof (Int) ; } /* --------------------------------------------------------------------- */ /* order the matrix */ /* --------------------------------------------------------------------- */ AMD_1 (n, Cp, Ci, P, Pinv, Len, slen, S, Control, Info) ; /* --------------------------------------------------------------------- */ /* free the workspace */ /* --------------------------------------------------------------------- */ amd_free (Rp) ; amd_free (Ri) ; amd_free (Len) ; amd_free (Pinv) ; amd_free (S) ; if (info) Info [AMD_STATUS] = status ; return (status) ; /* successful ordering */ } Rglpk/src/GLPK/amd/amd_dump.c0000644000176000001440000001400112245352174015401 0ustar ripleyusers/* ========================================================================= */ /* === AMD_dump ============================================================ */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* Debugging routines for AMD. Not used if NDEBUG is not defined at compile- * time (the default). See comments in amd_internal.h on how to enable * debugging. Not user-callable. */ #include "amd_internal.h" #ifndef NDEBUG /* This global variable is present only when debugging */ GLOBAL Int AMD_debug = -999 ; /* default is no debug printing */ /* ========================================================================= */ /* === AMD_debug_init ====================================================== */ /* ========================================================================= */ /* Sets the debug print level, by reading the file debug.amd (if it exists) */ GLOBAL void AMD_debug_init ( char *s ) { FILE *f ; f = fopen ("debug.amd", "r") ; if (f == (FILE *) NULL) { AMD_debug = -999 ; } else { fscanf (f, ID, &AMD_debug) ; fclose (f) ; } if (AMD_debug >= 0) { printf ("%s: AMD_debug_init, D= "ID"\n", s, AMD_debug) ; } } /* ========================================================================= */ /* === AMD_dump ============================================================ */ /* ========================================================================= */ /* Dump AMD's data structure, except for the hash buckets. This routine * cannot be called when the hash buckets are non-empty. */ GLOBAL void AMD_dump ( Int n, /* A is n-by-n */ Int Pe [ ], /* pe [0..n-1]: index in iw of start of row i */ Int Iw [ ], /* workspace of size iwlen, iwlen [0..pfree-1] * holds the matrix on input */ Int Len [ ], /* len [0..n-1]: length for row i */ Int iwlen, /* length of iw */ Int pfree, /* iw [pfree ... iwlen-1] is empty on input */ Int Nv [ ], /* nv [0..n-1] */ Int Next [ ], /* next [0..n-1] */ Int Last [ ], /* last [0..n-1] */ Int Head [ ], /* head [0..n-1] */ Int Elen [ ], /* size n */ Int Degree [ ], /* size n */ Int W [ ], /* size n */ Int nel ) { Int i, pe, elen, nv, len, e, p, k, j, deg, w, cnt, ilast ; if (AMD_debug < 0) return ; ASSERT (pfree <= iwlen) ; AMD_DEBUG3 (("\nAMD dump, pfree: "ID"\n", pfree)) ; for (i = 0 ; i < n ; i++) { pe = Pe [i] ; elen = Elen [i] ; nv = Nv [i] ; len = Len [i] ; w = W [i] ; if (elen >= EMPTY) { if (nv == 0) { AMD_DEBUG3 (("\nI "ID": nonprincipal: ", i)) ; ASSERT (elen == EMPTY) ; if (pe == EMPTY) { AMD_DEBUG3 ((" dense node\n")) ; ASSERT (w == 1) ; } else { ASSERT (pe < EMPTY) ; AMD_DEBUG3 ((" i "ID" -> parent "ID"\n", i, FLIP (Pe[i]))); } } else { AMD_DEBUG3 (("\nI "ID": active principal supervariable:\n",i)); AMD_DEBUG3 ((" nv(i): "ID" Flag: %d\n", nv, (nv < 0))) ; ASSERT (elen >= 0) ; ASSERT (nv > 0 && pe >= 0) ; p = pe ; AMD_DEBUG3 ((" e/s: ")) ; if (elen == 0) AMD_DEBUG3 ((" : ")) ; ASSERT (pe + len <= pfree) ; for (k = 0 ; k < len ; k++) { j = Iw [p] ; AMD_DEBUG3 ((" "ID"", j)) ; ASSERT (j >= 0 && j < n) ; if (k == elen-1) AMD_DEBUG3 ((" : ")) ; p++ ; } AMD_DEBUG3 (("\n")) ; } } else { e = i ; if (w == 0) { AMD_DEBUG3 (("\nE "ID": absorbed element: w "ID"\n", e, w)) ; ASSERT (nv > 0 && pe < 0) ; AMD_DEBUG3 ((" e "ID" -> parent "ID"\n", e, FLIP (Pe [e]))) ; } else { AMD_DEBUG3 (("\nE "ID": unabsorbed element: w "ID"\n", e, w)) ; ASSERT (nv > 0 && pe >= 0) ; p = pe ; AMD_DEBUG3 ((" : ")) ; ASSERT (pe + len <= pfree) ; for (k = 0 ; k < len ; k++) { j = Iw [p] ; AMD_DEBUG3 ((" "ID"", j)) ; ASSERT (j >= 0 && j < n) ; p++ ; } AMD_DEBUG3 (("\n")) ; } } } /* this routine cannot be called when the hash buckets are non-empty */ AMD_DEBUG3 (("\nDegree lists:\n")) ; if (nel >= 0) { cnt = 0 ; for (deg = 0 ; deg < n ; deg++) { if (Head [deg] == EMPTY) continue ; ilast = EMPTY ; AMD_DEBUG3 ((ID": \n", deg)) ; for (i = Head [deg] ; i != EMPTY ; i = Next [i]) { AMD_DEBUG3 ((" "ID" : next "ID" last "ID" deg "ID"\n", i, Next [i], Last [i], Degree [i])) ; ASSERT (i >= 0 && i < n && ilast == Last [i] && deg == Degree [i]) ; cnt += Nv [i] ; ilast = i ; } AMD_DEBUG3 (("\n")) ; } ASSERT (cnt == n - nel) ; } } #endif Rglpk/src/GLPK/amd/amd_defaults.c0000644000176000001440000000257312245352174016256 0ustar ripleyusers/* ========================================================================= */ /* === AMD_defaults ======================================================== */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* User-callable. Sets default control parameters for AMD. See amd.h * for details. */ #include "amd_internal.h" /* ========================================================================= */ /* === AMD defaults ======================================================== */ /* ========================================================================= */ GLOBAL void AMD_defaults ( double Control [ ] ) { Int i ; if (Control != (double *) NULL) { for (i = 0 ; i < AMD_CONTROL ; i++) { Control [i] = 0 ; } Control [AMD_DENSE] = AMD_DEFAULT_DENSE ; Control [AMD_AGGRESSIVE] = AMD_DEFAULT_AGGRESSIVE ; } } Rglpk/src/GLPK/amd/amd_valid.c0000644000176000001440000000651512245352174015546 0ustar ripleyusers/* ========================================================================= */ /* === AMD_valid =========================================================== */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* Check if a column-form matrix is valid or not. The matrix A is * n_row-by-n_col. The row indices of entries in column j are in * Ai [Ap [j] ... Ap [j+1]-1]. Required conditions are: * * n_row >= 0 * n_col >= 0 * nz = Ap [n_col] >= 0 number of entries in the matrix * Ap [0] == 0 * Ap [j] <= Ap [j+1] for all j in the range 0 to n_col. * Ai [0 ... nz-1] must be in the range 0 to n_row-1. * * If any of the above conditions hold, AMD_INVALID is returned. If the * following condition holds, AMD_OK_BUT_JUMBLED is returned (a warning, * not an error): * * row indices in Ai [Ap [j] ... Ap [j+1]-1] are not sorted in ascending * order, and/or duplicate entries exist. * * Otherwise, AMD_OK is returned. * * In v1.2 and earlier, this function returned TRUE if the matrix was valid * (now returns AMD_OK), or FALSE otherwise (now returns AMD_INVALID or * AMD_OK_BUT_JUMBLED). */ #include "amd_internal.h" GLOBAL Int AMD_valid ( /* inputs, not modified on output: */ Int n_row, /* A is n_row-by-n_col */ Int n_col, const Int Ap [ ], /* column pointers of A, of size n_col+1 */ const Int Ai [ ] /* row indices of A, of size nz = Ap [n_col] */ ) { Int nz, j, p1, p2, ilast, i, p, result = AMD_OK ; if (n_row < 0 || n_col < 0 || Ap == NULL || Ai == NULL) { return (AMD_INVALID) ; } nz = Ap [n_col] ; if (Ap [0] != 0 || nz < 0) { /* column pointers must start at Ap [0] = 0, and Ap [n] must be >= 0 */ AMD_DEBUG0 (("column 0 pointer bad or nz < 0\n")) ; return (AMD_INVALID) ; } for (j = 0 ; j < n_col ; j++) { p1 = Ap [j] ; p2 = Ap [j+1] ; AMD_DEBUG2 (("\nColumn: "ID" p1: "ID" p2: "ID"\n", j, p1, p2)) ; if (p1 > p2) { /* column pointers must be ascending */ AMD_DEBUG0 (("column "ID" pointer bad\n", j)) ; return (AMD_INVALID) ; } ilast = EMPTY ; for (p = p1 ; p < p2 ; p++) { i = Ai [p] ; AMD_DEBUG3 (("row: "ID"\n", i)) ; if (i < 0 || i >= n_row) { /* row index out of range */ AMD_DEBUG0 (("index out of range, col "ID" row "ID"\n", j, i)); return (AMD_INVALID) ; } if (i <= ilast) { /* row index unsorted, or duplicate entry present */ AMD_DEBUG1 (("index unsorted/dupl col "ID" row "ID"\n", j, i)); result = AMD_OK_BUT_JUMBLED ; } ilast = i ; } } return (result) ; } Rglpk/src/GLPK/amd/amd_1.c0000644000176000001440000001504312245352174014603 0ustar ripleyusers/* ========================================================================= */ /* === AMD_1 =============================================================== */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* AMD_1: Construct A+A' for a sparse matrix A and perform the AMD ordering. * * The n-by-n sparse matrix A can be unsymmetric. It is stored in MATLAB-style * compressed-column form, with sorted row indices in each column, and no * duplicate entries. Diagonal entries may be present, but they are ignored. * Row indices of column j of A are stored in Ai [Ap [j] ... Ap [j+1]-1]. * Ap [0] must be zero, and nz = Ap [n] is the number of entries in A. The * size of the matrix, n, must be greater than or equal to zero. * * This routine must be preceded by a call to AMD_aat, which computes the * number of entries in each row/column in A+A', excluding the diagonal. * Len [j], on input, is the number of entries in row/column j of A+A'. This * routine constructs the matrix A+A' and then calls AMD_2. No error checking * is performed (this was done in AMD_valid). */ #include "amd_internal.h" GLOBAL void AMD_1 ( Int n, /* n > 0 */ const Int Ap [ ], /* input of size n+1, not modified */ const Int Ai [ ], /* input of size nz = Ap [n], not modified */ Int P [ ], /* size n output permutation */ Int Pinv [ ], /* size n output inverse permutation */ Int Len [ ], /* size n input, undefined on output */ Int slen, /* slen >= sum (Len [0..n-1]) + 7n, * ideally slen = 1.2 * sum (Len) + 8n */ Int S [ ], /* size slen workspace */ double Control [ ], /* input array of size AMD_CONTROL */ double Info [ ] /* output array of size AMD_INFO */ ) { Int i, j, k, p, pfree, iwlen, pj, p1, p2, pj2, *Iw, *Pe, *Nv, *Head, *Elen, *Degree, *s, *W, *Sp, *Tp ; /* --------------------------------------------------------------------- */ /* construct the matrix for AMD_2 */ /* --------------------------------------------------------------------- */ ASSERT (n > 0) ; iwlen = slen - 6*n ; s = S ; Pe = s ; s += n ; Nv = s ; s += n ; Head = s ; s += n ; Elen = s ; s += n ; Degree = s ; s += n ; W = s ; s += n ; Iw = s ; s += iwlen ; ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ; /* construct the pointers for A+A' */ Sp = Nv ; /* use Nv and W as workspace for Sp and Tp [ */ Tp = W ; pfree = 0 ; for (j = 0 ; j < n ; j++) { Pe [j] = pfree ; Sp [j] = pfree ; pfree += Len [j] ; } /* Note that this restriction on iwlen is slightly more restrictive than * what is strictly required in AMD_2. AMD_2 can operate with no elbow * room at all, but it will be very slow. For better performance, at * least size-n elbow room is enforced. */ ASSERT (iwlen >= pfree + n) ; #ifndef NDEBUG for (p = 0 ; p < iwlen ; p++) Iw [p] = EMPTY ; #endif for (k = 0 ; k < n ; k++) { AMD_DEBUG1 (("Construct row/column k= "ID" of A+A'\n", k)) ; p1 = Ap [k] ; p2 = Ap [k+1] ; /* construct A+A' */ for (p = p1 ; p < p2 ; ) { /* scan the upper triangular part of A */ j = Ai [p] ; ASSERT (j >= 0 && j < n) ; if (j < k) { /* entry A (j,k) in the strictly upper triangular part */ ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ; ASSERT (Sp [k] < (k == n-1 ? pfree : Pe [k+1])) ; Iw [Sp [j]++] = k ; Iw [Sp [k]++] = j ; p++ ; } else if (j == k) { /* skip the diagonal */ p++ ; break ; } else /* j > k */ { /* first entry below the diagonal */ break ; } /* scan lower triangular part of A, in column j until reaching * row k. Start where last scan left off. */ ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ; pj2 = Ap [j+1] ; for (pj = Tp [j] ; pj < pj2 ; ) { i = Ai [pj] ; ASSERT (i >= 0 && i < n) ; if (i < k) { /* A (i,j) is only in the lower part, not in upper */ ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ; ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ; Iw [Sp [i]++] = j ; Iw [Sp [j]++] = i ; pj++ ; } else if (i == k) { /* entry A (k,j) in lower part and A (j,k) in upper */ pj++ ; break ; } else /* i > k */ { /* consider this entry later, when k advances to i */ break ; } } Tp [j] = pj ; } Tp [k] = p ; } /* clean up, for remaining mismatched entries */ for (j = 0 ; j < n ; j++) { for (pj = Tp [j] ; pj < Ap [j+1] ; pj++) { i = Ai [pj] ; ASSERT (i >= 0 && i < n) ; /* A (i,j) is only in the lower part, not in upper */ ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ; ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ; Iw [Sp [i]++] = j ; Iw [Sp [j]++] = i ; } } #ifndef NDEBUG for (j = 0 ; j < n-1 ; j++) ASSERT (Sp [j] == Pe [j+1]) ; ASSERT (Sp [n-1] == pfree) ; #endif /* Tp and Sp no longer needed ] */ /* --------------------------------------------------------------------- */ /* order the matrix */ /* --------------------------------------------------------------------- */ AMD_2 (n, Pe, Iw, Len, iwlen, pfree, Nv, Pinv, P, Head, Elen, Degree, W, Control, Info) ; } Rglpk/src/GLPK/amd/amd_2.c0000644000176000001440000023050112245352174014602 0ustar ripleyusers/* ========================================================================= */ /* === AMD_2 =============================================================== */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* AMD_2: performs the AMD ordering on a symmetric sparse matrix A, followed * by a postordering (via depth-first search) of the assembly tree using the * AMD_postorder routine. */ #include "amd_internal.h" /* ========================================================================= */ /* === clear_flag ========================================================== */ /* ========================================================================= */ static Int clear_flag (Int wflg, Int wbig, Int W [ ], Int n) { Int x ; if (wflg < 2 || wflg >= wbig) { for (x = 0 ; x < n ; x++) { if (W [x] != 0) W [x] = 1 ; } wflg = 2 ; } /* at this point, W [0..n-1] < wflg holds */ return (wflg) ; } /* ========================================================================= */ /* === AMD_2 =============================================================== */ /* ========================================================================= */ GLOBAL void AMD_2 ( Int n, /* A is n-by-n, where n > 0 */ Int Pe [ ], /* Pe [0..n-1]: index in Iw of row i on input */ Int Iw [ ], /* workspace of size iwlen. Iw [0..pfree-1] * holds the matrix on input */ Int Len [ ], /* Len [0..n-1]: length for row/column i on input */ Int iwlen, /* length of Iw. iwlen >= pfree + n */ Int pfree, /* Iw [pfree ... iwlen-1] is empty on input */ /* 7 size-n workspaces, not defined on input: */ Int Nv [ ], /* the size of each supernode on output */ Int Next [ ], /* the output inverse permutation */ Int Last [ ], /* the output permutation */ Int Head [ ], Int Elen [ ], /* the size columns of L for each supernode */ Int Degree [ ], Int W [ ], /* control parameters and output statistics */ double Control [ ], /* array of size AMD_CONTROL */ double Info [ ] /* array of size AMD_INFO */ ) { /* * Given a representation of the nonzero pattern of a symmetric matrix, A, * (excluding the diagonal) perform an approximate minimum (UMFPACK/MA38-style) * degree ordering to compute a pivot order such that the introduction of * nonzeros (fill-in) in the Cholesky factors A = LL' is kept low. At each * step, the pivot selected is the one with the minimum UMFAPACK/MA38-style * upper-bound on the external degree. This routine can optionally perform * aggresive absorption (as done by MC47B in the Harwell Subroutine * Library). * * The approximate degree algorithm implemented here is the symmetric analog of * the degree update algorithm in MA38 and UMFPACK (the Unsymmetric-pattern * MultiFrontal PACKage, both by Davis and Duff). The routine is based on the * MA27 minimum degree ordering algorithm by Iain Duff and John Reid. * * This routine is a translation of the original AMDBAR and MC47B routines, * in Fortran, with the following modifications: * * (1) dense rows/columns are removed prior to ordering the matrix, and placed * last in the output order. The presence of a dense row/column can * increase the ordering time by up to O(n^2), unless they are removed * prior to ordering. * * (2) the minimum degree ordering is followed by a postordering (depth-first * search) of the assembly tree. Note that mass elimination (discussed * below) combined with the approximate degree update can lead to the mass * elimination of nodes with lower exact degree than the current pivot * element. No additional fill-in is caused in the representation of the * Schur complement. The mass-eliminated nodes merge with the current * pivot element. They are ordered prior to the current pivot element. * Because they can have lower exact degree than the current element, the * merger of two or more of these nodes in the current pivot element can * lead to a single element that is not a "fundamental supernode". The * diagonal block can have zeros in it. Thus, the assembly tree used here * is not guaranteed to be the precise supernodal elemination tree (with * "funadmental" supernodes), and the postordering performed by this * routine is not guaranteed to be a precise postordering of the * elimination tree. * * (3) input parameters are added, to control aggressive absorption and the * detection of "dense" rows/columns of A. * * (4) additional statistical information is returned, such as the number of * nonzeros in L, and the flop counts for subsequent LDL' and LU * factorizations. These are slight upper bounds, because of the mass * elimination issue discussed above. * * (5) additional routines are added to interface this routine to MATLAB * to provide a simple C-callable user-interface, to check inputs for * errors, compute the symmetry of the pattern of A and the number of * nonzeros in each row/column of A+A', to compute the pattern of A+A', * to perform the assembly tree postordering, and to provide debugging * ouput. Many of these functions are also provided by the Fortran * Harwell Subroutine Library routine MC47A. * * (6) both int and UF_long versions are provided. In the descriptions below * and integer is and int or UF_long depending on which version is * being used. ********************************************************************** ***** CAUTION: ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT. ****** ********************************************************************** ** If you want error checking, a more versatile input format, and a ** ** simpler user interface, use amd_order or amd_l_order instead. ** ** This routine is not meant to be user-callable. ** ********************************************************************** * ---------------------------------------------------------------------------- * References: * ---------------------------------------------------------------------------- * * [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern multifrontal * method for sparse LU factorization", SIAM J. Matrix Analysis and * Applications, vol. 18, no. 1, pp. 140-158. Discusses UMFPACK / MA38, * which first introduced the approximate minimum degree used by this * routine. * * [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An approximate * minimum degree ordering algorithm," SIAM J. Matrix Analysis and * Applications, vol. 17, no. 4, pp. 886-905, 1996. Discusses AMDBAR and * MC47B, which are the Fortran versions of this routine. * * [3] Alan George and Joseph Liu, "The evolution of the minimum degree * ordering algorithm," SIAM Review, vol. 31, no. 1, pp. 1-19, 1989. * We list below the features mentioned in that paper that this code * includes: * * mass elimination: * Yes. MA27 relied on supervariable detection for mass elimination. * * indistinguishable nodes: * Yes (we call these "supervariables"). This was also in the MA27 * code - although we modified the method of detecting them (the * previous hash was the true degree, which we no longer keep track * of). A supervariable is a set of rows with identical nonzero * pattern. All variables in a supervariable are eliminated together. * Each supervariable has as its numerical name that of one of its * variables (its principal variable). * * quotient graph representation: * Yes. We use the term "element" for the cliques formed during * elimination. This was also in the MA27 code. The algorithm can * operate in place, but it will work more efficiently if given some * "elbow room." * * element absorption: * Yes. This was also in the MA27 code. * * external degree: * Yes. The MA27 code was based on the true degree. * * incomplete degree update and multiple elimination: * No. This was not in MA27, either. Our method of degree update * within MC47B is element-based, not variable-based. It is thus * not well-suited for use with incomplete degree update or multiple * elimination. * * Authors, and Copyright (C) 2004 by: * Timothy A. Davis, Patrick Amestoy, Iain S. Duff, John K. Reid. * * Acknowledgements: This work (and the UMFPACK package) was supported by the * National Science Foundation (ASC-9111263, DMS-9223088, and CCR-0203270). * The UMFPACK/MA38 approximate degree update algorithm, the unsymmetric analog * which forms the basis of AMD, was developed while Tim Davis was supported by * CERFACS (Toulouse, France) in a post-doctoral position. This C version, and * the etree postorder, were written while Tim Davis was on sabbatical at * Stanford University and Lawrence Berkeley National Laboratory. * ---------------------------------------------------------------------------- * INPUT ARGUMENTS (unaltered): * ---------------------------------------------------------------------------- * n: The matrix order. Restriction: n >= 1. * * iwlen: The size of the Iw array. On input, the matrix is stored in * Iw [0..pfree-1]. However, Iw [0..iwlen-1] should be slightly larger * than what is required to hold the matrix, at least iwlen >= pfree + n. * Otherwise, excessive compressions will take place. The recommended * value of iwlen is 1.2 * pfree + n, which is the value used in the * user-callable interface to this routine (amd_order.c). The algorithm * will not run at all if iwlen < pfree. Restriction: iwlen >= pfree + n. * Note that this is slightly more restrictive than the actual minimum * (iwlen >= pfree), but AMD_2 will be very slow with no elbow room. * Thus, this routine enforces a bare minimum elbow room of size n. * * pfree: On input the tail end of the array, Iw [pfree..iwlen-1], is empty, * and the matrix is stored in Iw [0..pfree-1]. During execution, * additional data is placed in Iw, and pfree is modified so that * Iw [pfree..iwlen-1] is always the unused part of Iw. * * Control: A double array of size AMD_CONTROL containing input parameters * that affect how the ordering is computed. If NULL, then default * settings are used. * * Control [AMD_DENSE] is used to determine whether or not a given input * row is "dense". A row is "dense" if the number of entries in the row * exceeds Control [AMD_DENSE] times sqrt (n), except that rows with 16 or * fewer entries are never considered "dense". To turn off the detection * of dense rows, set Control [AMD_DENSE] to a negative number, or to a * number larger than sqrt (n). The default value of Control [AMD_DENSE] * is AMD_DEFAULT_DENSE, which is defined in amd.h as 10. * * Control [AMD_AGGRESSIVE] is used to determine whether or not aggressive * absorption is to be performed. If nonzero, then aggressive absorption * is performed (this is the default). * ---------------------------------------------------------------------------- * INPUT/OUPUT ARGUMENTS: * ---------------------------------------------------------------------------- * * Pe: An integer array of size n. On input, Pe [i] is the index in Iw of * the start of row i. Pe [i] is ignored if row i has no off-diagonal * entries. Thus Pe [i] must be in the range 0 to pfree-1 for non-empty * rows. * * During execution, it is used for both supervariables and elements: * * Principal supervariable i: index into Iw of the description of * supervariable i. A supervariable represents one or more rows of * the matrix with identical nonzero pattern. In this case, * Pe [i] >= 0. * * Non-principal supervariable i: if i has been absorbed into another * supervariable j, then Pe [i] = FLIP (j), where FLIP (j) is defined * as (-(j)-2). Row j has the same pattern as row i. Note that j * might later be absorbed into another supervariable j2, in which * case Pe [i] is still FLIP (j), and Pe [j] = FLIP (j2) which is * < EMPTY, where EMPTY is defined as (-1) in amd_internal.h. * * Unabsorbed element e: the index into Iw of the description of element * e, if e has not yet been absorbed by a subsequent element. Element * e is created when the supervariable of the same name is selected as * the pivot. In this case, Pe [i] >= 0. * * Absorbed element e: if element e is absorbed into element e2, then * Pe [e] = FLIP (e2). This occurs when the pattern of e (which we * refer to as Le) is found to be a subset of the pattern of e2 (that * is, Le2). In this case, Pe [i] < EMPTY. If element e is "null" * (it has no nonzeros outside its pivot block), then Pe [e] = EMPTY, * and e is the root of an assembly subtree (or the whole tree if * there is just one such root). * * Dense variable i: if i is "dense", then Pe [i] = EMPTY. * * On output, Pe holds the assembly tree/forest, which implicitly * represents a pivot order with identical fill-in as the actual order * (via a depth-first search of the tree), as follows. If Nv [i] > 0, * then i represents a node in the assembly tree, and the parent of i is * Pe [i], or EMPTY if i is a root. If Nv [i] = 0, then (i, Pe [i]) * represents an edge in a subtree, the root of which is a node in the * assembly tree. Note that i refers to a row/column in the original * matrix, not the permuted matrix. * * Info: A double array of size AMD_INFO. If present, (that is, not NULL), * then statistics about the ordering are returned in the Info array. * See amd.h for a description. * ---------------------------------------------------------------------------- * INPUT/MODIFIED (undefined on output): * ---------------------------------------------------------------------------- * * Len: An integer array of size n. On input, Len [i] holds the number of * entries in row i of the matrix, excluding the diagonal. The contents * of Len are undefined on output. * * Iw: An integer array of size iwlen. On input, Iw [0..pfree-1] holds the * description of each row i in the matrix. The matrix must be symmetric, * and both upper and lower triangular parts must be present. The * diagonal must not be present. Row i is held as follows: * * Len [i]: the length of the row i data structure in the Iw array. * Iw [Pe [i] ... Pe [i] + Len [i] - 1]: * the list of column indices for nonzeros in row i (simple * supervariables), excluding the diagonal. All supervariables * start with one row/column each (supervariable i is just row i). * If Len [i] is zero on input, then Pe [i] is ignored on input. * * Note that the rows need not be in any particular order, and there * may be empty space between the rows. * * During execution, the supervariable i experiences fill-in. This is * represented by placing in i a list of the elements that cause fill-in * in supervariable i: * * Len [i]: the length of supervariable i in the Iw array. * Iw [Pe [i] ... Pe [i] + Elen [i] - 1]: * the list of elements that contain i. This list is kept short * by removing absorbed elements. * Iw [Pe [i] + Elen [i] ... Pe [i] + Len [i] - 1]: * the list of supervariables in i. This list is kept short by * removing nonprincipal variables, and any entry j that is also * contained in at least one of the elements (j in Le) in the list * for i (e in row i). * * When supervariable i is selected as pivot, we create an element e of * the same name (e=i): * * Len [e]: the length of element e in the Iw array. * Iw [Pe [e] ... Pe [e] + Len [e] - 1]: * the list of supervariables in element e. * * An element represents the fill-in that occurs when supervariable i is * selected as pivot (which represents the selection of row i and all * non-principal variables whose principal variable is i). We use the * term Le to denote the set of all supervariables in element e. Absorbed * supervariables and elements are pruned from these lists when * computationally convenient. * * CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION. * The contents of Iw are undefined on output. * ---------------------------------------------------------------------------- * OUTPUT (need not be set on input): * ---------------------------------------------------------------------------- * * Nv: An integer array of size n. During execution, ABS (Nv [i]) is equal to * the number of rows that are represented by the principal supervariable * i. If i is a nonprincipal or dense variable, then Nv [i] = 0. * Initially, Nv [i] = 1 for all i. Nv [i] < 0 signifies that i is a * principal variable in the pattern Lme of the current pivot element me. * After element me is constructed, Nv [i] is set back to a positive * value. * * On output, Nv [i] holds the number of pivots represented by super * row/column i of the original matrix, or Nv [i] = 0 for non-principal * rows/columns. Note that i refers to a row/column in the original * matrix, not the permuted matrix. * * Elen: An integer array of size n. See the description of Iw above. At the * start of execution, Elen [i] is set to zero for all rows i. During * execution, Elen [i] is the number of elements in the list for * supervariable i. When e becomes an element, Elen [e] = FLIP (esize) is * set, where esize is the size of the element (the number of pivots, plus * the number of nonpivotal entries). Thus Elen [e] < EMPTY. * Elen (i) = EMPTY set when variable i becomes nonprincipal. * * For variables, Elen (i) >= EMPTY holds until just before the * postordering and permutation vectors are computed. For elements, * Elen [e] < EMPTY holds. * * On output, Elen [i] is the degree of the row/column in the Cholesky * factorization of the permuted matrix, corresponding to the original row * i, if i is a super row/column. It is equal to EMPTY if i is * non-principal. Note that i refers to a row/column in the original * matrix, not the permuted matrix. * * Note that the contents of Elen on output differ from the Fortran * version (Elen holds the inverse permutation in the Fortran version, * which is instead returned in the Next array in this C version, * described below). * * Last: In a degree list, Last [i] is the supervariable preceding i, or EMPTY * if i is the head of the list. In a hash bucket, Last [i] is the hash * key for i. * * Last [Head [hash]] is also used as the head of a hash bucket if * Head [hash] contains a degree list (see the description of Head, * below). * * On output, Last [0..n-1] holds the permutation. That is, if * i = Last [k], then row i is the kth pivot row (where k ranges from 0 to * n-1). Row Last [k] of A is the kth row in the permuted matrix, PAP'. * * Next: Next [i] is the supervariable following i in a link list, or EMPTY if * i is the last in the list. Used for two kinds of lists: degree lists * and hash buckets (a supervariable can be in only one kind of list at a * time). * * On output Next [0..n-1] holds the inverse permutation. That is, if * k = Next [i], then row i is the kth pivot row. Row i of A appears as * the (Next[i])-th row in the permuted matrix, PAP'. * * Note that the contents of Next on output differ from the Fortran * version (Next is undefined on output in the Fortran version). * ---------------------------------------------------------------------------- * LOCAL WORKSPACE (not input or output - used only during execution): * ---------------------------------------------------------------------------- * * Degree: An integer array of size n. If i is a supervariable, then * Degree [i] holds the current approximation of the external degree of * row i (an upper bound). The external degree is the number of nonzeros * in row i, minus ABS (Nv [i]), the diagonal part. The bound is equal to * the exact external degree if Elen [i] is less than or equal to two. * * We also use the term "external degree" for elements e to refer to * |Le \ Lme|. If e is an element, then Degree [e] is |Le|, which is the * degree of the off-diagonal part of the element e (not including the * diagonal part). * * Head: An integer array of size n. Head is used for degree lists. * Head [deg] is the first supervariable in a degree list. All * supervariables i in a degree list Head [deg] have the same approximate * degree, namely, deg = Degree [i]. If the list Head [deg] is empty then * Head [deg] = EMPTY. * * During supervariable detection Head [hash] also serves as a pointer to * a hash bucket. If Head [hash] >= 0, there is a degree list of degree * hash. The hash bucket head pointer is Last [Head [hash]]. If * Head [hash] = EMPTY, then the degree list and hash bucket are both * empty. If Head [hash] < EMPTY, then the degree list is empty, and * FLIP (Head [hash]) is the head of the hash bucket. After supervariable * detection is complete, all hash buckets are empty, and the * (Last [Head [hash]] = EMPTY) condition is restored for the non-empty * degree lists. * * W: An integer array of size n. The flag array W determines the status of * elements and variables, and the external degree of elements. * * for elements: * if W [e] = 0, then the element e is absorbed. * if W [e] >= wflg, then W [e] - wflg is the size of the set * |Le \ Lme|, in terms of nonzeros (the sum of ABS (Nv [i]) for * each principal variable i that is both in the pattern of * element e and NOT in the pattern of the current pivot element, * me). * if wflg > W [e] > 0, then e is not absorbed and has not yet been * seen in the scan of the element lists in the computation of * |Le\Lme| in Scan 1 below. * * for variables: * during supervariable detection, if W [j] != wflg then j is * not in the pattern of variable i. * * The W array is initialized by setting W [i] = 1 for all i, and by * setting wflg = 2. It is reinitialized if wflg becomes too large (to * ensure that wflg+n does not cause integer overflow). * ---------------------------------------------------------------------------- * LOCAL INTEGERS: * ---------------------------------------------------------------------------- */ Int deg, degme, dext, lemax, e, elenme, eln, i, ilast, inext, j, jlast, jnext, k, knt1, knt2, knt3, lenj, ln, me, mindeg, nel, nleft, nvi, nvj, nvpiv, slenme, wbig, we, wflg, wnvi, ok, ndense, ncmpa, dense, aggressive ; unsigned Int hash ; /* unsigned, so that hash % n is well defined.*/ /* * deg: the degree of a variable or element * degme: size, |Lme|, of the current element, me (= Degree [me]) * dext: external degree, |Le \ Lme|, of some element e * lemax: largest |Le| seen so far (called dmax in Fortran version) * e: an element * elenme: the length, Elen [me], of element list of pivotal variable * eln: the length, Elen [...], of an element list * hash: the computed value of the hash function * i: a supervariable * ilast: the entry in a link list preceding i * inext: the entry in a link list following i * j: a supervariable * jlast: the entry in a link list preceding j * jnext: the entry in a link list, or path, following j * k: the pivot order of an element or variable * knt1: loop counter used during element construction * knt2: loop counter used during element construction * knt3: loop counter used during compression * lenj: Len [j] * ln: length of a supervariable list * me: current supervariable being eliminated, and the current * element created by eliminating that supervariable * mindeg: current minimum degree * nel: number of pivots selected so far * nleft: n - nel, the number of nonpivotal rows/columns remaining * nvi: the number of variables in a supervariable i (= Nv [i]) * nvj: the number of variables in a supervariable j (= Nv [j]) * nvpiv: number of pivots in current element * slenme: number of variables in variable list of pivotal variable * wbig: = INT_MAX - n for the int version, UF_long_max - n for the * UF_long version. wflg is not allowed to be >= wbig. * we: W [e] * wflg: used for flagging the W array. See description of Iw. * wnvi: wflg - Nv [i] * x: either a supervariable or an element * * ok: true if supervariable j can be absorbed into i * ndense: number of "dense" rows/columns * dense: rows/columns with initial degree > dense are considered "dense" * aggressive: true if aggressive absorption is being performed * ncmpa: number of garbage collections * ---------------------------------------------------------------------------- * LOCAL DOUBLES, used for statistical output only (except for alpha): * ---------------------------------------------------------------------------- */ double f, r, ndiv, s, nms_lu, nms_ldl, dmax, alpha, lnz, lnzme ; /* * f: nvpiv * r: degme + nvpiv * ndiv: number of divisions for LU or LDL' factorizations * s: number of multiply-subtract pairs for LU factorization, for the * current element me * nms_lu number of multiply-subtract pairs for LU factorization * nms_ldl number of multiply-subtract pairs for LDL' factorization * dmax: the largest number of entries in any column of L, including the * diagonal * alpha: "dense" degree ratio * lnz: the number of nonzeros in L (excluding the diagonal) * lnzme: the number of nonzeros in L (excl. the diagonal) for the * current element me * ---------------------------------------------------------------------------- * LOCAL "POINTERS" (indices into the Iw array) * ---------------------------------------------------------------------------- */ Int p, p1, p2, p3, p4, pdst, pend, pj, pme, pme1, pme2, pn, psrc ; /* * Any parameter (Pe [...] or pfree) or local variable starting with "p" (for * Pointer) is an index into Iw, and all indices into Iw use variables starting * with "p." The only exception to this rule is the iwlen input argument. * * p: pointer into lots of things * p1: Pe [i] for some variable i (start of element list) * p2: Pe [i] + Elen [i] - 1 for some variable i * p3: index of first supervariable in clean list * p4: * pdst: destination pointer, for compression * pend: end of memory to compress * pj: pointer into an element or variable * pme: pointer into the current element (pme1...pme2) * pme1: the current element, me, is stored in Iw [pme1...pme2] * pme2: the end of the current element * pn: pointer into a "clean" variable, also used to compress * psrc: source pointer, for compression */ /* ========================================================================= */ /* INITIALIZATIONS */ /* ========================================================================= */ /* Note that this restriction on iwlen is slightly more restrictive than * what is actually required in AMD_2. AMD_2 can operate with no elbow * room at all, but it will be slow. For better performance, at least * size-n elbow room is enforced. */ ASSERT (iwlen >= pfree + n) ; ASSERT (n > 0) ; /* initialize output statistics */ lnz = 0 ; ndiv = 0 ; nms_lu = 0 ; nms_ldl = 0 ; dmax = 1 ; me = EMPTY ; mindeg = 0 ; ncmpa = 0 ; nel = 0 ; lemax = 0 ; /* get control parameters */ if (Control != (double *) NULL) { alpha = Control [AMD_DENSE] ; aggressive = (Control [AMD_AGGRESSIVE] != 0) ; } else { alpha = AMD_DEFAULT_DENSE ; aggressive = AMD_DEFAULT_AGGRESSIVE ; } /* Note: if alpha is NaN, this is undefined: */ if (alpha < 0) { /* only remove completely dense rows/columns */ dense = n-2 ; } else { dense = alpha * sqrt ((double) n) ; } dense = MAX (16, dense) ; dense = MIN (n, dense) ; AMD_DEBUG1 (("\n\nAMD (debug), alpha %g, aggr. "ID"\n", alpha, aggressive)) ; for (i = 0 ; i < n ; i++) { Last [i] = EMPTY ; Head [i] = EMPTY ; Next [i] = EMPTY ; /* if separate Hhead array is used for hash buckets: * Hhead [i] = EMPTY ; */ Nv [i] = 1 ; W [i] = 1 ; Elen [i] = 0 ; Degree [i] = Len [i] ; } #ifndef NDEBUG AMD_DEBUG1 (("\n======Nel "ID" initial\n", nel)) ; AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next, Last, Head, Elen, Degree, W, -1) ; #endif /* initialize wflg */ wbig = Int_MAX - n ; wflg = clear_flag (0, wbig, W, n) ; /* --------------------------------------------------------------------- */ /* initialize degree lists and eliminate dense and empty rows */ /* --------------------------------------------------------------------- */ ndense = 0 ; for (i = 0 ; i < n ; i++) { deg = Degree [i] ; ASSERT (deg >= 0 && deg < n) ; if (deg == 0) { /* ------------------------------------------------------------- * we have a variable that can be eliminated at once because * there is no off-diagonal non-zero in its row. Note that * Nv [i] = 1 for an empty variable i. It is treated just * the same as an eliminated element i. * ------------------------------------------------------------- */ Elen [i] = FLIP (1) ; nel++ ; Pe [i] = EMPTY ; W [i] = 0 ; } else if (deg > dense) { /* ------------------------------------------------------------- * Dense variables are not treated as elements, but as unordered, * non-principal variables that have no parent. They do not take * part in the postorder, since Nv [i] = 0. Note that the Fortran * version does not have this option. * ------------------------------------------------------------- */ AMD_DEBUG1 (("Dense node "ID" degree "ID"\n", i, deg)) ; ndense++ ; Nv [i] = 0 ; /* do not postorder this node */ Elen [i] = EMPTY ; nel++ ; Pe [i] = EMPTY ; } else { /* ------------------------------------------------------------- * place i in the degree list corresponding to its degree * ------------------------------------------------------------- */ inext = Head [deg] ; ASSERT (inext >= EMPTY && inext < n) ; if (inext != EMPTY) Last [inext] = i ; Next [i] = inext ; Head [deg] = i ; } } /* ========================================================================= */ /* WHILE (selecting pivots) DO */ /* ========================================================================= */ while (nel < n) { #ifndef NDEBUG AMD_DEBUG1 (("\n======Nel "ID"\n", nel)) ; if (AMD_debug >= 2) { AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next, Last, Head, Elen, Degree, W, nel) ; } #endif /* ========================================================================= */ /* GET PIVOT OF MINIMUM DEGREE */ /* ========================================================================= */ /* ----------------------------------------------------------------- */ /* find next supervariable for elimination */ /* ----------------------------------------------------------------- */ ASSERT (mindeg >= 0 && mindeg < n) ; for (deg = mindeg ; deg < n ; deg++) { me = Head [deg] ; if (me != EMPTY) break ; } mindeg = deg ; ASSERT (me >= 0 && me < n) ; AMD_DEBUG1 (("=================me: "ID"\n", me)) ; /* ----------------------------------------------------------------- */ /* remove chosen variable from link list */ /* ----------------------------------------------------------------- */ inext = Next [me] ; ASSERT (inext >= EMPTY && inext < n) ; if (inext != EMPTY) Last [inext] = EMPTY ; Head [deg] = inext ; /* ----------------------------------------------------------------- */ /* me represents the elimination of pivots nel to nel+Nv[me]-1. */ /* place me itself as the first in this set. */ /* ----------------------------------------------------------------- */ elenme = Elen [me] ; nvpiv = Nv [me] ; ASSERT (nvpiv > 0) ; nel += nvpiv ; /* ========================================================================= */ /* CONSTRUCT NEW ELEMENT */ /* ========================================================================= */ /* ----------------------------------------------------------------- * At this point, me is the pivotal supervariable. It will be * converted into the current element. Scan list of the pivotal * supervariable, me, setting tree pointers and constructing new list * of supervariables for the new element, me. p is a pointer to the * current position in the old list. * ----------------------------------------------------------------- */ /* flag the variable "me" as being in Lme by negating Nv [me] */ Nv [me] = -nvpiv ; degme = 0 ; ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ; if (elenme == 0) { /* ------------------------------------------------------------- */ /* construct the new element in place */ /* ------------------------------------------------------------- */ pme1 = Pe [me] ; pme2 = pme1 - 1 ; for (p = pme1 ; p <= pme1 + Len [me] - 1 ; p++) { i = Iw [p] ; ASSERT (i >= 0 && i < n && Nv [i] >= 0) ; nvi = Nv [i] ; if (nvi > 0) { /* ----------------------------------------------------- */ /* i is a principal variable not yet placed in Lme. */ /* store i in new list */ /* ----------------------------------------------------- */ /* flag i as being in Lme by negating Nv [i] */ degme += nvi ; Nv [i] = -nvi ; Iw [++pme2] = i ; /* ----------------------------------------------------- */ /* remove variable i from degree list. */ /* ----------------------------------------------------- */ ilast = Last [i] ; inext = Next [i] ; ASSERT (ilast >= EMPTY && ilast < n) ; ASSERT (inext >= EMPTY && inext < n) ; if (inext != EMPTY) Last [inext] = ilast ; if (ilast != EMPTY) { Next [ilast] = inext ; } else { /* i is at the head of the degree list */ ASSERT (Degree [i] >= 0 && Degree [i] < n) ; Head [Degree [i]] = inext ; } } } } else { /* ------------------------------------------------------------- */ /* construct the new element in empty space, Iw [pfree ...] */ /* ------------------------------------------------------------- */ p = Pe [me] ; pme1 = pfree ; slenme = Len [me] - elenme ; for (knt1 = 1 ; knt1 <= elenme + 1 ; knt1++) { if (knt1 > elenme) { /* search the supervariables in me. */ e = me ; pj = p ; ln = slenme ; AMD_DEBUG2 (("Search sv: "ID" "ID" "ID"\n", me,pj,ln)) ; } else { /* search the elements in me. */ e = Iw [p++] ; ASSERT (e >= 0 && e < n) ; pj = Pe [e] ; ln = Len [e] ; AMD_DEBUG2 (("Search element e "ID" in me "ID"\n", e,me)) ; ASSERT (Elen [e] < EMPTY && W [e] > 0 && pj >= 0) ; } ASSERT (ln >= 0 && (ln == 0 || (pj >= 0 && pj < iwlen))) ; /* --------------------------------------------------------- * search for different supervariables and add them to the * new list, compressing when necessary. this loop is * executed once for each element in the list and once for * all the supervariables in the list. * --------------------------------------------------------- */ for (knt2 = 1 ; knt2 <= ln ; knt2++) { i = Iw [pj++] ; ASSERT (i >= 0 && i < n && (i == me || Elen [i] >= EMPTY)); nvi = Nv [i] ; AMD_DEBUG2 ((": "ID" "ID" "ID" "ID"\n", i, Elen [i], Nv [i], wflg)) ; if (nvi > 0) { /* ------------------------------------------------- */ /* compress Iw, if necessary */ /* ------------------------------------------------- */ if (pfree >= iwlen) { AMD_DEBUG1 (("GARBAGE COLLECTION\n")) ; /* prepare for compressing Iw by adjusting pointers * and lengths so that the lists being searched in * the inner and outer loops contain only the * remaining entries. */ Pe [me] = p ; Len [me] -= knt1 ; /* check if nothing left of supervariable me */ if (Len [me] == 0) Pe [me] = EMPTY ; Pe [e] = pj ; Len [e] = ln - knt2 ; /* nothing left of element e */ if (Len [e] == 0) Pe [e] = EMPTY ; ncmpa++ ; /* one more garbage collection */ /* store first entry of each object in Pe */ /* FLIP the first entry in each object */ for (j = 0 ; j < n ; j++) { pn = Pe [j] ; if (pn >= 0) { ASSERT (pn >= 0 && pn < iwlen) ; Pe [j] = Iw [pn] ; Iw [pn] = FLIP (j) ; } } /* psrc/pdst point to source/destination */ psrc = 0 ; pdst = 0 ; pend = pme1 - 1 ; while (psrc <= pend) { /* search for next FLIP'd entry */ j = FLIP (Iw [psrc++]) ; if (j >= 0) { AMD_DEBUG2 (("Got object j: "ID"\n", j)) ; Iw [pdst] = Pe [j] ; Pe [j] = pdst++ ; lenj = Len [j] ; /* copy from source to destination */ for (knt3 = 0 ; knt3 <= lenj - 2 ; knt3++) { Iw [pdst++] = Iw [psrc++] ; } } } /* move the new partially-constructed element */ p1 = pdst ; for (psrc = pme1 ; psrc <= pfree-1 ; psrc++) { Iw [pdst++] = Iw [psrc] ; } pme1 = p1 ; pfree = pdst ; pj = Pe [e] ; p = Pe [me] ; } /* ------------------------------------------------- */ /* i is a principal variable not yet placed in Lme */ /* store i in new list */ /* ------------------------------------------------- */ /* flag i as being in Lme by negating Nv [i] */ degme += nvi ; Nv [i] = -nvi ; Iw [pfree++] = i ; AMD_DEBUG2 ((" s: "ID" nv "ID"\n", i, Nv [i])); /* ------------------------------------------------- */ /* remove variable i from degree link list */ /* ------------------------------------------------- */ ilast = Last [i] ; inext = Next [i] ; ASSERT (ilast >= EMPTY && ilast < n) ; ASSERT (inext >= EMPTY && inext < n) ; if (inext != EMPTY) Last [inext] = ilast ; if (ilast != EMPTY) { Next [ilast] = inext ; } else { /* i is at the head of the degree list */ ASSERT (Degree [i] >= 0 && Degree [i] < n) ; Head [Degree [i]] = inext ; } } } if (e != me) { /* set tree pointer and flag to indicate element e is * absorbed into new element me (the parent of e is me) */ AMD_DEBUG1 ((" Element "ID" => "ID"\n", e, me)) ; Pe [e] = FLIP (me) ; W [e] = 0 ; } } pme2 = pfree - 1 ; } /* ----------------------------------------------------------------- */ /* me has now been converted into an element in Iw [pme1..pme2] */ /* ----------------------------------------------------------------- */ /* degme holds the external degree of new element */ Degree [me] = degme ; Pe [me] = pme1 ; Len [me] = pme2 - pme1 + 1 ; ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ; Elen [me] = FLIP (nvpiv + degme) ; /* FLIP (Elen (me)) is now the degree of pivot (including * diagonal part). */ #ifndef NDEBUG AMD_DEBUG2 (("New element structure: length= "ID"\n", pme2-pme1+1)) ; for (pme = pme1 ; pme <= pme2 ; pme++) AMD_DEBUG3 ((" "ID"", Iw[pme])); AMD_DEBUG3 (("\n")) ; #endif /* ----------------------------------------------------------------- */ /* make sure that wflg is not too large. */ /* ----------------------------------------------------------------- */ /* With the current value of wflg, wflg+n must not cause integer * overflow */ wflg = clear_flag (wflg, wbig, W, n) ; /* ========================================================================= */ /* COMPUTE (W [e] - wflg) = |Le\Lme| FOR ALL ELEMENTS */ /* ========================================================================= */ /* ----------------------------------------------------------------- * Scan 1: compute the external degrees of previous elements with * respect to the current element. That is: * (W [e] - wflg) = |Le \ Lme| * for each element e that appears in any supervariable in Lme. The * notation Le refers to the pattern (list of supervariables) of a * previous element e, where e is not yet absorbed, stored in * Iw [Pe [e] + 1 ... Pe [e] + Len [e]]. The notation Lme * refers to the pattern of the current element (stored in * Iw [pme1..pme2]). If aggressive absorption is enabled, and * (W [e] - wflg) becomes zero, then the element e will be absorbed * in Scan 2. * ----------------------------------------------------------------- */ AMD_DEBUG2 (("me: ")) ; for (pme = pme1 ; pme <= pme2 ; pme++) { i = Iw [pme] ; ASSERT (i >= 0 && i < n) ; eln = Elen [i] ; AMD_DEBUG3 ((""ID" Elen "ID": \n", i, eln)) ; if (eln > 0) { /* note that Nv [i] has been negated to denote i in Lme: */ nvi = -Nv [i] ; ASSERT (nvi > 0 && Pe [i] >= 0 && Pe [i] < iwlen) ; wnvi = wflg - nvi ; for (p = Pe [i] ; p <= Pe [i] + eln - 1 ; p++) { e = Iw [p] ; ASSERT (e >= 0 && e < n) ; we = W [e] ; AMD_DEBUG4 ((" e "ID" we "ID" ", e, we)) ; if (we >= wflg) { /* unabsorbed element e has been seen in this loop */ AMD_DEBUG4 ((" unabsorbed, first time seen")) ; we -= nvi ; } else if (we != 0) { /* e is an unabsorbed element */ /* this is the first we have seen e in all of Scan 1 */ AMD_DEBUG4 ((" unabsorbed")) ; we = Degree [e] + wnvi ; } AMD_DEBUG4 (("\n")) ; W [e] = we ; } } } AMD_DEBUG2 (("\n")) ; /* ========================================================================= */ /* DEGREE UPDATE AND ELEMENT ABSORPTION */ /* ========================================================================= */ /* ----------------------------------------------------------------- * Scan 2: for each i in Lme, sum up the degree of Lme (which is * degme), plus the sum of the external degrees of each Le for the * elements e appearing within i, plus the supervariables in i. * Place i in hash list. * ----------------------------------------------------------------- */ for (pme = pme1 ; pme <= pme2 ; pme++) { i = Iw [pme] ; ASSERT (i >= 0 && i < n && Nv [i] < 0 && Elen [i] >= 0) ; AMD_DEBUG2 (("Updating: i "ID" "ID" "ID"\n", i, Elen[i], Len [i])); p1 = Pe [i] ; p2 = p1 + Elen [i] - 1 ; pn = p1 ; hash = 0 ; deg = 0 ; ASSERT (p1 >= 0 && p1 < iwlen && p2 >= -1 && p2 < iwlen) ; /* ------------------------------------------------------------- */ /* scan the element list associated with supervariable i */ /* ------------------------------------------------------------- */ /* UMFPACK/MA38-style approximate degree: */ if (aggressive) { for (p = p1 ; p <= p2 ; p++) { e = Iw [p] ; ASSERT (e >= 0 && e < n) ; we = W [e] ; if (we != 0) { /* e is an unabsorbed element */ /* dext = | Le \ Lme | */ dext = we - wflg ; if (dext > 0) { deg += dext ; Iw [pn++] = e ; hash += e ; AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ; } else { /* external degree of e is zero, absorb e into me*/ AMD_DEBUG1 ((" Element "ID" =>"ID" (aggressive)\n", e, me)) ; ASSERT (dext == 0) ; Pe [e] = FLIP (me) ; W [e] = 0 ; } } } } else { for (p = p1 ; p <= p2 ; p++) { e = Iw [p] ; ASSERT (e >= 0 && e < n) ; we = W [e] ; if (we != 0) { /* e is an unabsorbed element */ dext = we - wflg ; ASSERT (dext >= 0) ; deg += dext ; Iw [pn++] = e ; hash += e ; AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ; } } } /* count the number of elements in i (including me): */ Elen [i] = pn - p1 + 1 ; /* ------------------------------------------------------------- */ /* scan the supervariables in the list associated with i */ /* ------------------------------------------------------------- */ /* The bulk of the AMD run time is typically spent in this loop, * particularly if the matrix has many dense rows that are not * removed prior to ordering. */ p3 = pn ; p4 = p1 + Len [i] ; for (p = p2 + 1 ; p < p4 ; p++) { j = Iw [p] ; ASSERT (j >= 0 && j < n) ; nvj = Nv [j] ; if (nvj > 0) { /* j is unabsorbed, and not in Lme. */ /* add to degree and add to new list */ deg += nvj ; Iw [pn++] = j ; hash += j ; AMD_DEBUG4 ((" s: "ID" hash "ID" Nv[j]= "ID"\n", j, hash, nvj)) ; } } /* ------------------------------------------------------------- */ /* update the degree and check for mass elimination */ /* ------------------------------------------------------------- */ /* with aggressive absorption, deg==0 is identical to the * Elen [i] == 1 && p3 == pn test, below. */ ASSERT (IMPLIES (aggressive, (deg==0) == (Elen[i]==1 && p3==pn))) ; if (Elen [i] == 1 && p3 == pn) { /* --------------------------------------------------------- */ /* mass elimination */ /* --------------------------------------------------------- */ /* There is nothing left of this node except for an edge to * the current pivot element. Elen [i] is 1, and there are * no variables adjacent to node i. Absorb i into the * current pivot element, me. Note that if there are two or * more mass eliminations, fillin due to mass elimination is * possible within the nvpiv-by-nvpiv pivot block. It is this * step that causes AMD's analysis to be an upper bound. * * The reason is that the selected pivot has a lower * approximate degree than the true degree of the two mass * eliminated nodes. There is no edge between the two mass * eliminated nodes. They are merged with the current pivot * anyway. * * No fillin occurs in the Schur complement, in any case, * and this effect does not decrease the quality of the * ordering itself, just the quality of the nonzero and * flop count analysis. It also means that the post-ordering * is not an exact elimination tree post-ordering. */ AMD_DEBUG1 ((" MASS i "ID" => parent e "ID"\n", i, me)) ; Pe [i] = FLIP (me) ; nvi = -Nv [i] ; degme -= nvi ; nvpiv += nvi ; nel += nvi ; Nv [i] = 0 ; Elen [i] = EMPTY ; } else { /* --------------------------------------------------------- */ /* update the upper-bound degree of i */ /* --------------------------------------------------------- */ /* the following degree does not yet include the size * of the current element, which is added later: */ Degree [i] = MIN (Degree [i], deg) ; /* --------------------------------------------------------- */ /* add me to the list for i */ /* --------------------------------------------------------- */ /* move first supervariable to end of list */ Iw [pn] = Iw [p3] ; /* move first element to end of element part of list */ Iw [p3] = Iw [p1] ; /* add new element, me, to front of list. */ Iw [p1] = me ; /* store the new length of the list in Len [i] */ Len [i] = pn - p1 + 1 ; /* --------------------------------------------------------- */ /* place in hash bucket. Save hash key of i in Last [i]. */ /* --------------------------------------------------------- */ /* NOTE: this can fail if hash is negative, because the ANSI C * standard does not define a % b when a and/or b are negative. * That's why hash is defined as an unsigned Int, to avoid this * problem. */ hash = hash % n ; ASSERT (((Int) hash) >= 0 && ((Int) hash) < n) ; /* if the Hhead array is not used: */ j = Head [hash] ; if (j <= EMPTY) { /* degree list is empty, hash head is FLIP (j) */ Next [i] = FLIP (j) ; Head [hash] = FLIP (i) ; } else { /* degree list is not empty, use Last [Head [hash]] as * hash head. */ Next [i] = Last [j] ; Last [j] = i ; } /* if a separate Hhead array is used: * Next [i] = Hhead [hash] ; Hhead [hash] = i ; */ Last [i] = hash ; } } Degree [me] = degme ; /* ----------------------------------------------------------------- */ /* Clear the counter array, W [...], by incrementing wflg. */ /* ----------------------------------------------------------------- */ /* make sure that wflg+n does not cause integer overflow */ lemax = MAX (lemax, degme) ; wflg += lemax ; wflg = clear_flag (wflg, wbig, W, n) ; /* at this point, W [0..n-1] < wflg holds */ /* ========================================================================= */ /* SUPERVARIABLE DETECTION */ /* ========================================================================= */ AMD_DEBUG1 (("Detecting supervariables:\n")) ; for (pme = pme1 ; pme <= pme2 ; pme++) { i = Iw [pme] ; ASSERT (i >= 0 && i < n) ; AMD_DEBUG2 (("Consider i "ID" nv "ID"\n", i, Nv [i])) ; if (Nv [i] < 0) { /* i is a principal variable in Lme */ /* --------------------------------------------------------- * examine all hash buckets with 2 or more variables. We do * this by examing all unique hash keys for supervariables in * the pattern Lme of the current element, me * --------------------------------------------------------- */ /* let i = head of hash bucket, and empty the hash bucket */ ASSERT (Last [i] >= 0 && Last [i] < n) ; hash = Last [i] ; /* if Hhead array is not used: */ j = Head [hash] ; if (j == EMPTY) { /* hash bucket and degree list are both empty */ i = EMPTY ; } else if (j < EMPTY) { /* degree list is empty */ i = FLIP (j) ; Head [hash] = EMPTY ; } else { /* degree list is not empty, restore Last [j] of head j */ i = Last [j] ; Last [j] = EMPTY ; } /* if separate Hhead array is used: * i = Hhead [hash] ; Hhead [hash] = EMPTY ; */ ASSERT (i >= EMPTY && i < n) ; AMD_DEBUG2 (("----i "ID" hash "ID"\n", i, hash)) ; while (i != EMPTY && Next [i] != EMPTY) { /* ----------------------------------------------------- * this bucket has one or more variables following i. * scan all of them to see if i can absorb any entries * that follow i in hash bucket. Scatter i into w. * ----------------------------------------------------- */ ln = Len [i] ; eln = Elen [i] ; ASSERT (ln >= 0 && eln >= 0) ; ASSERT (Pe [i] >= 0 && Pe [i] < iwlen) ; /* do not flag the first element in the list (me) */ for (p = Pe [i] + 1 ; p <= Pe [i] + ln - 1 ; p++) { ASSERT (Iw [p] >= 0 && Iw [p] < n) ; W [Iw [p]] = wflg ; } /* ----------------------------------------------------- */ /* scan every other entry j following i in bucket */ /* ----------------------------------------------------- */ jlast = i ; j = Next [i] ; ASSERT (j >= EMPTY && j < n) ; while (j != EMPTY) { /* ------------------------------------------------- */ /* check if j and i have identical nonzero pattern */ /* ------------------------------------------------- */ AMD_DEBUG3 (("compare i "ID" and j "ID"\n", i,j)) ; /* check if i and j have the same Len and Elen */ ASSERT (Len [j] >= 0 && Elen [j] >= 0) ; ASSERT (Pe [j] >= 0 && Pe [j] < iwlen) ; ok = (Len [j] == ln) && (Elen [j] == eln) ; /* skip the first element in the list (me) */ for (p = Pe [j] + 1 ; ok && p <= Pe [j] + ln - 1 ; p++) { ASSERT (Iw [p] >= 0 && Iw [p] < n) ; if (W [Iw [p]] != wflg) ok = 0 ; } if (ok) { /* --------------------------------------------- */ /* found it! j can be absorbed into i */ /* --------------------------------------------- */ AMD_DEBUG1 (("found it! j "ID" => i "ID"\n", j,i)); Pe [j] = FLIP (i) ; /* both Nv [i] and Nv [j] are negated since they */ /* are in Lme, and the absolute values of each */ /* are the number of variables in i and j: */ Nv [i] += Nv [j] ; Nv [j] = 0 ; Elen [j] = EMPTY ; /* delete j from hash bucket */ ASSERT (j != Next [j]) ; j = Next [j] ; Next [jlast] = j ; } else { /* j cannot be absorbed into i */ jlast = j ; ASSERT (j != Next [j]) ; j = Next [j] ; } ASSERT (j >= EMPTY && j < n) ; } /* ----------------------------------------------------- * no more variables can be absorbed into i * go to next i in bucket and clear flag array * ----------------------------------------------------- */ wflg++ ; i = Next [i] ; ASSERT (i >= EMPTY && i < n) ; } } } AMD_DEBUG2 (("detect done\n")) ; /* ========================================================================= */ /* RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVARIABLES FROM ELEMENT */ /* ========================================================================= */ p = pme1 ; nleft = n - nel ; for (pme = pme1 ; pme <= pme2 ; pme++) { i = Iw [pme] ; ASSERT (i >= 0 && i < n) ; nvi = -Nv [i] ; AMD_DEBUG3 (("Restore i "ID" "ID"\n", i, nvi)) ; if (nvi > 0) { /* i is a principal variable in Lme */ /* restore Nv [i] to signify that i is principal */ Nv [i] = nvi ; /* --------------------------------------------------------- */ /* compute the external degree (add size of current element) */ /* --------------------------------------------------------- */ deg = Degree [i] + degme - nvi ; deg = MIN (deg, nleft - nvi) ; ASSERT (IMPLIES (aggressive, deg > 0) && deg >= 0 && deg < n) ; /* --------------------------------------------------------- */ /* place the supervariable at the head of the degree list */ /* --------------------------------------------------------- */ inext = Head [deg] ; ASSERT (inext >= EMPTY && inext < n) ; if (inext != EMPTY) Last [inext] = i ; Next [i] = inext ; Last [i] = EMPTY ; Head [deg] = i ; /* --------------------------------------------------------- */ /* save the new degree, and find the minimum degree */ /* --------------------------------------------------------- */ mindeg = MIN (mindeg, deg) ; Degree [i] = deg ; /* --------------------------------------------------------- */ /* place the supervariable in the element pattern */ /* --------------------------------------------------------- */ Iw [p++] = i ; } } AMD_DEBUG2 (("restore done\n")) ; /* ========================================================================= */ /* FINALIZE THE NEW ELEMENT */ /* ========================================================================= */ AMD_DEBUG2 (("ME = "ID" DONE\n", me)) ; Nv [me] = nvpiv ; /* save the length of the list for the new element me */ Len [me] = p - pme1 ; if (Len [me] == 0) { /* there is nothing left of the current pivot element */ /* it is a root of the assembly tree */ Pe [me] = EMPTY ; W [me] = 0 ; } if (elenme != 0) { /* element was not constructed in place: deallocate part of */ /* it since newly nonprincipal variables may have been removed */ pfree = p ; } /* The new element has nvpiv pivots and the size of the contribution * block for a multifrontal method is degme-by-degme, not including * the "dense" rows/columns. If the "dense" rows/columns are included, * the frontal matrix is no larger than * (degme+ndense)-by-(degme+ndense). */ if (Info != (double *) NULL) { f = nvpiv ; r = degme + ndense ; dmax = MAX (dmax, f + r) ; /* number of nonzeros in L (excluding the diagonal) */ lnzme = f*r + (f-1)*f/2 ; lnz += lnzme ; /* number of divide operations for LDL' and for LU */ ndiv += lnzme ; /* number of multiply-subtract pairs for LU */ s = f*r*r + r*(f-1)*f + (f-1)*f*(2*f-1)/6 ; nms_lu += s ; /* number of multiply-subtract pairs for LDL' */ nms_ldl += (s + lnzme)/2 ; } #ifndef NDEBUG AMD_DEBUG2 (("finalize done nel "ID" n "ID"\n ::::\n", nel, n)) ; for (pme = Pe [me] ; pme <= Pe [me] + Len [me] - 1 ; pme++) { AMD_DEBUG3 ((" "ID"", Iw [pme])) ; } AMD_DEBUG3 (("\n")) ; #endif } /* ========================================================================= */ /* DONE SELECTING PIVOTS */ /* ========================================================================= */ if (Info != (double *) NULL) { /* count the work to factorize the ndense-by-ndense submatrix */ f = ndense ; dmax = MAX (dmax, (double) ndense) ; /* number of nonzeros in L (excluding the diagonal) */ lnzme = (f-1)*f/2 ; lnz += lnzme ; /* number of divide operations for LDL' and for LU */ ndiv += lnzme ; /* number of multiply-subtract pairs for LU */ s = (f-1)*f*(2*f-1)/6 ; nms_lu += s ; /* number of multiply-subtract pairs for LDL' */ nms_ldl += (s + lnzme)/2 ; /* number of nz's in L (excl. diagonal) */ Info [AMD_LNZ] = lnz ; /* number of divide ops for LU and LDL' */ Info [AMD_NDIV] = ndiv ; /* number of multiply-subtract pairs for LDL' */ Info [AMD_NMULTSUBS_LDL] = nms_ldl ; /* number of multiply-subtract pairs for LU */ Info [AMD_NMULTSUBS_LU] = nms_lu ; /* number of "dense" rows/columns */ Info [AMD_NDENSE] = ndense ; /* largest front is dmax-by-dmax */ Info [AMD_DMAX] = dmax ; /* number of garbage collections in AMD */ Info [AMD_NCMPA] = ncmpa ; /* successful ordering */ Info [AMD_STATUS] = AMD_OK ; } /* ========================================================================= */ /* POST-ORDERING */ /* ========================================================================= */ /* ------------------------------------------------------------------------- * Variables at this point: * * Pe: holds the elimination tree. The parent of j is FLIP (Pe [j]), * or EMPTY if j is a root. The tree holds both elements and * non-principal (unordered) variables absorbed into them. * Dense variables are non-principal and unordered. * * Elen: holds the size of each element, including the diagonal part. * FLIP (Elen [e]) > 0 if e is an element. For unordered * variables i, Elen [i] is EMPTY. * * Nv: Nv [e] > 0 is the number of pivots represented by the element e. * For unordered variables i, Nv [i] is zero. * * Contents no longer needed: * W, Iw, Len, Degree, Head, Next, Last. * * The matrix itself has been destroyed. * * n: the size of the matrix. * No other scalars needed (pfree, iwlen, etc.) * ------------------------------------------------------------------------- */ /* restore Pe */ for (i = 0 ; i < n ; i++) { Pe [i] = FLIP (Pe [i]) ; } /* restore Elen, for output information, and for postordering */ for (i = 0 ; i < n ; i++) { Elen [i] = FLIP (Elen [i]) ; } /* Now the parent of j is Pe [j], or EMPTY if j is a root. Elen [e] > 0 * is the size of element e. Elen [i] is EMPTY for unordered variable i. */ #ifndef NDEBUG AMD_DEBUG2 (("\nTree:\n")) ; for (i = 0 ; i < n ; i++) { AMD_DEBUG2 ((" "ID" parent: "ID" ", i, Pe [i])) ; ASSERT (Pe [i] >= EMPTY && Pe [i] < n) ; if (Nv [i] > 0) { /* this is an element */ e = i ; AMD_DEBUG2 ((" element, size is "ID"\n", Elen [i])) ; ASSERT (Elen [e] > 0) ; } AMD_DEBUG2 (("\n")) ; } AMD_DEBUG2 (("\nelements:\n")) ; for (e = 0 ; e < n ; e++) { if (Nv [e] > 0) { AMD_DEBUG3 (("Element e= "ID" size "ID" nv "ID" \n", e, Elen [e], Nv [e])) ; } } AMD_DEBUG2 (("\nvariables:\n")) ; for (i = 0 ; i < n ; i++) { Int cnt ; if (Nv [i] == 0) { AMD_DEBUG3 (("i unordered: "ID"\n", i)) ; j = Pe [i] ; cnt = 0 ; AMD_DEBUG3 ((" j: "ID"\n", j)) ; if (j == EMPTY) { AMD_DEBUG3 ((" i is a dense variable\n")) ; } else { ASSERT (j >= 0 && j < n) ; while (Nv [j] == 0) { AMD_DEBUG3 ((" j : "ID"\n", j)) ; j = Pe [j] ; AMD_DEBUG3 ((" j:: "ID"\n", j)) ; cnt++ ; if (cnt > n) break ; } e = j ; AMD_DEBUG3 ((" got to e: "ID"\n", e)) ; } } } #endif /* ========================================================================= */ /* compress the paths of the variables */ /* ========================================================================= */ for (i = 0 ; i < n ; i++) { if (Nv [i] == 0) { /* ------------------------------------------------------------- * i is an un-ordered row. Traverse the tree from i until * reaching an element, e. The element, e, was the principal * supervariable of i and all nodes in the path from i to when e * was selected as pivot. * ------------------------------------------------------------- */ AMD_DEBUG1 (("Path compression, i unordered: "ID"\n", i)) ; j = Pe [i] ; ASSERT (j >= EMPTY && j < n) ; AMD_DEBUG3 ((" j: "ID"\n", j)) ; if (j == EMPTY) { /* Skip a dense variable. It has no parent. */ AMD_DEBUG3 ((" i is a dense variable\n")) ; continue ; } /* while (j is a variable) */ while (Nv [j] == 0) { AMD_DEBUG3 ((" j : "ID"\n", j)) ; j = Pe [j] ; AMD_DEBUG3 ((" j:: "ID"\n", j)) ; ASSERT (j >= 0 && j < n) ; } /* got to an element e */ e = j ; AMD_DEBUG3 (("got to e: "ID"\n", e)) ; /* ------------------------------------------------------------- * traverse the path again from i to e, and compress the path * (all nodes point to e). Path compression allows this code to * compute in O(n) time. * ------------------------------------------------------------- */ j = i ; /* while (j is a variable) */ while (Nv [j] == 0) { jnext = Pe [j] ; AMD_DEBUG3 (("j "ID" jnext "ID"\n", j, jnext)) ; Pe [j] = e ; j = jnext ; ASSERT (j >= 0 && j < n) ; } } } /* ========================================================================= */ /* postorder the assembly tree */ /* ========================================================================= */ AMD_postorder (n, Pe, Nv, Elen, W, /* output order */ Head, Next, Last) ; /* workspace */ /* ========================================================================= */ /* compute output permutation and inverse permutation */ /* ========================================================================= */ /* W [e] = k means that element e is the kth element in the new * order. e is in the range 0 to n-1, and k is in the range 0 to * the number of elements. Use Head for inverse order. */ for (k = 0 ; k < n ; k++) { Head [k] = EMPTY ; Next [k] = EMPTY ; } for (e = 0 ; e < n ; e++) { k = W [e] ; ASSERT ((k == EMPTY) == (Nv [e] == 0)) ; if (k != EMPTY) { ASSERT (k >= 0 && k < n) ; Head [k] = e ; } } /* construct output inverse permutation in Next, * and permutation in Last */ nel = 0 ; for (k = 0 ; k < n ; k++) { e = Head [k] ; if (e == EMPTY) break ; ASSERT (e >= 0 && e < n && Nv [e] > 0) ; Next [e] = nel ; nel += Nv [e] ; } ASSERT (nel == n - ndense) ; /* order non-principal variables (dense, & those merged into supervar's) */ for (i = 0 ; i < n ; i++) { if (Nv [i] == 0) { e = Pe [i] ; ASSERT (e >= EMPTY && e < n) ; if (e != EMPTY) { /* This is an unordered variable that was merged * into element e via supernode detection or mass * elimination of i when e became the pivot element. * Place i in order just before e. */ ASSERT (Next [i] == EMPTY && Nv [e] > 0) ; Next [i] = Next [e] ; Next [e]++ ; } else { /* This is a dense unordered variable, with no parent. * Place it last in the output order. */ Next [i] = nel++ ; } } } ASSERT (nel == n) ; AMD_DEBUG2 (("\n\nPerm:\n")) ; for (i = 0 ; i < n ; i++) { k = Next [i] ; ASSERT (k >= 0 && k < n) ; Last [k] = i ; AMD_DEBUG2 ((" perm ["ID"] = "ID"\n", k, i)) ; } } Rglpk/src/GLPK/amd/amd_post_tree.c0000644000176000001440000001070512245352174016447 0ustar ripleyusers/* ========================================================================= */ /* === AMD_post_tree ======================================================= */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* Post-ordering of a supernodal elimination tree. */ #include "amd_internal.h" GLOBAL Int AMD_post_tree ( Int root, /* root of the tree */ Int k, /* start numbering at k */ Int Child [ ], /* input argument of size nn, undefined on * output. Child [i] is the head of a link * list of all nodes that are children of node * i in the tree. */ const Int Sibling [ ], /* input argument of size nn, not modified. * If f is a node in the link list of the * children of node i, then Sibling [f] is the * next child of node i. */ Int Order [ ], /* output order, of size nn. Order [i] = k * if node i is the kth node of the reordered * tree. */ Int Stack [ ] /* workspace of size nn */ #ifndef NDEBUG , Int nn /* nodes are in the range 0..nn-1. */ #endif ) { Int f, head, h, i ; #if 0 /* --------------------------------------------------------------------- */ /* recursive version (Stack [ ] is not used): */ /* --------------------------------------------------------------------- */ /* this is simple, but can caouse stack overflow if nn is large */ i = root ; for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) { k = AMD_post_tree (f, k, Child, Sibling, Order, Stack, nn) ; } Order [i] = k++ ; return (k) ; #endif /* --------------------------------------------------------------------- */ /* non-recursive version, using an explicit stack */ /* --------------------------------------------------------------------- */ /* push root on the stack */ head = 0 ; Stack [0] = root ; while (head >= 0) { /* get head of stack */ ASSERT (head < nn) ; i = Stack [head] ; AMD_DEBUG1 (("head of stack "ID" \n", i)) ; ASSERT (i >= 0 && i < nn) ; if (Child [i] != EMPTY) { /* the children of i are not yet ordered */ /* push each child onto the stack in reverse order */ /* so that small ones at the head of the list get popped first */ /* and the biggest one at the end of the list gets popped last */ for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) { head++ ; ASSERT (head < nn) ; ASSERT (f >= 0 && f < nn) ; } h = head ; ASSERT (head < nn) ; for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) { ASSERT (h > 0) ; Stack [h--] = f ; AMD_DEBUG1 (("push "ID" on stack\n", f)) ; ASSERT (f >= 0 && f < nn) ; } ASSERT (Stack [h] == i) ; /* delete child list so that i gets ordered next time we see it */ Child [i] = EMPTY ; } else { /* the children of i (if there were any) are already ordered */ /* remove i from the stack and order it. Front i is kth front */ head-- ; AMD_DEBUG1 (("pop "ID" order "ID"\n", i, k)) ; Order [i] = k++ ; ASSERT (k <= nn) ; } #ifndef NDEBUG AMD_DEBUG1 (("\nStack:")) ; for (h = head ; h >= 0 ; h--) { Int j = Stack [h] ; AMD_DEBUG1 ((" "ID, j)) ; ASSERT (j >= 0 && j < nn) ; } AMD_DEBUG1 (("\n\n")) ; ASSERT (head < nn) ; #endif } return (k) ; } Rglpk/src/GLPK/bignum.h0000644000176000001440000000261212245352174014345 0ustar ripleyusers/* bignum.h (arbitrary precision arithmetic) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2006, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef BIGNUM_H #define BIGNUM_H #define bigmul _glp_bigmul void bigmul(int n, int m, unsigned short x[], unsigned short y[]); /* multiply unsigned integer numbers of arbitrary precision */ #define bigdiv _glp_bigdiv void bigdiv(int n, int m, unsigned short x[], unsigned short y[]); /* divide unsigned integer numbers of arbitrary precision */ #endif /* eof */ Rglpk/src/GLPK/glpapi21.c0000644000176000001440000015016612245352174014506 0ustar ripleyusers/* glpapi21.c (stand-alone LP/MIP solver) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpapi.h" #include "glpgmp.h" #include "glplib.h" struct csa { /* common storage area */ glp_prob *prob; /* LP/MIP problem object */ glp_bfcp bfcp; /* basis factorization control parameters */ glp_smcp smcp; /* simplex method control parameters */ glp_iptcp iptcp; /* interior-point method control parameters */ glp_iocp iocp; /* integer optimizer control parameters */ glp_tran *tran; /* model translator workspace */ glp_graph *graph; /* network problem object */ int format; /* problem file format: */ #define FMT_MPS_DECK 1 /* fixed MPS */ #define FMT_MPS_FILE 2 /* free MPS */ #define FMT_LP 3 /* CPLEX LP */ #define FMT_GLP 4 /* GLPK LP/MIP */ #define FMT_MATHPROG 5 /* MathProg */ #define FMT_MIN_COST 6 /* DIMACS min-cost flow */ #define FMT_MAX_FLOW 7 /* DIMACS maximum flow */ #if 1 /* 06/VIII-2011 */ #define FMT_CNF 8 /* DIMACS CNF-SAT */ #endif const char *in_file; /* name of input problem file */ #define DATA_MAX 10 /* maximal number of input data files */ int ndf; /* number of input data files specified */ const char *in_data[1+DATA_MAX]; /* name(s) of input data file(s) */ const char *out_dpy; /* name of output file to send display output; NULL means the display output is sent to the terminal */ int seed; /* seed value to be passed to the MathProg translator; initially set to 1; 0x80000000 means the value is omitted */ int solution; /* solution type flag: */ #define SOL_BASIC 1 /* basic */ #define SOL_INTERIOR 2 /* interior-point */ #define SOL_INTEGER 3 /* mixed integer */ const char *in_res; /* name of input solution file in raw format */ int dir; /* optimization direction flag: 0 - not specified GLP_MIN - minimization GLP_MAX - maximization */ int scale; /* automatic problem scaling flag */ const char *out_sol; /* name of output solution file in printable format */ const char *out_res; /* name of output solution file in raw format */ const char *out_ranges; /* name of output file to write sensitivity analysis report */ int check; /* input data checking flag; no solution is performed */ const char *new_name; /* new name to be assigned to the problem */ const char *out_mps; /* name of output problem file in fixed MPS format */ const char *out_freemps; /* name of output problem file in free MPS format */ const char *out_cpxlp; /* name of output problem file in CPLEX LP format */ const char *out_glp; /* name of output problem file in GLPK format */ const char *out_pb; /* name of output problem file in OPB format */ const char *out_npb; /* name of output problem file in normalized OPB format */ #if 1 /* 06/VIII-2011 */ const char *out_cnf; /* name of output problem file in DIMACS CNF-SAT format */ #endif const char *log_file; /* name of output file to hardcopy terminal output */ int crash; /* initial basis option: */ #define USE_STD_BASIS 1 /* use standard basis */ #define USE_ADV_BASIS 2 /* use advanced basis */ #define USE_CPX_BASIS 3 /* use Bixby's basis */ #define USE_INI_BASIS 4 /* use initial basis from ini_file */ const char *ini_file; /* name of input file containing initial basis */ int exact; /* flag to use glp_exact rather than glp_simplex */ int xcheck; /* flag to check final basis with glp_exact */ int nomip; /* flag to consider MIP as pure LP */ #if 1 /* 15/VIII-2011 */ int minisat; /* option to solve feasibility problem with MiniSat solver */ int use_bnd; /* option to bound objective function */ int obj_bnd; /* upper (minization) or lower (maximization) objective bound */ #endif #if 1 /* 11/VII-2013 */ const char *use_sol; /* name of input mip solution file in GLPK format */ #endif }; static void print_help(const char *my_name) { /* print help information */ xprintf("Usage: %s [options...] filename\n", my_name); xprintf("\n"); xprintf("General options:\n"); xprintf(" --mps read LP/MIP problem in fixed MPS fo" "rmat\n"); xprintf(" --freemps read LP/MIP problem in free MPS for" "mat (default)\n"); xprintf(" --lp read LP/MIP problem in CPLEX LP for" "mat\n"); xprintf(" --glp read LP/MIP problem in GLPK format " "\n"); xprintf(" --math read LP/MIP model written in GNU Ma" "thProg modeling\n"); xprintf(" language\n"); xprintf(" -m filename, --model filename\n"); xprintf(" read model section and optional dat" "a section from\n"); xprintf(" filename (same as --math)\n"); xprintf(" -d filename, --data filename\n"); xprintf(" read data section from filename (fo" "r --math only);\n"); xprintf(" if model file also has data section" ", it is ignored\n"); xprintf(" -y filename, --display filename\n"); xprintf(" send display output to filename (fo" "r --math only);\n"); xprintf(" by default the output is sent to te" "rminal\n"); xprintf(" --seed value initialize pseudo-random number gen" "erator used in\n"); xprintf(" MathProg model with specified seed " "(any integer);\n"); xprintf(" if seed value is ?, some random see" "d will be used\n"); xprintf(" --mincost read min-cost flow problem in DIMAC" "S format\n"); xprintf(" --maxflow read maximum flow problem in DIMACS" " format\n"); #if 1 /* 06/VIII-2011 */ xprintf(" --cnf read CNF-SAT problem in DIMACS form" "at\n"); #endif xprintf(" --simplex use simplex method (default)\n"); xprintf(" --interior use interior point method (LP only)" "\n"); xprintf(" -r filename, --read filename\n"); xprintf(" read solution from filename rather " "to find it with\n"); xprintf(" the solver\n"); xprintf(" --min minimization\n"); xprintf(" --max maximization\n"); xprintf(" --scale scale problem (default)\n"); xprintf(" --noscale do not scale problem\n"); xprintf(" -o filename, --output filename\n"); xprintf(" write solution to filename in print" "able format\n"); xprintf(" -w filename, --write filename\n"); xprintf(" write solution to filename in plain" " text format\n"); xprintf(" --ranges filename\n"); xprintf(" write sensitivity analysis report t" "o filename in\n"); xprintf(" printable format (simplex only)\n"); xprintf(" --tmlim nnn limit solution time to nnn seconds " "\n"); xprintf(" --memlim nnn limit available memory to nnn megab" "ytes\n"); xprintf(" --check do not solve problem, check input d" "ata only\n"); xprintf(" --name probname change problem name to probname\n"); xprintf(" --wmps filename write problem to filename in fixed " "MPS format\n"); xprintf(" --wfreemps filename\n"); xprintf(" write problem to filename in free M" "PS format\n"); xprintf(" --wlp filename write problem to filename in CPLEX " "LP format\n"); xprintf(" --wglp filename write problem to filename in GLPK f" "ormat\n"); #if 0 xprintf(" --wpb filename write problem to filename in OPB fo" "rmat\n"); xprintf(" --wnpb filename write problem to filename in normal" "ized OPB format\n"); #endif #if 1 /* 06/VIII-2011 */ xprintf(" --wcnf filename write problem to filename in DIMACS" " CNF-SAT format\n"); #endif xprintf(" --log filename write copy of terminal output to fi" "lename\n"); xprintf(" -h, --help display this help information and e" "xit\n"); xprintf(" -v, --version display program version and exit\n") ; xprintf("\n"); xprintf("LP basis factorization options:\n"); xprintf(" --luf LU + Forrest-Tomlin update\n"); xprintf(" (faster, less stable; default)\n"); xprintf(" --cbg LU + Schur complement + Bartels-Gol" "ub update\n"); xprintf(" (slower, more stable)\n"); xprintf(" --cgr LU + Schur complement + Givens rota" "tion update\n"); xprintf(" (slower, more stable)\n"); xprintf("\n"); xprintf("Options specific to simplex solver:\n"); xprintf(" --primal use primal simplex (default)\n"); xprintf(" --dual use dual simplex\n"); xprintf(" --std use standard initial basis of all s" "lacks\n"); xprintf(" --adv use advanced initial basis (default" ")\n"); xprintf(" --bib use Bixby's initial basis\n"); xprintf(" --ini filename use as initial basis previously sav" "ed with -w\n"); xprintf(" (disables LP presolver)\n"); xprintf(" --steep use steepest edge technique (defaul" "t)\n"); xprintf(" --nosteep use standard \"textbook\" pricing\n" ); xprintf(" --relax use Harris' two-pass ratio test (de" "fault)\n"); xprintf(" --norelax use standard \"textbook\" ratio tes" "t\n"); xprintf(" --presol use presolver (default; assumes --s" "cale and --adv)\n"); xprintf(" --nopresol do not use presolver\n"); xprintf(" --exact use simplex method based on exact a" "rithmetic\n"); xprintf(" --xcheck check final basis using exact arith" "metic\n"); xprintf("\n"); xprintf("Options specific to interior-point solver:\n"); xprintf(" --nord use natural (original) ordering\n"); xprintf(" --qmd use quotient minimum degree orderin" "g\n"); xprintf(" --amd use approximate minimum degree orde" "ring (default)\n"); xprintf(" --symamd use approximate minimum degree orde" "ring\n"); xprintf("\n"); xprintf("Options specific to MIP solver:\n"); xprintf(" --nomip consider all integer variables as c" "ontinuous\n"); xprintf(" (allows solving MIP as pure LP)\n"); xprintf(" --first branch on first integer variable\n") ; xprintf(" --last branch on last integer variable\n"); xprintf(" --mostf branch on most fractional variable " "\n"); xprintf(" --drtom branch using heuristic by Driebeck " "and Tomlin\n"); xprintf(" (default)\n"); xprintf(" --pcost branch using hybrid pseudocost heur" "istic (may be\n"); xprintf(" useful for hard instances)\n"); xprintf(" --dfs backtrack using depth first search " "\n"); xprintf(" --bfs backtrack using breadth first searc" "h\n"); xprintf(" --bestp backtrack using the best projection" " heuristic\n"); xprintf(" --bestb backtrack using node with best loca" "l bound\n"); xprintf(" (default)\n"); xprintf(" --intopt use MIP presolver (default)\n"); xprintf(" --nointopt do not use MIP presolver\n"); xprintf(" --binarize replace general integer variables b" "y binary ones\n"); xprintf(" (assumes --intopt)\n"); xprintf(" --fpump apply feasibility pump heuristic\n") ; #if 1 /* 29/VI-2013 */ xprintf(" --proxy [nnn] apply proximity search heuristic (n" "nn is time limit\n"); xprintf(" in seconds; default is 60)\n"); #endif xprintf(" --gomory generate Gomory's mixed integer cut" "s\n"); xprintf(" --mir generate MIR (mixed integer roundin" "g) cuts\n"); xprintf(" --cover generate mixed cover cuts\n"); xprintf(" --clique generate clique cuts\n"); xprintf(" --cuts generate all cuts above\n"); xprintf(" --mipgap tol set relative mip gap tolerance to t" "ol\n"); #if 1 /* 15/VIII-2011 */ xprintf(" --minisat translate integer feasibility probl" "em to CNF-SAT\n"); xprintf(" and solve it with MiniSat solver\n") ; xprintf(" --objbnd bound add inequality obj <= bound (minimi" "zation) or\n"); xprintf(" obj >= bound (maximization) to inte" "ger feasibility\n"); xprintf(" problem (assumes --minisat)\n"); #endif xprintf("\n"); xprintf("For description of the MPS and CPLEX LP formats see Refe" "rence Manual.\n"); xprintf("For description of the modeling language see \"GLPK: Mod" "eling Language\n"); xprintf("GNU MathProg\". Both documents are included in the GLPK " "distribution.\n"); xprintf("\n"); xprintf("See GLPK web page at .\n"); xprintf("\n"); xprintf("Please report bugs to .\n"); return; } static void print_version(int briefly) { /* print version information */ xprintf("GLPSOL: GLPK LP/MIP Solver, v%s\n", glp_version()); if (briefly) goto done; xprintf("\n"); xprintf("Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, " "2007, 2008,\n"); xprintf("2009, 2010, 2011, 2013 Andrew Makhorin, Department for A" "pplied\n"); xprintf("Informatics, Moscow Aviation Institute, Moscow, Russia. " "All rights\n"); xprintf("reserved. E-mail: .\n"); xprintf("\n"); xprintf("This program has ABSOLUTELY NO WARRANTY.\n"); xprintf("\n"); xprintf("This program is free software; you may re-distribute it " "under the terms\n"); xprintf("of the GNU General Public License version 3 or later.\n") ; done: return; } static int parse_cmdline(struct csa *csa, int argc, const char *argv[]) { /* parse command-line parameters */ int k; #define p(str) (strcmp(argv[k], str) == 0) for (k = 1; k < argc; k++) { if (p("--mps")) csa->format = FMT_MPS_DECK; else if (p("--freemps")) csa->format = FMT_MPS_FILE; else if (p("--lp") || p("--cpxlp")) csa->format = FMT_LP; else if (p("--glp")) csa->format = FMT_GLP; else if (p("--math") || p("-m") || p("--model")) csa->format = FMT_MATHPROG; else if (p("-d") || p("--data")) { k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No input data file specified\n"); return 1; } if (csa->ndf == DATA_MAX) { xprintf("Too many input data files\n"); return 1; } csa->in_data[++(csa->ndf)] = argv[k]; } else if (p("-y") || p("--display")) { k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No display output file specified\n"); return 1; } if (csa->out_dpy != NULL) { xprintf("Only one display output file allowed\n"); return 1; } csa->out_dpy = argv[k]; } else if (p("--seed")) { k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-' && !isdigit((unsigned char)argv[k][1])) { xprintf("No seed value specified\n"); return 1; } if (strcmp(argv[k], "?") == 0) csa->seed = 0x80000000; else if (str2int(argv[k], &csa->seed)) { xprintf("Invalid seed value '%s'\n", argv[k]); return 1; } } else if (p("--mincost")) csa->format = FMT_MIN_COST; else if (p("--maxflow")) csa->format = FMT_MAX_FLOW; #if 1 /* 06/VIII-2011 */ else if (p("--cnf")) csa->format = FMT_CNF; #endif else if (p("--simplex")) csa->solution = SOL_BASIC; else if (p("--interior")) csa->solution = SOL_INTERIOR; #if 1 /* 28/V-2010 */ else if (p("--alien")) csa->iocp.alien = GLP_ON; #endif else if (p("-r") || p("--read")) { k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No input solution file specified\n"); return 1; } if (csa->in_res != NULL) { xprintf("Only one input solution file allowed\n"); return 1; } csa->in_res = argv[k]; } else if (p("--min")) csa->dir = GLP_MIN; else if (p("--max")) csa->dir = GLP_MAX; else if (p("--scale")) csa->scale = 1; else if (p("--noscale")) csa->scale = 0; else if (p("-o") || p("--output")) { k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No output solution file specified\n"); return 1; } if (csa->out_sol != NULL) { xprintf("Only one output solution file allowed\n"); return 1; } csa->out_sol = argv[k]; } else if (p("-w") || p("--write")) { k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No output solution file specified\n"); return 1; } if (csa->out_res != NULL) { xprintf("Only one output solution file allowed\n"); return 1; } csa->out_res = argv[k]; } else if (p("--ranges") || p("--bounds")) { k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No output file specified to write sensitivity a" "nalysis report\n"); return 1; } if (csa->out_ranges != NULL) { xprintf("Only one output file allowed to write sensitivi" "ty analysis report\n"); return 1; } csa->out_ranges = argv[k]; } else if (p("--tmlim")) { int tm_lim; k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No time limit specified\n"); return 1; } if (str2int(argv[k], &tm_lim) || tm_lim < 0) { xprintf("Invalid time limit '%s'\n", argv[k]); return 1; } if (tm_lim <= INT_MAX / 1000) csa->smcp.tm_lim = csa->iocp.tm_lim = 1000 * tm_lim; else csa->smcp.tm_lim = csa->iocp.tm_lim = INT_MAX; } else if (p("--memlim")) { int mem_lim; k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No memory limit specified\n"); return 1; } if (str2int(argv[k], &mem_lim) || mem_lim < 1) { xprintf("Invalid memory limit '%s'\n", argv[k]); return 1; } glp_mem_limit(mem_lim); } else if (p("--check")) csa->check = 1; else if (p("--name")) { k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No problem name specified\n"); return 1; } if (csa->new_name != NULL) { xprintf("Only one problem name allowed\n"); return 1; } csa->new_name = argv[k]; } else if (p("--wmps")) { k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No fixed MPS output file specified\n"); return 1; } if (csa->out_mps != NULL) { xprintf("Only one fixed MPS output file allowed\n"); return 1; } csa->out_mps = argv[k]; } else if (p("--wfreemps")) { k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No free MPS output file specified\n"); return 1; } if (csa->out_freemps != NULL) { xprintf("Only one free MPS output file allowed\n"); return 1; } csa->out_freemps = argv[k]; } else if (p("--wlp") || p("--wcpxlp") || p("--wlpt")) { k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No CPLEX LP output file specified\n"); return 1; } if (csa->out_cpxlp != NULL) { xprintf("Only one CPLEX LP output file allowed\n"); return 1; } csa->out_cpxlp = argv[k]; } else if (p("--wglp")) { k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No GLPK LP/MIP output file specified\n"); return 1; } if (csa->out_glp != NULL) { xprintf("Only one GLPK LP/MIP output file allowed\n"); return 1; } csa->out_glp = argv[k]; } else if (p("--wpb")) { k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No problem output file specified\n"); return 1; } if (csa->out_pb != NULL) { xprintf("Only one OPB output file allowed\n"); return 1; } csa->out_pb = argv[k]; } else if (p("--wnpb")) { k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No problem output file specified\n"); return 1; } if (csa->out_npb != NULL) { xprintf("Only one normalized OPB output file allowed\n"); return 1; } csa->out_npb = argv[k]; } #if 1 /* 06/VIII-2011 */ else if (p("--wcnf")) { k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No problem output file specified\n"); return 1; } if (csa->out_cnf != NULL) { xprintf("Only one output DIMACS CNF-SAT file allowed\n"); return 1; } csa->out_cnf = argv[k]; } #endif else if (p("--log")) { k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No log file specified\n"); return 1; } if (csa->log_file != NULL) { xprintf("Only one log file allowed\n"); return 1; } csa->log_file = argv[k]; } else if (p("-h") || p("--help")) { print_help(argv[0]); return -1; } else if (p("-v") || p("--version")) { print_version(0); return -1; } else if (p("--luf")) csa->bfcp.type = GLP_BF_FT; else if (p("--cbg")) csa->bfcp.type = GLP_BF_BG; else if (p("--cgr")) csa->bfcp.type = GLP_BF_GR; else if (p("--primal")) csa->smcp.meth = GLP_PRIMAL; else if (p("--dual")) csa->smcp.meth = GLP_DUAL; else if (p("--std")) csa->crash = USE_STD_BASIS; else if (p("--adv")) csa->crash = USE_ADV_BASIS; else if (p("--bib")) csa->crash = USE_CPX_BASIS; else if (p("--ini")) { csa->crash = USE_INI_BASIS; csa->smcp.presolve = GLP_OFF; k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No initial basis file specified\n"); return 1; } if (csa->ini_file != NULL) { xprintf("Only one initial basis file allowed\n"); return 1; } csa->ini_file = argv[k]; } else if (p("--steep")) csa->smcp.pricing = GLP_PT_PSE; else if (p("--nosteep")) csa->smcp.pricing = GLP_PT_STD; else if (p("--relax")) csa->smcp.r_test = GLP_RT_HAR; else if (p("--norelax")) csa->smcp.r_test = GLP_RT_STD; else if (p("--presol")) csa->smcp.presolve = GLP_ON; else if (p("--nopresol")) csa->smcp.presolve = GLP_OFF; else if (p("--exact")) csa->exact = 1; else if (p("--xcheck")) csa->xcheck = 1; else if (p("--nord")) csa->iptcp.ord_alg = GLP_ORD_NONE; else if (p("--qmd")) csa->iptcp.ord_alg = GLP_ORD_QMD; else if (p("--amd")) csa->iptcp.ord_alg = GLP_ORD_AMD; else if (p("--symamd")) csa->iptcp.ord_alg = GLP_ORD_SYMAMD; else if (p("--nomip")) csa->nomip = 1; else if (p("--first")) csa->iocp.br_tech = GLP_BR_FFV; else if (p("--last")) csa->iocp.br_tech = GLP_BR_LFV; else if (p("--drtom")) csa->iocp.br_tech = GLP_BR_DTH; else if (p("--mostf")) csa->iocp.br_tech = GLP_BR_MFV; else if (p("--pcost")) csa->iocp.br_tech = GLP_BR_PCH; else if (p("--dfs")) csa->iocp.bt_tech = GLP_BT_DFS; else if (p("--bfs")) csa->iocp.bt_tech = GLP_BT_BFS; else if (p("--bestp")) csa->iocp.bt_tech = GLP_BT_BPH; else if (p("--bestb")) csa->iocp.bt_tech = GLP_BT_BLB; else if (p("--intopt")) csa->iocp.presolve = GLP_ON; else if (p("--nointopt")) csa->iocp.presolve = GLP_OFF; else if (p("--binarize")) csa->iocp.presolve = csa->iocp.binarize = GLP_ON; else if (p("--fpump")) csa->iocp.fp_heur = GLP_ON; #if 1 /* 29/VI-2013 */ else if (p("--proxy")) { csa->iocp.ps_heur = GLP_ON; if (argv[k+1] && isdigit((unsigned char)argv[k+1][0])) { int nnn; k++; if (str2int(argv[k], &nnn) || nnn < 1) { xprintf("Invalid proxy time limit '%s'\n", argv[k]); return 1; } csa->iocp.ps_tm_lim = 1000 * nnn; } } #endif else if (p("--gomory")) csa->iocp.gmi_cuts = GLP_ON; else if (p("--mir")) csa->iocp.mir_cuts = GLP_ON; else if (p("--cover")) csa->iocp.cov_cuts = GLP_ON; else if (p("--clique")) csa->iocp.clq_cuts = GLP_ON; else if (p("--cuts")) csa->iocp.gmi_cuts = csa->iocp.mir_cuts = csa->iocp.cov_cuts = csa->iocp.clq_cuts = GLP_ON; else if (p("--mipgap")) { double mip_gap; k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No relative gap tolerance specified\n"); return 1; } if (str2num(argv[k], &mip_gap) || mip_gap < 0.0) { xprintf("Invalid relative mip gap tolerance '%s'\n", argv[k]); return 1; } csa->iocp.mip_gap = mip_gap; } #if 1 /* 15/VIII-2011 */ else if (p("--minisat")) csa->minisat = 1; else if (p("--objbnd")) { k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-' && !isdigit((unsigned char)argv[k][1])) { xprintf("No objective bound specified\n"); return 1; } csa->minisat = 1; csa->use_bnd = 1; if (str2int(argv[k], &csa->obj_bnd)) { xprintf("Invalid objective bound '%s' (should be integer" " value)\n", argv[k]); return 1; } } #endif #if 1 /* 11/VII-2013 */ else if (p("--use")) { k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No input MIP solution file specified\n"); return 1; } if (csa->use_sol != NULL) { xprintf("Only one input MIP solution file allowed\n"); return 1; } csa->use_sol = argv[k]; } else if (p("--save")) { k++; if (k == argc || argv[k][0] == '\0' || argv[k][0] == '-') { xprintf("No output MIP solution file specified\n"); return 1; } if (csa->iocp.save_sol != NULL) { xprintf("Only one output MIP solution file allowed\n"); return 1; } csa->iocp.save_sol = argv[k]; } #endif else if (argv[k][0] == '-' || (argv[k][0] == '-' && argv[k][1] == '-')) { xprintf("Invalid option '%s'; try %s --help\n", argv[k], argv[0]); return 1; } else { if (csa->in_file != NULL) { xprintf("Only one input problem file allowed\n"); return 1; } csa->in_file = argv[k]; } } #undef p return 0; } typedef struct { double rhs, pi; } v_data; typedef struct { double low, cap, cost, x; } a_data; int glp_main(int argc, const char *argv[]) { /* stand-alone LP/MIP solver */ struct csa _csa, *csa = &_csa; int ret; #if 0 /* 10/VI-2013 */ glp_long start; #else double start; #endif /* perform initialization */ csa->prob = glp_create_prob(); glp_get_bfcp(csa->prob, &csa->bfcp); glp_init_smcp(&csa->smcp); csa->smcp.presolve = GLP_ON; glp_init_iptcp(&csa->iptcp); glp_init_iocp(&csa->iocp); csa->iocp.presolve = GLP_ON; csa->tran = NULL; csa->graph = NULL; csa->format = FMT_MPS_FILE; csa->in_file = NULL; csa->ndf = 0; csa->out_dpy = NULL; csa->seed = 1; csa->solution = SOL_BASIC; csa->in_res = NULL; csa->dir = 0; csa->scale = 1; csa->out_sol = NULL; csa->out_res = NULL; csa->out_ranges = NULL; csa->check = 0; csa->new_name = NULL; csa->out_mps = NULL; csa->out_freemps = NULL; csa->out_cpxlp = NULL; csa->out_glp = NULL; csa->out_pb = NULL; csa->out_npb = NULL; #if 1 /* 06/VIII-2011 */ csa->out_cnf = NULL; #endif csa->log_file = NULL; csa->crash = USE_ADV_BASIS; csa->ini_file = NULL; csa->exact = 0; csa->xcheck = 0; csa->nomip = 0; #if 1 /* 15/VIII-2011 */ csa->minisat = 0; csa->use_bnd = 0; csa->obj_bnd = 0; #endif #if 1 /* 11/VII-2013 */ csa->use_sol = NULL; #endif /* parse command-line parameters */ ret = parse_cmdline(csa, argc, argv); if (ret < 0) { ret = EXIT_SUCCESS; goto done; } if (ret > 0) { ret = EXIT_FAILURE; goto done; } /*--------------------------------------------------------------*/ /* remove all output files specified in the command line */ if (csa->out_dpy != NULL) remove(csa->out_dpy); if (csa->out_sol != NULL) remove(csa->out_sol); if (csa->out_res != NULL) remove(csa->out_res); if (csa->out_ranges != NULL) remove(csa->out_ranges); if (csa->out_mps != NULL) remove(csa->out_mps); if (csa->out_freemps != NULL) remove(csa->out_freemps); if (csa->out_cpxlp != NULL) remove(csa->out_cpxlp); if (csa->out_glp != NULL) remove(csa->out_glp); if (csa->out_pb != NULL) remove(csa->out_pb); if (csa->out_npb != NULL) remove(csa->out_npb); #if 1 /* 06/VIII-2011 */ if (csa->out_cnf != NULL) remove(csa->out_cnf); #endif if (csa->log_file != NULL) remove(csa->log_file); /*--------------------------------------------------------------*/ /* open log file, if required */ if (csa->log_file != NULL) { if (glp_open_tee(csa->log_file)) { xprintf("Unable to create log file\n"); ret = EXIT_FAILURE; goto done; } } /*--------------------------------------------------------------*/ /* print version information */ print_version(1); /*--------------------------------------------------------------*/ /* print parameters specified in the command line */ if (argc > 1) { int k, len = INT_MAX; xprintf("Parameter(s) specified in the command line:"); for (k = 1; k < argc; k++) { if (len > 72) xprintf("\n"), len = 0; xprintf(" %s", argv[k]); len += 1 + strlen(argv[k]); } xprintf("\n"); } /*--------------------------------------------------------------*/ /* read problem data from the input file */ if (csa->in_file == NULL) { xprintf("No input problem file specified; try %s --help\n", argv[0]); ret = EXIT_FAILURE; goto done; } if (csa->format == FMT_MPS_DECK) { ret = glp_read_mps(csa->prob, GLP_MPS_DECK, NULL, csa->in_file); if (ret != 0) err1: { xprintf("MPS file processing error\n"); ret = EXIT_FAILURE; goto done; } } else if (csa->format == FMT_MPS_FILE) { ret = glp_read_mps(csa->prob, GLP_MPS_FILE, NULL, csa->in_file); if (ret != 0) goto err1; } else if (csa->format == FMT_LP) { ret = glp_read_lp(csa->prob, NULL, csa->in_file); if (ret != 0) { xprintf("CPLEX LP file processing error\n"); ret = EXIT_FAILURE; goto done; } } else if (csa->format == FMT_GLP) { ret = glp_read_prob(csa->prob, 0, csa->in_file); if (ret != 0) { xprintf("GLPK LP/MIP file processing error\n"); ret = EXIT_FAILURE; goto done; } } else if (csa->format == FMT_MATHPROG) { int k; /* allocate the translator workspace */ csa->tran = glp_mpl_alloc_wksp(); /* set seed value */ if (csa->seed == 0x80000000) #if 0 /* 10/VI-2013 */ { csa->seed = glp_time().lo; #else { csa->seed = (int)fmod(glp_time(), 1000000000.0); #endif xprintf("Seed value %d will be used\n", csa->seed); } _glp_mpl_init_rand(csa->tran, csa->seed); /* read model section and optional data section */ if (glp_mpl_read_model(csa->tran, csa->in_file, csa->ndf > 0)) err2: { xprintf("MathProg model processing error\n"); ret = EXIT_FAILURE; goto done; } /* read optional data section(s), if necessary */ for (k = 1; k <= csa->ndf; k++) { if (glp_mpl_read_data(csa->tran, csa->in_data[k])) goto err2; } /* generate the model */ if (glp_mpl_generate(csa->tran, csa->out_dpy)) goto err2; /* build the problem instance from the model */ glp_mpl_build_prob(csa->tran, csa->prob); } else if (csa->format == FMT_MIN_COST) { csa->graph = glp_create_graph(sizeof(v_data), sizeof(a_data)); ret = glp_read_mincost(csa->graph, offsetof(v_data, rhs), offsetof(a_data, low), offsetof(a_data, cap), offsetof(a_data, cost), csa->in_file); if (ret != 0) { xprintf("DIMACS file processing error\n"); ret = EXIT_FAILURE; goto done; } glp_mincost_lp(csa->prob, csa->graph, GLP_ON, offsetof(v_data, rhs), offsetof(a_data, low), offsetof(a_data, cap), offsetof(a_data, cost)); glp_set_prob_name(csa->prob, csa->in_file); } else if (csa->format == FMT_MAX_FLOW) { int s, t; csa->graph = glp_create_graph(sizeof(v_data), sizeof(a_data)); ret = glp_read_maxflow(csa->graph, &s, &t, offsetof(a_data, cap), csa->in_file); if (ret != 0) { xprintf("DIMACS file processing error\n"); ret = EXIT_FAILURE; goto done; } glp_maxflow_lp(csa->prob, csa->graph, GLP_ON, s, t, offsetof(a_data, cap)); glp_set_prob_name(csa->prob, csa->in_file); } #if 1 /* 06/VIII-2011 */ else if (csa->format == FMT_CNF) { ret = glp_read_cnfsat(csa->prob, csa->in_file); if (ret != 0) { xprintf("DIMACS file processing error\n"); ret = EXIT_FAILURE; goto done; } glp_set_prob_name(csa->prob, csa->in_file); } #endif else xassert(csa != csa); /*--------------------------------------------------------------*/ /* change problem name, if required */ if (csa->new_name != NULL) glp_set_prob_name(csa->prob, csa->new_name); /* change optimization direction, if required */ if (csa->dir != 0) glp_set_obj_dir(csa->prob, csa->dir); /* sort elements of the constraint matrix */ glp_sort_matrix(csa->prob); /*--------------------------------------------------------------*/ /* write problem data in fixed MPS format, if required */ if (csa->out_mps != NULL) { ret = glp_write_mps(csa->prob, GLP_MPS_DECK, NULL, csa->out_mps); if (ret != 0) { xprintf("Unable to write problem in fixed MPS format\n"); ret = EXIT_FAILURE; goto done; } } /* write problem data in free MPS format, if required */ if (csa->out_freemps != NULL) { ret = glp_write_mps(csa->prob, GLP_MPS_FILE, NULL, csa->out_freemps); if (ret != 0) { xprintf("Unable to write problem in free MPS format\n"); ret = EXIT_FAILURE; goto done; } } /* write problem data in CPLEX LP format, if required */ if (csa->out_cpxlp != NULL) { ret = glp_write_lp(csa->prob, NULL, csa->out_cpxlp); if (ret != 0) { xprintf("Unable to write problem in CPLEX LP format\n"); ret = EXIT_FAILURE; goto done; } } /* write problem data in GLPK format, if required */ if (csa->out_glp != NULL) { ret = glp_write_prob(csa->prob, 0, csa->out_glp); if (ret != 0) { xprintf("Unable to write problem in GLPK format\n"); ret = EXIT_FAILURE; goto done; } } /* write problem data in OPB format, if required */ if (csa->out_pb != NULL) { ret = lpx_write_pb(csa->prob, csa->out_pb, 0, 0); if (ret != 0) { xprintf("Unable to write problem in OPB format\n"); ret = EXIT_FAILURE; goto done; } } /* write problem data in normalized OPB format, if required */ if (csa->out_npb != NULL) { ret = lpx_write_pb(csa->prob, csa->out_npb, 1, 1); if (ret != 0) { xprintf( "Unable to write problem in normalized OPB format\n"); ret = EXIT_FAILURE; goto done; } } #if 1 /* 06/VIII-2011 */ /* write problem data in DIMACS CNF-SAT format, if required */ if (csa->out_cnf != NULL) { ret = glp_write_cnfsat(csa->prob, csa->out_cnf); if (ret != 0) { xprintf( "Unable to write problem in DIMACS CNF-SAT format\n"); ret = EXIT_FAILURE; goto done; } } #endif /*--------------------------------------------------------------*/ /* if only problem data check is required, skip computations */ if (csa->check) { ret = EXIT_SUCCESS; goto done; } /*--------------------------------------------------------------*/ /* determine the solution type */ if (!csa->nomip && glp_get_num_int(csa->prob) + glp_get_num_bin(csa->prob) > 0) { if (csa->solution == SOL_INTERIOR) { xprintf("Interior-point method is not able to solve MIP pro" "blem; use --simplex\n"); ret = EXIT_FAILURE; goto done; } csa->solution = SOL_INTEGER; } /*--------------------------------------------------------------*/ /* if solution is provided, read it and skip computations */ if (csa->in_res != NULL) { if (csa->solution == SOL_BASIC) ret = glp_read_sol(csa->prob, csa->in_res); else if (csa->solution == SOL_INTERIOR) ret = glp_read_ipt(csa->prob, csa->in_res); else if (csa->solution == SOL_INTEGER) ret = glp_read_mip(csa->prob, csa->in_res); else xassert(csa != csa); if (ret != 0) { xprintf("Unable to read problem solution\n"); ret = EXIT_FAILURE; goto done; } goto skip; } #if 1 /* 11/VII-2013 */ /*--------------------------------------------------------------*/ /* if initial MIP solution is provided, read it */ if (csa->solution == SOL_INTEGER && csa->use_sol != NULL) { ret = glp_read_mip(csa->prob, csa->use_sol); if (ret != 0) { xprintf("Unable to read initial MIP solution\n"); ret = EXIT_FAILURE; goto done; } csa->iocp.use_sol = GLP_ON; } #endif /*--------------------------------------------------------------*/ /* scale the problem data, if required */ if (csa->scale) { if (csa->solution == SOL_BASIC && !csa->smcp.presolve || csa->solution == SOL_INTERIOR || csa->solution == SOL_INTEGER && !csa->iocp.presolve) glp_scale_prob(csa->prob, GLP_SF_AUTO); } /*--------------------------------------------------------------*/ /* construct starting LP basis */ if (csa->solution == SOL_BASIC && !csa->smcp.presolve || csa->solution == SOL_INTEGER && !csa->iocp.presolve) { if (csa->crash == USE_STD_BASIS) glp_std_basis(csa->prob); else if (csa->crash == USE_ADV_BASIS) glp_adv_basis(csa->prob, 0); else if (csa->crash == USE_CPX_BASIS) glp_cpx_basis(csa->prob); else if (csa->crash == USE_INI_BASIS) { ret = glp_read_sol(csa->prob, csa->ini_file); if (ret != 0) { xprintf("Unable to read initial basis\n"); ret = EXIT_FAILURE; goto done; } } else xassert(csa != csa); } /*--------------------------------------------------------------*/ /* solve the problem */ start = xtime(); if (csa->solution == SOL_BASIC) { if (!csa->exact) { glp_set_bfcp(csa->prob, &csa->bfcp); glp_simplex(csa->prob, &csa->smcp); if (csa->xcheck) { if (csa->smcp.presolve && glp_get_status(csa->prob) != GLP_OPT) xprintf("If you need to check final basis for non-opt" "imal solution, use --nopresol\n"); else glp_exact(csa->prob, &csa->smcp); } if (csa->out_sol != NULL || csa->out_res != NULL) { if (csa->smcp.presolve && glp_get_status(csa->prob) != GLP_OPT) xprintf("If you need actual output for non-optimal solut" "ion, use --nopresol\n"); } } else glp_exact(csa->prob, &csa->smcp); } else if (csa->solution == SOL_INTERIOR) glp_interior(csa->prob, &csa->iptcp); #if 1 /* 15/VIII-2011 */ else if (csa->solution == SOL_INTEGER && csa->minisat) { if (glp_check_cnfsat(csa->prob) == 0) glp_minisat1(csa->prob); else glp_intfeas1(csa->prob, csa->use_bnd, csa->obj_bnd); } #endif else if (csa->solution == SOL_INTEGER) { if (!csa->iocp.presolve) { glp_set_bfcp(csa->prob, &csa->bfcp); glp_simplex(csa->prob, &csa->smcp); } #if 0 csa->iocp.msg_lev = GLP_MSG_DBG; csa->iocp.pp_tech = GLP_PP_NONE; #endif glp_intopt(csa->prob, &csa->iocp); } else xassert(csa != csa); /*--------------------------------------------------------------*/ /* display statistics */ xprintf("Time used: %.1f secs\n", xdifftime(xtime(), start)); #if 0 /* 16/II-2012 */ { glp_long tpeak; char buf[50]; glp_mem_usage(NULL, NULL, NULL, &tpeak); xprintf("Memory used: %.1f Mb (%s bytes)\n", xltod(tpeak) / 1048576.0, xltoa(tpeak, buf)); } #else { size_t tpeak; glp_mem_usage(NULL, NULL, NULL, &tpeak); xprintf("Memory used: %.1f Mb (%.0f bytes)\n", (double)tpeak / 1048576.0, (double)tpeak); } #endif /*--------------------------------------------------------------*/ skip: /* postsolve the model, if necessary */ if (csa->tran != NULL) { if (csa->solution == SOL_BASIC) { if (!(glp_get_status(csa->prob) == GLP_OPT || glp_get_status(csa->prob) == GLP_FEAS)) ret = -1; else ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_SOL); } else if (csa->solution == SOL_INTERIOR) { if (!(glp_ipt_status(csa->prob) == GLP_OPT || glp_ipt_status(csa->prob) == GLP_FEAS)) ret = -1; else ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_IPT); } else if (csa->solution == SOL_INTEGER) { if (!(glp_mip_status(csa->prob) == GLP_OPT || glp_mip_status(csa->prob) == GLP_FEAS)) ret = -1; else ret = glp_mpl_postsolve(csa->tran, csa->prob, GLP_MIP); } else xassert(csa != csa); if (ret > 0) { xprintf("Model postsolving error\n"); ret = EXIT_FAILURE; goto done; } } /*--------------------------------------------------------------*/ /* write problem solution in printable format, if required */ if (csa->out_sol != NULL) { if (csa->solution == SOL_BASIC) ret = lpx_print_sol(csa->prob, csa->out_sol); else if (csa->solution == SOL_INTERIOR) ret = lpx_print_ips(csa->prob, csa->out_sol); else if (csa->solution == SOL_INTEGER) ret = lpx_print_mip(csa->prob, csa->out_sol); else xassert(csa != csa); if (ret != 0) { xprintf("Unable to write problem solution\n"); ret = EXIT_FAILURE; goto done; } } /* write problem solution in printable format, if required */ if (csa->out_res != NULL) { if (csa->solution == SOL_BASIC) ret = glp_write_sol(csa->prob, csa->out_res); else if (csa->solution == SOL_INTERIOR) ret = glp_write_ipt(csa->prob, csa->out_res); else if (csa->solution == SOL_INTEGER) ret = glp_write_mip(csa->prob, csa->out_res); else xassert(csa != csa); if (ret != 0) { xprintf("Unable to write problem solution\n"); ret = EXIT_FAILURE; goto done; } } /* write sensitivity analysis report, if required */ if (csa->out_ranges != NULL) { if (csa->solution == SOL_BASIC) { if (glp_get_status(csa->prob) == GLP_OPT) { if (glp_bf_exists(csa->prob)) ranges: { ret = glp_print_ranges(csa->prob, 0, NULL, 0, csa->out_ranges); if (ret != 0) { xprintf("Unable to write sensitivity analysis repo" "rt\n"); ret = EXIT_FAILURE; goto done; } } else { ret = glp_factorize(csa->prob); if (ret == 0) goto ranges; xprintf("Cannot produce sensitivity analysis report d" "ue to error in basis factorization (glp_factorize" " returned %d); try --nopresol\n", ret); } } else xprintf("Cannot produce sensitivity analysis report for " "non-optimal basic solution\n"); } else xprintf("Cannot produce sensitivity analysis report for int" "erior-point or MIP solution\n"); } /*--------------------------------------------------------------*/ /* all seems to be ok */ ret = EXIT_SUCCESS; /*--------------------------------------------------------------*/ done: /* delete the LP/MIP problem object */ if (csa->prob != NULL) glp_delete_prob(csa->prob); /* free the translator workspace, if necessary */ if (csa->tran != NULL) glp_mpl_free_wksp(csa->tran); /* delete the network problem object, if necessary */ if (csa->graph != NULL) glp_delete_graph(csa->graph); xassert(gmp_pool_count() == 0); gmp_free_mem(); /* close log file, if necessary */ if (csa->log_file != NULL) glp_close_tee(); /* check that no memory blocks are still allocated */ #if 0 /* 16/II-2012 */ { int count; glp_long total; glp_mem_usage(&count, NULL, &total, NULL); if (count != 0) xerror("Error: %d memory block(s) were lost\n", count); xassert(count == 0); xassert(total.lo == 0 && total.hi == 0); } #else { int count; size_t total; glp_mem_usage(&count, NULL, &total, NULL); if (count != 0) xerror("Error: %d memory block(s) were lost\n", count); xassert(total == 0); } #endif /* free the GLPK environment */ glp_free_env(); /* return to the control program */ return ret; } /* eof */ Rglpk/src/GLPK/lufint.h0000644000176000001440000000462112245352174014367 0ustar ripleyusers/* lufint.h (interface to LU-factorization) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef LUFINT_H #define LUFINT_H #include "sgf.h" typedef struct LUFINT LUFINT; struct LUFINT { /* interface to LU-factorization */ int n_max; /* maximal value of n (increased automatically) */ int valid; /* factorization is valid only if this flag is set */ SVA *sva; /* sparse vector area (SVA) */ LUF *luf; /* sparse LU-factorization */ SGF *sgf; /* sparse Gaussian factorizer workspace */ /*--------------------------------------------------------------*/ /* control parameters */ int sva_n_max, sva_size; /* parameters passed to sva_create_area */ int delta_n0, delta_n; /* if n_max = 0, set n_max = n + delta_n0 * if n_max < n, set n_max = n + delta_n */ int sgf_updat; double sgf_piv_tol; int sgf_piv_lim; int sgf_suhl; double sgf_eps_tol; /* factorizer control parameters */ }; #define lufint_create _glp_lufint_create LUFINT *lufint_create(void); /* create interface to LU-factorization */ #define lufint_factorize _glp_lufint_factorize int lufint_factorize(LUFINT *fi, int n, int (*col)(void *info, int j, int ind[], double val[]), void *info); /* compute LU-factorization of specified matrix A */ #define lufint_delete _glp_lufint_delete void lufint_delete(LUFINT *fi); /* delete interface to LU-factorization */ #endif /* eof */ Rglpk/src/GLPK/glpnpp06.c0000644000176000001440000014441312245352174014533 0ustar ripleyusers/* glpnpp06.c (translate feasibility problem to CNF-SAT) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpnpp.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 */ Rglpk/src/GLPK/glpmpl03.c0000644000176000001440000064542312245352174014532 0ustar ripleyusers/* glpmpl03.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #define _GLPSTD_ERRNO #define _GLPSTD_STDIO #include "env.h" #include "glpmpl.h" /**********************************************************************/ /* * * FLOATING-POINT NUMBERS * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- fp_add - floating-point addition. -- -- This routine computes the sum x + y. */ double fp_add(MPL *mpl, double x, double y) { if (x > 0.0 && y > 0.0 && x > + 0.999 * DBL_MAX - y || x < 0.0 && y < 0.0 && x < - 0.999 * DBL_MAX - y) error(mpl, "%.*g + %.*g; floating-point overflow", DBL_DIG, x, DBL_DIG, y); return x + y; } /*---------------------------------------------------------------------- -- fp_sub - floating-point subtraction. -- -- This routine computes the difference x - y. */ double fp_sub(MPL *mpl, double x, double y) { if (x > 0.0 && y < 0.0 && x > + 0.999 * DBL_MAX + y || x < 0.0 && y > 0.0 && x < - 0.999 * DBL_MAX + y) error(mpl, "%.*g - %.*g; floating-point overflow", DBL_DIG, x, DBL_DIG, y); return x - y; } /*---------------------------------------------------------------------- -- fp_less - floating-point non-negative subtraction. -- -- This routine computes the non-negative difference max(0, x - y). */ double fp_less(MPL *mpl, double x, double y) { if (x < y) return 0.0; if (x > 0.0 && y < 0.0 && x > + 0.999 * DBL_MAX + y) error(mpl, "%.*g less %.*g; floating-point overflow", DBL_DIG, x, DBL_DIG, y); return x - y; } /*---------------------------------------------------------------------- -- fp_mul - floating-point multiplication. -- -- This routine computes the product x * y. */ double fp_mul(MPL *mpl, double x, double y) { if (fabs(y) > 1.0 && fabs(x) > (0.999 * DBL_MAX) / fabs(y)) error(mpl, "%.*g * %.*g; floating-point overflow", DBL_DIG, x, DBL_DIG, y); return x * y; } /*---------------------------------------------------------------------- -- fp_div - floating-point division. -- -- This routine computes the quotient x / y. */ double fp_div(MPL *mpl, double x, double y) { if (fabs(y) < DBL_MIN) error(mpl, "%.*g / %.*g; floating-point zero divide", DBL_DIG, x, DBL_DIG, y); if (fabs(y) < 1.0 && fabs(x) > (0.999 * DBL_MAX) * fabs(y)) error(mpl, "%.*g / %.*g; floating-point overflow", DBL_DIG, x, DBL_DIG, y); return x / y; } /*---------------------------------------------------------------------- -- fp_idiv - floating-point quotient of exact division. -- -- This routine computes the quotient of exact division x div y. */ double fp_idiv(MPL *mpl, double x, double y) { if (fabs(y) < DBL_MIN) error(mpl, "%.*g div %.*g; floating-point zero divide", DBL_DIG, x, DBL_DIG, y); if (fabs(y) < 1.0 && fabs(x) > (0.999 * DBL_MAX) * fabs(y)) error(mpl, "%.*g div %.*g; floating-point overflow", DBL_DIG, x, DBL_DIG, y); x /= y; return x > 0.0 ? floor(x) : x < 0.0 ? ceil(x) : 0.0; } /*---------------------------------------------------------------------- -- fp_mod - floating-point remainder of exact division. -- -- This routine computes the remainder of exact division x mod y. -- -- NOTE: By definition x mod y = x - y * floor(x / y). */ double fp_mod(MPL *mpl, double x, double y) { double r; xassert(mpl == mpl); if (x == 0.0) r = 0.0; else if (y == 0.0) r = x; else { r = fmod(fabs(x), fabs(y)); if (r != 0.0) { if (x < 0.0) r = - r; if (x > 0.0 && y < 0.0 || x < 0.0 && y > 0.0) r += y; } } return r; } /*---------------------------------------------------------------------- -- fp_power - floating-point exponentiation (raise to power). -- -- This routine computes the exponentiation x ** y. */ double fp_power(MPL *mpl, double x, double y) { double r; if (x == 0.0 && y <= 0.0 || x < 0.0 && y != floor(y)) error(mpl, "%.*g ** %.*g; result undefined", DBL_DIG, x, DBL_DIG, y); if (x == 0.0) goto eval; if (fabs(x) > 1.0 && y > +1.0 && +log(fabs(x)) > (0.999 * log(DBL_MAX)) / y || fabs(x) < 1.0 && y < -1.0 && +log(fabs(x)) < (0.999 * log(DBL_MAX)) / y) error(mpl, "%.*g ** %.*g; floating-point overflow", DBL_DIG, x, DBL_DIG, y); if (fabs(x) > 1.0 && y < -1.0 && -log(fabs(x)) < (0.999 * log(DBL_MAX)) / y || fabs(x) < 1.0 && y > +1.0 && -log(fabs(x)) > (0.999 * log(DBL_MAX)) / y) r = 0.0; else eval: r = pow(x, y); return r; } /*---------------------------------------------------------------------- -- fp_exp - floating-point base-e exponential. -- -- This routine computes the base-e exponential e ** x. */ double fp_exp(MPL *mpl, double x) { if (x > 0.999 * log(DBL_MAX)) error(mpl, "exp(%.*g); floating-point overflow", DBL_DIG, x); return exp(x); } /*---------------------------------------------------------------------- -- fp_log - floating-point natural logarithm. -- -- This routine computes the natural logarithm log x. */ double fp_log(MPL *mpl, double x) { if (x <= 0.0) error(mpl, "log(%.*g); non-positive argument", DBL_DIG, x); return log(x); } /*---------------------------------------------------------------------- -- fp_log10 - floating-point common (decimal) logarithm. -- -- This routine computes the common (decimal) logarithm lg x. */ double fp_log10(MPL *mpl, double x) { if (x <= 0.0) error(mpl, "log10(%.*g); non-positive argument", DBL_DIG, x); return log10(x); } /*---------------------------------------------------------------------- -- fp_sqrt - floating-point square root. -- -- This routine computes the square root x ** 0.5. */ double fp_sqrt(MPL *mpl, double x) { if (x < 0.0) error(mpl, "sqrt(%.*g); negative argument", DBL_DIG, x); return sqrt(x); } /*---------------------------------------------------------------------- -- fp_sin - floating-point trigonometric sine. -- -- This routine computes the trigonometric sine sin(x). */ double fp_sin(MPL *mpl, double x) { if (!(-1e6 <= x && x <= +1e6)) error(mpl, "sin(%.*g); argument too large", DBL_DIG, x); return sin(x); } /*---------------------------------------------------------------------- -- fp_cos - floating-point trigonometric cosine. -- -- This routine computes the trigonometric cosine cos(x). */ double fp_cos(MPL *mpl, double x) { if (!(-1e6 <= x && x <= +1e6)) error(mpl, "cos(%.*g); argument too large", DBL_DIG, x); return cos(x); } /*---------------------------------------------------------------------- -- fp_atan - floating-point trigonometric arctangent. -- -- This routine computes the trigonometric arctangent atan(x). */ double fp_atan(MPL *mpl, double x) { xassert(mpl == mpl); return atan(x); } /*---------------------------------------------------------------------- -- fp_atan2 - floating-point trigonometric arctangent. -- -- This routine computes the trigonometric arctangent atan(y / x). */ double fp_atan2(MPL *mpl, double y, double x) { xassert(mpl == mpl); return atan2(y, x); } /*---------------------------------------------------------------------- -- fp_round - round floating-point value to n fractional digits. -- -- This routine rounds given floating-point value x to n fractional -- digits with the formula: -- -- round(x, n) = floor(x * 10^n + 0.5) / 10^n. -- -- The parameter n is assumed to be integer. */ double fp_round(MPL *mpl, double x, double n) { double ten_to_n; if (n != floor(n)) error(mpl, "round(%.*g, %.*g); non-integer second argument", DBL_DIG, x, DBL_DIG, n); if (n <= DBL_DIG + 2) { ten_to_n = pow(10.0, n); if (fabs(x) < (0.999 * DBL_MAX) / ten_to_n) { x = floor(x * ten_to_n + 0.5); if (x != 0.0) x /= ten_to_n; } } return x; } /*---------------------------------------------------------------------- -- fp_trunc - truncate floating-point value to n fractional digits. -- -- This routine truncates given floating-point value x to n fractional -- digits with the formula: -- -- ( floor(x * 10^n) / 10^n, if x >= 0 -- trunc(x, n) = < -- ( ceil(x * 10^n) / 10^n, if x < 0 -- -- The parameter n is assumed to be integer. */ double fp_trunc(MPL *mpl, double x, double n) { double ten_to_n; if (n != floor(n)) error(mpl, "trunc(%.*g, %.*g); non-integer second argument", DBL_DIG, x, DBL_DIG, n); if (n <= DBL_DIG + 2) { ten_to_n = pow(10.0, n); if (fabs(x) < (0.999 * DBL_MAX) / ten_to_n) { x = (x >= 0.0 ? floor(x * ten_to_n) : ceil(x * ten_to_n)); if (x != 0.0) x /= ten_to_n; } } return x; } /**********************************************************************/ /* * * PSEUDO-RANDOM NUMBER GENERATORS * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- fp_irand224 - pseudo-random integer in the range [0, 2^24). -- -- This routine returns a next pseudo-random integer (converted to -- floating-point) which is uniformly distributed between 0 and 2^24-1, -- inclusive. */ #define two_to_the_24 0x1000000 double fp_irand224(MPL *mpl) { return (double)rng_unif_rand(mpl->rand, two_to_the_24); } /*---------------------------------------------------------------------- -- fp_uniform01 - pseudo-random number in the range [0, 1). -- -- This routine returns a next pseudo-random number which is uniformly -- distributed in the range [0, 1). */ #define two_to_the_31 ((unsigned int)0x80000000) double fp_uniform01(MPL *mpl) { return (double)rng_next_rand(mpl->rand) / (double)two_to_the_31; } /*---------------------------------------------------------------------- -- fp_uniform - pseudo-random number in the range [a, b). -- -- This routine returns a next pseudo-random number which is uniformly -- distributed in the range [a, b). */ double fp_uniform(MPL *mpl, double a, double b) { double x; if (a >= b) error(mpl, "Uniform(%.*g, %.*g); invalid range", DBL_DIG, a, DBL_DIG, b); x = fp_uniform01(mpl); #if 0 x = a * (1.0 - x) + b * x; #else x = fp_add(mpl, a * (1.0 - x), b * x); #endif return x; } /*---------------------------------------------------------------------- -- fp_normal01 - Gaussian random variate with mu = 0 and sigma = 1. -- -- This routine returns a Gaussian random variate with zero mean and -- unit standard deviation. The polar (Box-Mueller) method is used. -- -- This code is a modified version of the routine gsl_ran_gaussian from -- the GNU Scientific Library Version 1.0. */ double fp_normal01(MPL *mpl) { double x, y, r2; do { /* choose x, y in uniform square (-1,-1) to (+1,+1) */ x = -1.0 + 2.0 * fp_uniform01(mpl); y = -1.0 + 2.0 * fp_uniform01(mpl); /* see if it is in the unit circle */ r2 = x * x + y * y; } while (r2 > 1.0 || r2 == 0.0); /* Box-Muller transform */ return y * sqrt(-2.0 * log (r2) / r2); } /*---------------------------------------------------------------------- -- fp_normal - Gaussian random variate with specified mu and sigma. -- -- This routine returns a Gaussian random variate with mean mu and -- standard deviation sigma. */ double fp_normal(MPL *mpl, double mu, double sigma) { double x; #if 0 x = mu + sigma * fp_normal01(mpl); #else x = fp_add(mpl, mu, fp_mul(mpl, sigma, fp_normal01(mpl))); #endif return x; } /**********************************************************************/ /* * * SEGMENTED CHARACTER STRINGS * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- create_string - create character string. -- -- This routine creates a segmented character string, which is exactly -- equivalent to specified character string. */ STRING *create_string ( MPL *mpl, char buf[MAX_LENGTH+1] /* not changed */ ) #if 0 { STRING *head, *tail; int i, j; xassert(buf != NULL); xassert(strlen(buf) <= MAX_LENGTH); head = tail = dmp_get_atom(mpl->strings, sizeof(STRING)); for (i = j = 0; ; i++) { if ((tail->seg[j++] = buf[i]) == '\0') break; if (j == STRSEG_SIZE) tail = (tail->next = dmp_get_atom(mpl->strings, sizeof(STRING))), j = 0; } tail->next = NULL; return head; } #else { STRING *str; xassert(strlen(buf) <= MAX_LENGTH); str = dmp_get_atom(mpl->strings, strlen(buf)+1); strcpy(str, buf); return str; } #endif /*---------------------------------------------------------------------- -- copy_string - make copy of character string. -- -- This routine returns an exact copy of segmented character string. */ STRING *copy_string ( MPL *mpl, STRING *str /* not changed */ ) #if 0 { STRING *head, *tail; xassert(str != NULL); head = tail = dmp_get_atom(mpl->strings, sizeof(STRING)); for (; str != NULL; str = str->next) { memcpy(tail->seg, str->seg, STRSEG_SIZE); if (str->next != NULL) tail = (tail->next = dmp_get_atom(mpl->strings, sizeof(STRING))); } tail->next = NULL; return head; } #else { xassert(mpl == mpl); return create_string(mpl, str); } #endif /*---------------------------------------------------------------------- -- compare_strings - compare one character string with another. -- -- This routine compares one segmented character strings with another -- and returns the result of comparison as follows: -- -- = 0 - both strings are identical; -- < 0 - the first string precedes the second one; -- > 0 - the first string follows the second one. */ int compare_strings ( MPL *mpl, STRING *str1, /* not changed */ STRING *str2 /* not changed */ ) #if 0 { int j, c1, c2; xassert(mpl == mpl); for (;; str1 = str1->next, str2 = str2->next) { xassert(str1 != NULL); xassert(str2 != NULL); for (j = 0; j < STRSEG_SIZE; j++) { c1 = (unsigned char)str1->seg[j]; c2 = (unsigned char)str2->seg[j]; if (c1 < c2) return -1; if (c1 > c2) return +1; if (c1 == '\0') goto done; } } done: return 0; } #else { xassert(mpl == mpl); return strcmp(str1, str2); } #endif /*---------------------------------------------------------------------- -- fetch_string - extract content of character string. -- -- This routine returns a character string, which is exactly equivalent -- to specified segmented character string. */ char *fetch_string ( MPL *mpl, STRING *str, /* not changed */ char buf[MAX_LENGTH+1] /* modified */ ) #if 0 { int i, j; xassert(mpl == mpl); xassert(buf != NULL); for (i = 0; ; str = str->next) { xassert(str != NULL); for (j = 0; j < STRSEG_SIZE; j++) if ((buf[i++] = str->seg[j]) == '\0') goto done; } done: xassert(strlen(buf) <= MAX_LENGTH); return buf; } #else { xassert(mpl == mpl); return strcpy(buf, str); } #endif /*---------------------------------------------------------------------- -- delete_string - delete character string. -- -- This routine deletes specified segmented character string. */ void delete_string ( MPL *mpl, STRING *str /* destroyed */ ) #if 0 { STRING *temp; xassert(str != NULL); while (str != NULL) { temp = str; str = str->next; dmp_free_atom(mpl->strings, temp, sizeof(STRING)); } return; } #else { dmp_free_atom(mpl->strings, str, strlen(str)+1); return; } #endif /**********************************************************************/ /* * * SYMBOLS * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- create_symbol_num - create symbol of numeric type. -- -- This routine creates a symbol, which has a numeric value specified -- as floating-point number. */ SYMBOL *create_symbol_num(MPL *mpl, double num) { SYMBOL *sym; sym = dmp_get_atom(mpl->symbols, sizeof(SYMBOL)); sym->num = num; sym->str = NULL; return sym; } /*---------------------------------------------------------------------- -- create_symbol_str - create symbol of abstract type. -- -- This routine creates a symbol, which has an abstract value specified -- as segmented character string. */ SYMBOL *create_symbol_str ( MPL *mpl, STRING *str /* destroyed */ ) { SYMBOL *sym; xassert(str != NULL); sym = dmp_get_atom(mpl->symbols, sizeof(SYMBOL)); sym->num = 0.0; sym->str = str; return sym; } /*---------------------------------------------------------------------- -- copy_symbol - make copy of symbol. -- -- This routine returns an exact copy of symbol. */ SYMBOL *copy_symbol ( MPL *mpl, SYMBOL *sym /* not changed */ ) { SYMBOL *copy; xassert(sym != NULL); copy = dmp_get_atom(mpl->symbols, sizeof(SYMBOL)); if (sym->str == NULL) { copy->num = sym->num; copy->str = NULL; } else { copy->num = 0.0; copy->str = copy_string(mpl, sym->str); } return copy; } /*---------------------------------------------------------------------- -- compare_symbols - compare one symbol with another. -- -- This routine compares one symbol with another and returns the result -- of comparison as follows: -- -- = 0 - both symbols are identical; -- < 0 - the first symbol precedes the second one; -- > 0 - the first symbol follows the second one. -- -- Note that the linear order, in which symbols follow each other, is -- implementation-dependent. It may be not an alphabetical order. */ int compare_symbols ( MPL *mpl, SYMBOL *sym1, /* not changed */ SYMBOL *sym2 /* not changed */ ) { xassert(sym1 != NULL); xassert(sym2 != NULL); /* let all numeric quantities precede all symbolic quantities */ if (sym1->str == NULL && sym2->str == NULL) { if (sym1->num < sym2->num) return -1; if (sym1->num > sym2->num) return +1; return 0; } if (sym1->str == NULL) return -1; if (sym2->str == NULL) return +1; return compare_strings(mpl, sym1->str, sym2->str); } /*---------------------------------------------------------------------- -- delete_symbol - delete symbol. -- -- This routine deletes specified symbol. */ void delete_symbol ( MPL *mpl, SYMBOL *sym /* destroyed */ ) { xassert(sym != NULL); if (sym->str != NULL) delete_string(mpl, sym->str); dmp_free_atom(mpl->symbols, sym, sizeof(SYMBOL)); return; } /*---------------------------------------------------------------------- -- format_symbol - format symbol for displaying or printing. -- -- This routine converts specified symbol to a charater string, which -- is suitable for displaying or printing. -- -- The resultant string is never longer than 255 characters. If it gets -- longer, it is truncated from the right and appended by dots. */ char *format_symbol ( MPL *mpl, SYMBOL *sym /* not changed */ ) { char *buf = mpl->sym_buf; xassert(sym != NULL); if (sym->str == NULL) sprintf(buf, "%.*g", DBL_DIG, sym->num); else { char str[MAX_LENGTH+1]; int quoted, j, len; fetch_string(mpl, sym->str, str); if (!(isalpha((unsigned char)str[0]) || str[0] == '_')) quoted = 1; else { quoted = 0; for (j = 1; str[j] != '\0'; j++) { if (!(isalnum((unsigned char)str[j]) || strchr("+-._", (unsigned char)str[j]) != NULL)) { quoted = 1; break; } } } # define safe_append(c) \ (void)(len < 255 ? (buf[len++] = (char)(c)) : 0) buf[0] = '\0', len = 0; if (quoted) safe_append('\''); for (j = 0; str[j] != '\0'; j++) { if (quoted && str[j] == '\'') safe_append('\''); safe_append(str[j]); } if (quoted) safe_append('\''); # undef safe_append buf[len] = '\0'; if (len == 255) strcpy(buf+252, "..."); } xassert(strlen(buf) <= 255); return buf; } /*---------------------------------------------------------------------- -- concat_symbols - concatenate one symbol with another. -- -- This routine concatenates values of two given symbols and assigns -- the resultant character string to a new symbol, which is returned on -- exit. Both original symbols are destroyed. */ SYMBOL *concat_symbols ( MPL *mpl, SYMBOL *sym1, /* destroyed */ SYMBOL *sym2 /* destroyed */ ) { char str1[MAX_LENGTH+1], str2[MAX_LENGTH+1]; xassert(MAX_LENGTH >= DBL_DIG + DBL_DIG); if (sym1->str == NULL) sprintf(str1, "%.*g", DBL_DIG, sym1->num); else fetch_string(mpl, sym1->str, str1); if (sym2->str == NULL) sprintf(str2, "%.*g", DBL_DIG, sym2->num); else fetch_string(mpl, sym2->str, str2); if (strlen(str1) + strlen(str2) > MAX_LENGTH) { char buf[255+1]; strcpy(buf, format_symbol(mpl, sym1)); xassert(strlen(buf) < sizeof(buf)); error(mpl, "%s & %s; resultant symbol exceeds %d characters", buf, format_symbol(mpl, sym2), MAX_LENGTH); } delete_symbol(mpl, sym1); delete_symbol(mpl, sym2); return create_symbol_str(mpl, create_string(mpl, strcat(str1, str2))); } /**********************************************************************/ /* * * N-TUPLES * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- create_tuple - create n-tuple. -- -- This routine creates a n-tuple, which initially has no components, -- i.e. which is 0-tuple. */ TUPLE *create_tuple(MPL *mpl) { TUPLE *tuple; xassert(mpl == mpl); tuple = NULL; return tuple; } /*---------------------------------------------------------------------- -- expand_tuple - append symbol to n-tuple. -- -- This routine expands n-tuple appending to it a given symbol, which -- becomes its new last component. */ TUPLE *expand_tuple ( MPL *mpl, TUPLE *tuple, /* destroyed */ SYMBOL *sym /* destroyed */ ) { TUPLE *tail, *temp; xassert(sym != NULL); /* create a new component */ tail = dmp_get_atom(mpl->tuples, sizeof(TUPLE)); tail->sym = sym; tail->next = NULL; /* and append it to the component list */ if (tuple == NULL) tuple = tail; else { for (temp = tuple; temp->next != NULL; temp = temp->next); temp->next = tail; } return tuple; } /*---------------------------------------------------------------------- -- tuple_dimen - determine dimension of n-tuple. -- -- This routine returns dimension of n-tuple, i.e. number of components -- in the n-tuple. */ int tuple_dimen ( MPL *mpl, TUPLE *tuple /* not changed */ ) { TUPLE *temp; int dim = 0; xassert(mpl == mpl); for (temp = tuple; temp != NULL; temp = temp->next) dim++; return dim; } /*---------------------------------------------------------------------- -- copy_tuple - make copy of n-tuple. -- -- This routine returns an exact copy of n-tuple. */ TUPLE *copy_tuple ( MPL *mpl, TUPLE *tuple /* not changed */ ) { TUPLE *head, *tail; if (tuple == NULL) head = NULL; else { head = tail = dmp_get_atom(mpl->tuples, sizeof(TUPLE)); for (; tuple != NULL; tuple = tuple->next) { xassert(tuple->sym != NULL); tail->sym = copy_symbol(mpl, tuple->sym); if (tuple->next != NULL) tail = (tail->next = dmp_get_atom(mpl->tuples, sizeof(TUPLE))); } tail->next = NULL; } return head; } /*---------------------------------------------------------------------- -- compare_tuples - compare one n-tuple with another. -- -- This routine compares two given n-tuples, which must have the same -- dimension (not checked for the sake of efficiency), and returns one -- of the following codes: -- -- = 0 - both n-tuples are identical; -- < 0 - the first n-tuple precedes the second one; -- > 0 - the first n-tuple follows the second one. -- -- Note that the linear order, in which n-tuples follow each other, is -- implementation-dependent. It may be not an alphabetical order. */ int compare_tuples ( MPL *mpl, TUPLE *tuple1, /* not changed */ TUPLE *tuple2 /* not changed */ ) { TUPLE *item1, *item2; int ret; xassert(mpl == mpl); for (item1 = tuple1, item2 = tuple2; item1 != NULL; item1 = item1->next, item2 = item2->next) { xassert(item2 != NULL); xassert(item1->sym != NULL); xassert(item2->sym != NULL); ret = compare_symbols(mpl, item1->sym, item2->sym); if (ret != 0) return ret; } xassert(item2 == NULL); return 0; } /*---------------------------------------------------------------------- -- build_subtuple - build subtuple of given n-tuple. -- -- This routine builds subtuple, which consists of first dim components -- of given n-tuple. */ TUPLE *build_subtuple ( MPL *mpl, TUPLE *tuple, /* not changed */ int dim ) { TUPLE *head, *temp; int j; head = create_tuple(mpl); for (j = 1, temp = tuple; j <= dim; j++, temp = temp->next) { xassert(temp != NULL); head = expand_tuple(mpl, head, copy_symbol(mpl, temp->sym)); } return head; } /*---------------------------------------------------------------------- -- delete_tuple - delete n-tuple. -- -- This routine deletes specified n-tuple. */ void delete_tuple ( MPL *mpl, TUPLE *tuple /* destroyed */ ) { TUPLE *temp; while (tuple != NULL) { temp = tuple; tuple = temp->next; xassert(temp->sym != NULL); delete_symbol(mpl, temp->sym); dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE)); } return; } /*---------------------------------------------------------------------- -- format_tuple - format n-tuple for displaying or printing. -- -- This routine converts specified n-tuple to a character string, which -- is suitable for displaying or printing. -- -- The resultant string is never longer than 255 characters. If it gets -- longer, it is truncated from the right and appended by dots. */ char *format_tuple ( MPL *mpl, int c, TUPLE *tuple /* not changed */ ) { TUPLE *temp; int dim, j, len; char *buf = mpl->tup_buf, str[255+1], *save; # define safe_append(c) \ (void)(len < 255 ? (buf[len++] = (char)(c)) : 0) buf[0] = '\0', len = 0; dim = tuple_dimen(mpl, tuple); if (c == '[' && dim > 0) safe_append('['); if (c == '(' && dim > 1) safe_append('('); for (temp = tuple; temp != NULL; temp = temp->next) { if (temp != tuple) safe_append(','); xassert(temp->sym != NULL); save = mpl->sym_buf; mpl->sym_buf = str; format_symbol(mpl, temp->sym); mpl->sym_buf = save; xassert(strlen(str) < sizeof(str)); for (j = 0; str[j] != '\0'; j++) safe_append(str[j]); } if (c == '[' && dim > 0) safe_append(']'); if (c == '(' && dim > 1) safe_append(')'); # undef safe_append buf[len] = '\0'; if (len == 255) strcpy(buf+252, "..."); xassert(strlen(buf) <= 255); return buf; } /**********************************************************************/ /* * * ELEMENTAL SETS * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- create_elemset - create elemental set. -- -- This routine creates an elemental set, whose members are n-tuples of -- specified dimension. Being created the set is initially empty. */ ELEMSET *create_elemset(MPL *mpl, int dim) { ELEMSET *set; xassert(dim > 0); set = create_array(mpl, A_NONE, dim); return set; } /*---------------------------------------------------------------------- -- find_tuple - check if elemental set contains given n-tuple. -- -- This routine finds given n-tuple in specified elemental set in order -- to check if the set contains that n-tuple. If the n-tuple is found, -- the routine returns pointer to corresponding array member. Otherwise -- null pointer is returned. */ MEMBER *find_tuple ( MPL *mpl, ELEMSET *set, /* not changed */ TUPLE *tuple /* not changed */ ) { xassert(set != NULL); xassert(set->type == A_NONE); xassert(set->dim == tuple_dimen(mpl, tuple)); return find_member(mpl, set, tuple); } /*---------------------------------------------------------------------- -- add_tuple - add new n-tuple to elemental set. -- -- This routine adds given n-tuple to specified elemental set. -- -- For the sake of efficiency this routine doesn't check whether the -- set already contains the same n-tuple or not. Therefore the calling -- program should use the routine find_tuple (if necessary) in order to -- make sure that the given n-tuple is not contained in the set, since -- duplicate n-tuples within the same set are not allowed. */ MEMBER *add_tuple ( MPL *mpl, ELEMSET *set, /* modified */ TUPLE *tuple /* destroyed */ ) { MEMBER *memb; xassert(set != NULL); xassert(set->type == A_NONE); xassert(set->dim == tuple_dimen(mpl, tuple)); memb = add_member(mpl, set, tuple); memb->value.none = NULL; return memb; } /*---------------------------------------------------------------------- -- check_then_add - check and add new n-tuple to elemental set. -- -- This routine is equivalent to the routine add_tuple except that it -- does check for duplicate n-tuples. */ MEMBER *check_then_add ( MPL *mpl, ELEMSET *set, /* modified */ TUPLE *tuple /* destroyed */ ) { if (find_tuple(mpl, set, tuple) != NULL) error(mpl, "duplicate tuple %s detected", format_tuple(mpl, '(', tuple)); return add_tuple(mpl, set, tuple); } /*---------------------------------------------------------------------- -- copy_elemset - make copy of elemental set. -- -- This routine makes an exact copy of elemental set. */ ELEMSET *copy_elemset ( MPL *mpl, ELEMSET *set /* not changed */ ) { ELEMSET *copy; MEMBER *memb; xassert(set != NULL); xassert(set->type == A_NONE); xassert(set->dim > 0); copy = create_elemset(mpl, set->dim); for (memb = set->head; memb != NULL; memb = memb->next) add_tuple(mpl, copy, copy_tuple(mpl, memb->tuple)); return copy; } /*---------------------------------------------------------------------- -- delete_elemset - delete elemental set. -- -- This routine deletes specified elemental set. */ void delete_elemset ( MPL *mpl, ELEMSET *set /* destroyed */ ) { xassert(set != NULL); xassert(set->type == A_NONE); delete_array(mpl, set); return; } /*---------------------------------------------------------------------- -- arelset_size - compute size of "arithmetic" elemental set. -- -- This routine computes the size of "arithmetic" elemental set, which -- is specified in the form of arithmetic progression: -- -- { t0 .. tf by dt }. -- -- The size is computed using the formula: -- -- n = max(0, floor((tf - t0) / dt) + 1). */ int arelset_size(MPL *mpl, double t0, double tf, double dt) { double temp; if (dt == 0.0) error(mpl, "%.*g .. %.*g by %.*g; zero stride not allowed", DBL_DIG, t0, DBL_DIG, tf, DBL_DIG, dt); if (tf > 0.0 && t0 < 0.0 && tf > + 0.999 * DBL_MAX + t0) temp = +DBL_MAX; else if (tf < 0.0 && t0 > 0.0 && tf < - 0.999 * DBL_MAX + t0) temp = -DBL_MAX; else temp = tf - t0; if (fabs(dt) < 1.0 && fabs(temp) > (0.999 * DBL_MAX) * fabs(dt)) { if (temp > 0.0 && dt > 0.0 || temp < 0.0 && dt < 0.0) temp = +DBL_MAX; else temp = 0.0; } else { temp = floor(temp / dt) + 1.0; if (temp < 0.0) temp = 0.0; } xassert(temp >= 0.0); if (temp > (double)(INT_MAX - 1)) error(mpl, "%.*g .. %.*g by %.*g; set too large", DBL_DIG, t0, DBL_DIG, tf, DBL_DIG, dt); return (int)(temp + 0.5); } /*---------------------------------------------------------------------- -- arelset_member - compute member of "arithmetic" elemental set. -- -- This routine returns a numeric value of symbol, which is equivalent -- to j-th member of given "arithmetic" elemental set specified in the -- form of arithmetic progression: -- -- { t0 .. tf by dt }. -- -- The symbol value is computed with the formula: -- -- j-th member = t0 + (j - 1) * dt, -- -- The number j must satisfy to the restriction 1 <= j <= n, where n is -- the set size computed by the routine arelset_size. */ double arelset_member(MPL *mpl, double t0, double tf, double dt, int j) { xassert(1 <= j && j <= arelset_size(mpl, t0, tf, dt)); return t0 + (double)(j - 1) * dt; } /*---------------------------------------------------------------------- -- create_arelset - create "arithmetic" elemental set. -- -- This routine creates "arithmetic" elemental set, which is specified -- in the form of arithmetic progression: -- -- { t0 .. tf by dt }. -- -- Components of this set are 1-tuples. */ ELEMSET *create_arelset(MPL *mpl, double t0, double tf, double dt) { ELEMSET *set; int j, n; set = create_elemset(mpl, 1); n = arelset_size(mpl, t0, tf, dt); for (j = 1; j <= n; j++) { add_tuple ( mpl, set, expand_tuple ( mpl, create_tuple(mpl), create_symbol_num ( mpl, arelset_member(mpl, t0, tf, dt, j) ) ) ); } return set; } /*---------------------------------------------------------------------- -- set_union - union of two elemental sets. -- -- This routine computes the union: -- -- X U Y = { j | (j in X) or (j in Y) }, -- -- where X and Y are given elemental sets (destroyed on exit). */ ELEMSET *set_union ( MPL *mpl, ELEMSET *X, /* destroyed */ ELEMSET *Y /* destroyed */ ) { MEMBER *memb; xassert(X != NULL); xassert(X->type == A_NONE); xassert(X->dim > 0); xassert(Y != NULL); xassert(Y->type == A_NONE); xassert(Y->dim > 0); xassert(X->dim == Y->dim); for (memb = Y->head; memb != NULL; memb = memb->next) { if (find_tuple(mpl, X, memb->tuple) == NULL) add_tuple(mpl, X, copy_tuple(mpl, memb->tuple)); } delete_elemset(mpl, Y); return X; } /*---------------------------------------------------------------------- -- set_diff - difference between two elemental sets. -- -- This routine computes the difference: -- -- X \ Y = { j | (j in X) and (j not in Y) }, -- -- where X and Y are given elemental sets (destroyed on exit). */ ELEMSET *set_diff ( MPL *mpl, ELEMSET *X, /* destroyed */ ELEMSET *Y /* destroyed */ ) { ELEMSET *Z; MEMBER *memb; xassert(X != NULL); xassert(X->type == A_NONE); xassert(X->dim > 0); xassert(Y != NULL); xassert(Y->type == A_NONE); xassert(Y->dim > 0); xassert(X->dim == Y->dim); Z = create_elemset(mpl, X->dim); for (memb = X->head; memb != NULL; memb = memb->next) { if (find_tuple(mpl, Y, memb->tuple) == NULL) add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple)); } delete_elemset(mpl, X); delete_elemset(mpl, Y); return Z; } /*---------------------------------------------------------------------- -- set_symdiff - symmetric difference between two elemental sets. -- -- This routine computes the symmetric difference: -- -- X (+) Y = (X \ Y) U (Y \ X), -- -- where X and Y are given elemental sets (destroyed on exit). */ ELEMSET *set_symdiff ( MPL *mpl, ELEMSET *X, /* destroyed */ ELEMSET *Y /* destroyed */ ) { ELEMSET *Z; MEMBER *memb; xassert(X != NULL); xassert(X->type == A_NONE); xassert(X->dim > 0); xassert(Y != NULL); xassert(Y->type == A_NONE); xassert(Y->dim > 0); xassert(X->dim == Y->dim); /* Z := X \ Y */ Z = create_elemset(mpl, X->dim); for (memb = X->head; memb != NULL; memb = memb->next) { if (find_tuple(mpl, Y, memb->tuple) == NULL) add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple)); } /* Z := Z U (Y \ X) */ for (memb = Y->head; memb != NULL; memb = memb->next) { if (find_tuple(mpl, X, memb->tuple) == NULL) add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple)); } delete_elemset(mpl, X); delete_elemset(mpl, Y); return Z; } /*---------------------------------------------------------------------- -- set_inter - intersection of two elemental sets. -- -- This routine computes the intersection: -- -- X ^ Y = { j | (j in X) and (j in Y) }, -- -- where X and Y are given elemental sets (destroyed on exit). */ ELEMSET *set_inter ( MPL *mpl, ELEMSET *X, /* destroyed */ ELEMSET *Y /* destroyed */ ) { ELEMSET *Z; MEMBER *memb; xassert(X != NULL); xassert(X->type == A_NONE); xassert(X->dim > 0); xassert(Y != NULL); xassert(Y->type == A_NONE); xassert(Y->dim > 0); xassert(X->dim == Y->dim); Z = create_elemset(mpl, X->dim); for (memb = X->head; memb != NULL; memb = memb->next) { if (find_tuple(mpl, Y, memb->tuple) != NULL) add_tuple(mpl, Z, copy_tuple(mpl, memb->tuple)); } delete_elemset(mpl, X); delete_elemset(mpl, Y); return Z; } /*---------------------------------------------------------------------- -- set_cross - cross (Cartesian) product of two elemental sets. -- -- This routine computes the cross (Cartesian) product: -- -- X x Y = { (i,j) | (i in X) and (j in Y) }, -- -- where X and Y are given elemental sets (destroyed on exit). */ ELEMSET *set_cross ( MPL *mpl, ELEMSET *X, /* destroyed */ ELEMSET *Y /* destroyed */ ) { ELEMSET *Z; MEMBER *memx, *memy; TUPLE *tuple, *temp; xassert(X != NULL); xassert(X->type == A_NONE); xassert(X->dim > 0); xassert(Y != NULL); xassert(Y->type == A_NONE); xassert(Y->dim > 0); Z = create_elemset(mpl, X->dim + Y->dim); for (memx = X->head; memx != NULL; memx = memx->next) { for (memy = Y->head; memy != NULL; memy = memy->next) { tuple = copy_tuple(mpl, memx->tuple); for (temp = memy->tuple; temp != NULL; temp = temp->next) tuple = expand_tuple(mpl, tuple, copy_symbol(mpl, temp->sym)); add_tuple(mpl, Z, tuple); } } delete_elemset(mpl, X); delete_elemset(mpl, Y); return Z; } /**********************************************************************/ /* * * ELEMENTAL VARIABLES * * */ /**********************************************************************/ /* (there are no specific routines for elemental variables) */ /**********************************************************************/ /* * * LINEAR FORMS * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- constant_term - create constant term. -- -- This routine creates the linear form, which is a constant term. */ FORMULA *constant_term(MPL *mpl, double coef) { FORMULA *form; if (coef == 0.0) form = NULL; else { form = dmp_get_atom(mpl->formulae, sizeof(FORMULA)); form->coef = coef; form->var = NULL; form->next = NULL; } return form; } /*---------------------------------------------------------------------- -- single_variable - create single variable. -- -- This routine creates the linear form, which is a single elemental -- variable. */ FORMULA *single_variable ( MPL *mpl, ELEMVAR *var /* referenced */ ) { FORMULA *form; xassert(var != NULL); form = dmp_get_atom(mpl->formulae, sizeof(FORMULA)); form->coef = 1.0; form->var = var; form->next = NULL; return form; } /*---------------------------------------------------------------------- -- copy_formula - make copy of linear form. -- -- This routine returns an exact copy of linear form. */ FORMULA *copy_formula ( MPL *mpl, FORMULA *form /* not changed */ ) { FORMULA *head, *tail; if (form == NULL) head = NULL; else { head = tail = dmp_get_atom(mpl->formulae, sizeof(FORMULA)); for (; form != NULL; form = form->next) { tail->coef = form->coef; tail->var = form->var; if (form->next != NULL) tail = (tail->next = dmp_get_atom(mpl->formulae, sizeof(FORMULA))); } tail->next = NULL; } return head; } /*---------------------------------------------------------------------- -- delete_formula - delete linear form. -- -- This routine deletes specified linear form. */ void delete_formula ( MPL *mpl, FORMULA *form /* destroyed */ ) { FORMULA *temp; while (form != NULL) { temp = form; form = form->next; dmp_free_atom(mpl->formulae, temp, sizeof(FORMULA)); } return; } /*---------------------------------------------------------------------- -- linear_comb - linear combination of two linear forms. -- -- This routine computes the linear combination: -- -- a * fx + b * fy, -- -- where a and b are numeric coefficients, fx and fy are linear forms -- (destroyed on exit). */ FORMULA *linear_comb ( MPL *mpl, double a, FORMULA *fx, /* destroyed */ double b, FORMULA *fy /* destroyed */ ) { FORMULA *form = NULL, *term, *temp; double c0 = 0.0; for (term = fx; term != NULL; term = term->next) { if (term->var == NULL) c0 = fp_add(mpl, c0, fp_mul(mpl, a, term->coef)); else term->var->temp = fp_add(mpl, term->var->temp, fp_mul(mpl, a, term->coef)); } for (term = fy; term != NULL; term = term->next) { if (term->var == NULL) c0 = fp_add(mpl, c0, fp_mul(mpl, b, term->coef)); else term->var->temp = fp_add(mpl, term->var->temp, fp_mul(mpl, b, term->coef)); } for (term = fx; term != NULL; term = term->next) { if (term->var != NULL && term->var->temp != 0.0) { temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA)); temp->coef = term->var->temp, temp->var = term->var; temp->next = form, form = temp; term->var->temp = 0.0; } } for (term = fy; term != NULL; term = term->next) { if (term->var != NULL && term->var->temp != 0.0) { temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA)); temp->coef = term->var->temp, temp->var = term->var; temp->next = form, form = temp; term->var->temp = 0.0; } } if (c0 != 0.0) { temp = dmp_get_atom(mpl->formulae, sizeof(FORMULA)); temp->coef = c0, temp->var = NULL; temp->next = form, form = temp; } delete_formula(mpl, fx); delete_formula(mpl, fy); return form; } /*---------------------------------------------------------------------- -- remove_constant - remove constant term from linear form. -- -- This routine removes constant term from linear form and stores its -- value to given location. */ FORMULA *remove_constant ( MPL *mpl, FORMULA *form, /* destroyed */ double *coef /* modified */ ) { FORMULA *head = NULL, *temp; *coef = 0.0; while (form != NULL) { temp = form; form = form->next; if (temp->var == NULL) { /* constant term */ *coef = fp_add(mpl, *coef, temp->coef); dmp_free_atom(mpl->formulae, temp, sizeof(FORMULA)); } else { /* linear term */ temp->next = head; head = temp; } } return head; } /*---------------------------------------------------------------------- -- reduce_terms - reduce identical terms in linear form. -- -- This routine reduces identical terms in specified linear form. */ FORMULA *reduce_terms ( MPL *mpl, FORMULA *form /* destroyed */ ) { FORMULA *term, *next_term; double c0 = 0.0; for (term = form; term != NULL; term = term->next) { if (term->var == NULL) c0 = fp_add(mpl, c0, term->coef); else term->var->temp = fp_add(mpl, term->var->temp, term->coef); } next_term = form, form = NULL; for (term = next_term; term != NULL; term = next_term) { next_term = term->next; if (term->var == NULL && c0 != 0.0) { term->coef = c0, c0 = 0.0; term->next = form, form = term; } else if (term->var != NULL && term->var->temp != 0.0) { term->coef = term->var->temp, term->var->temp = 0.0; term->next = form, form = term; } else dmp_free_atom(mpl->formulae, term, sizeof(FORMULA)); } return form; } /**********************************************************************/ /* * * ELEMENTAL CONSTRAINTS * * */ /**********************************************************************/ /* (there are no specific routines for elemental constraints) */ /**********************************************************************/ /* * * GENERIC VALUES * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- delete_value - delete generic value. -- -- This routine deletes specified generic value. -- -- NOTE: The generic value to be deleted must be valid. */ void delete_value ( MPL *mpl, int type, VALUE *value /* content destroyed */ ) { xassert(value != NULL); switch (type) { case A_NONE: value->none = NULL; break; case A_NUMERIC: value->num = 0.0; break; case A_SYMBOLIC: delete_symbol(mpl, value->sym), value->sym = NULL; break; case A_LOGICAL: value->bit = 0; break; case A_TUPLE: delete_tuple(mpl, value->tuple), value->tuple = NULL; break; case A_ELEMSET: delete_elemset(mpl, value->set), value->set = NULL; break; case A_ELEMVAR: value->var = NULL; break; case A_FORMULA: delete_formula(mpl, value->form), value->form = NULL; break; case A_ELEMCON: value->con = NULL; break; default: xassert(type != type); } return; } /**********************************************************************/ /* * * SYMBOLICALLY INDEXED ARRAYS * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- create_array - create array. -- -- This routine creates an array of specified type and dimension. Being -- created the array is initially empty. -- -- The type indicator determines generic values, which can be assigned -- to the array members: -- -- A_NONE - none (members have no assigned values) -- A_NUMERIC - floating-point numbers -- A_SYMBOLIC - symbols -- A_ELEMSET - elemental sets -- A_ELEMVAR - elemental variables -- A_ELEMCON - elemental constraints -- -- The dimension may be 0, in which case the array consists of the only -- member (such arrays represent 0-dimensional objects). */ ARRAY *create_array(MPL *mpl, int type, int dim) { ARRAY *array; xassert(type == A_NONE || type == A_NUMERIC || type == A_SYMBOLIC || type == A_ELEMSET || type == A_ELEMVAR || type == A_ELEMCON); xassert(dim >= 0); array = dmp_get_atom(mpl->arrays, sizeof(ARRAY)); array->type = type; array->dim = dim; array->size = 0; array->head = NULL; array->tail = NULL; array->tree = NULL; array->prev = NULL; array->next = mpl->a_list; /* include the array in the global array list */ if (array->next != NULL) array->next->prev = array; mpl->a_list = array; return array; } /*---------------------------------------------------------------------- -- find_member - find array member with given n-tuple. -- -- This routine finds an array member, which has given n-tuple. If the -- array is short, the linear search is used. Otherwise the routine -- autimatically creates the search tree (i.e. the array index) to find -- members for logarithmic time. */ static int compare_member_tuples(void *info, const void *key1, const void *key2) { /* this is an auxiliary routine used to compare keys, which are n-tuples assigned to array members */ return compare_tuples((MPL *)info, (TUPLE *)key1, (TUPLE *)key2); } MEMBER *find_member ( MPL *mpl, ARRAY *array, /* not changed */ TUPLE *tuple /* not changed */ ) { MEMBER *memb; xassert(array != NULL); /* the n-tuple must have the same dimension as the array */ xassert(tuple_dimen(mpl, tuple) == array->dim); /* if the array is large enough, create the search tree and index all existing members of the array */ if (array->size > 30 && array->tree == NULL) { array->tree = avl_create_tree(compare_member_tuples, mpl); for (memb = array->head; memb != NULL; memb = memb->next) avl_set_node_link(avl_insert_node(array->tree, memb->tuple), (void *)memb); } /* find a member, which has the given tuple */ if (array->tree == NULL) { /* the search tree doesn't exist; use the linear search */ for (memb = array->head; memb != NULL; memb = memb->next) if (compare_tuples(mpl, memb->tuple, tuple) == 0) break; } else { /* the search tree exists; use the binary search */ AVLNODE *node; node = avl_find_node(array->tree, tuple); memb = (MEMBER *)(node == NULL ? NULL : avl_get_node_link(node)); } return memb; } /*---------------------------------------------------------------------- -- add_member - add new member to array. -- -- This routine creates a new member with given n-tuple and adds it to -- specified array. -- -- For the sake of efficiency this routine doesn't check whether the -- array already contains a member with the given n-tuple or not. Thus, -- if necessary, the calling program should use the routine find_member -- in order to be sure that the array contains no member with the same -- n-tuple, because members with duplicate n-tuples are not allowed. -- -- This routine assigns no generic value to the new member, because the -- calling program must do that. */ MEMBER *add_member ( MPL *mpl, ARRAY *array, /* modified */ TUPLE *tuple /* destroyed */ ) { MEMBER *memb; xassert(array != NULL); /* the n-tuple must have the same dimension as the array */ xassert(tuple_dimen(mpl, tuple) == array->dim); /* create new member */ memb = dmp_get_atom(mpl->members, sizeof(MEMBER)); memb->tuple = tuple; memb->next = NULL; memset(&memb->value, '?', sizeof(VALUE)); /* and append it to the member list */ array->size++; if (array->head == NULL) array->head = memb; else array->tail->next = memb; array->tail = memb; /* if the search tree exists, index the new member */ if (array->tree != NULL) avl_set_node_link(avl_insert_node(array->tree, memb->tuple), (void *)memb); return memb; } /*---------------------------------------------------------------------- -- delete_array - delete array. -- -- This routine deletes specified array. -- -- Generic values assigned to the array members are not deleted by this -- routine. The calling program itself must delete all assigned generic -- values before deleting the array. */ void delete_array ( MPL *mpl, ARRAY *array /* destroyed */ ) { MEMBER *memb; xassert(array != NULL); /* delete all existing array members */ while (array->head != NULL) { memb = array->head; array->head = memb->next; delete_tuple(mpl, memb->tuple); dmp_free_atom(mpl->members, memb, sizeof(MEMBER)); } /* if the search tree exists, also delete it */ if (array->tree != NULL) avl_delete_tree(array->tree); /* remove the array from the global array list */ if (array->prev == NULL) mpl->a_list = array->next; else array->prev->next = array->next; if (array->next == NULL) ; else array->next->prev = array->prev; /* delete the array descriptor */ dmp_free_atom(mpl->arrays, array, sizeof(ARRAY)); return; } /**********************************************************************/ /* * * DOMAINS AND DUMMY INDICES * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- assign_dummy_index - assign new value to dummy index. -- -- This routine assigns new value to specified dummy index and, that is -- important, invalidates all temporary resultant values, which depends -- on that dummy index. */ void assign_dummy_index ( MPL *mpl, DOMAIN_SLOT *slot, /* modified */ SYMBOL *value /* not changed */ ) { CODE *leaf, *code; xassert(slot != NULL); xassert(value != NULL); /* delete the current value assigned to the dummy index */ if (slot->value != NULL) { /* if the current value and the new one are identical, actual assignment is not needed */ if (compare_symbols(mpl, slot->value, value) == 0) goto done; /* delete a symbol, which is the current value */ delete_symbol(mpl, slot->value), slot->value = NULL; } /* now walk through all the pseudo-codes with op = O_INDEX, which refer to the dummy index to be changed (these pseudo-codes are leaves in the forest of *all* expressions in the database) */ for (leaf = slot->list; leaf != NULL; leaf = leaf->arg.index. next) { xassert(leaf->op == O_INDEX); /* invalidate all resultant values, which depend on the dummy index, walking from the current leaf toward the root of the corresponding expression tree */ for (code = leaf; code != NULL; code = code->up) { if (code->valid) { /* invalidate and delete resultant value */ code->valid = 0; delete_value(mpl, code->type, &code->value); } } } /* assign new value to the dummy index */ slot->value = copy_symbol(mpl, value); done: return; } /*---------------------------------------------------------------------- -- update_dummy_indices - update current values of dummy indices. -- -- This routine assigns components of "backup" n-tuple to dummy indices -- of specified domain block. If no "backup" n-tuple is defined for the -- domain block, values of the dummy indices remain untouched. */ void update_dummy_indices ( MPL *mpl, DOMAIN_BLOCK *block /* not changed */ ) { DOMAIN_SLOT *slot; TUPLE *temp; if (block->backup != NULL) { for (slot = block->list, temp = block->backup; slot != NULL; slot = slot->next, temp = temp->next) { xassert(temp != NULL); xassert(temp->sym != NULL); assign_dummy_index(mpl, slot, temp->sym); } } return; } /*---------------------------------------------------------------------- -- enter_domain_block - enter domain block. -- -- Let specified domain block have the form: -- -- { ..., (j1, j2, ..., jn) in J, ... } -- -- where j1, j2, ..., jn are dummy indices, J is a basic set. -- -- This routine does the following: -- -- 1. Checks if the given n-tuple is a member of the basic set J. Note -- that J being *out of the scope* of the domain block cannot depend -- on the dummy indices in the same and inner domain blocks, so it -- can be computed before the dummy indices are assigned new values. -- If this check fails, the routine returns with non-zero code. -- -- 2. Saves current values of the dummy indices j1, j2, ..., jn. -- -- 3. Assigns new values, which are components of the given n-tuple, to -- the dummy indices j1, j2, ..., jn. If dimension of the n-tuple is -- larger than n, its extra components n+1, n+2, ... are not used. -- -- 4. Calls the formal routine func which either enters the next domain -- block or evaluates some code within the domain scope. -- -- 5. Restores former values of the dummy indices j1, j2, ..., jn. -- -- Since current values assigned to the dummy indices on entry to this -- routine are restored on exit, the formal routine func is allowed to -- call this routine recursively. */ int enter_domain_block ( MPL *mpl, DOMAIN_BLOCK *block, /* not changed */ TUPLE *tuple, /* not changed */ void *info, void (*func)(MPL *mpl, void *info) ) { TUPLE *backup; int ret = 0; /* check if the given n-tuple is a member of the basic set */ xassert(block->code != NULL); if (!is_member(mpl, block->code, tuple)) { ret = 1; goto done; } /* save reference to "backup" n-tuple, which was used to assign current values of the dummy indices (it is sufficient to save reference, not value, because that n-tuple is defined in some outer level of recursion and therefore cannot be changed on this and deeper recursive calls) */ backup = block->backup; /* set up new "backup" n-tuple, which defines new values of the dummy indices */ block->backup = tuple; /* assign new values to the dummy indices */ update_dummy_indices(mpl, block); /* call the formal routine that does the rest part of the job */ func(mpl, info); /* restore reference to the former "backup" n-tuple */ block->backup = backup; /* restore former values of the dummy indices; note that if the domain block just escaped has no other active instances which may exist due to recursion (it is indicated by a null pointer to the former n-tuple), former values of the dummy indices are undefined; therefore in this case the routine keeps currently assigned values of the dummy indices that involves keeping all dependent temporary results and thereby, if this domain block is not used recursively, allows improving efficiency */ update_dummy_indices(mpl, block); done: return ret; } /*---------------------------------------------------------------------- -- eval_within_domain - perform evaluation within domain scope. -- -- This routine assigns new values (symbols) to all dummy indices of -- specified domain and calls the formal routine func, which is used to -- evaluate some code in the domain scope. Each free dummy index in the -- domain is assigned a value specified in the corresponding component -- of given n-tuple. Non-free dummy indices are assigned values, which -- are computed by this routine. -- -- Number of components in the given n-tuple must be the same as number -- of free indices in the domain. -- -- If the given n-tuple is not a member of the domain set, the routine -- func is not called, and non-zero code is returned. -- -- For the sake of convenience it is allowed to specify domain as NULL -- (then n-tuple also must be 0-tuple, i.e. empty), in which case this -- routine just calls the routine func and returns zero. -- -- This routine allows recursive calls from the routine func providing -- correct values of dummy indices for each instance. -- -- NOTE: The n-tuple passed to this routine must not be changed by any -- other routines called from the formal routine func until this -- routine has returned. */ struct eval_domain_info { /* working info used by the routine eval_within_domain */ DOMAIN *domain; /* domain, which has to be entered */ DOMAIN_BLOCK *block; /* domain block, which is currently processed */ TUPLE *tuple; /* tail of original n-tuple, whose components have to be assigned to free dummy indices in the current domain block */ void *info; /* transit pointer passed to the formal routine func */ void (*func)(MPL *mpl, void *info); /* routine, which has to be executed in the domain scope */ int failure; /* this flag indicates that given n-tuple is not a member of the domain set */ }; static void eval_domain_func(MPL *mpl, void *_my_info) { /* this routine recursively enters into the domain scope and then calls the routine func */ struct eval_domain_info *my_info = _my_info; if (my_info->block != NULL) { /* the current domain block to be entered exists */ DOMAIN_BLOCK *block; DOMAIN_SLOT *slot; TUPLE *tuple = NULL, *temp = NULL; /* save pointer to the current domain block */ block = my_info->block; /* and get ready to enter the next block (if it exists) */ my_info->block = block->next; /* construct temporary n-tuple, whose components correspond to dummy indices (slots) of the current domain; components of the temporary n-tuple that correspond to free dummy indices are assigned references (not values!) to symbols specified in the corresponding components of the given n-tuple, while other components that correspond to non-free dummy indices are assigned symbolic values computed here */ for (slot = block->list; slot != NULL; slot = slot->next) { /* create component that corresponds to the current slot */ if (tuple == NULL) tuple = temp = dmp_get_atom(mpl->tuples, sizeof(TUPLE)); else temp = (temp->next = dmp_get_atom(mpl->tuples, sizeof(TUPLE))); if (slot->code == NULL) { /* dummy index is free; take reference to symbol, which is specified in the corresponding component of given n-tuple */ xassert(my_info->tuple != NULL); temp->sym = my_info->tuple->sym; xassert(temp->sym != NULL); my_info->tuple = my_info->tuple->next; } else { /* dummy index is non-free; compute symbolic value to be temporarily assigned to the dummy index */ temp->sym = eval_symbolic(mpl, slot->code); } } temp->next = NULL; /* enter the current domain block */ if (enter_domain_block(mpl, block, tuple, my_info, eval_domain_func)) my_info->failure = 1; /* delete temporary n-tuple as well as symbols that correspond to non-free dummy indices (they were computed here) */ for (slot = block->list; slot != NULL; slot = slot->next) { xassert(tuple != NULL); temp = tuple; tuple = tuple->next; if (slot->code != NULL) { /* dummy index is non-free; delete symbolic value */ delete_symbol(mpl, temp->sym); } /* delete component that corresponds to the current slot */ dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE)); } } else { /* there are no more domain blocks, i.e. we have reached the domain scope */ xassert(my_info->tuple == NULL); /* check optional predicate specified for the domain */ if (my_info->domain->code != NULL && !eval_logical(mpl, my_info->domain->code)) { /* the predicate is false */ my_info->failure = 2; } else { /* the predicate is true; do the job */ my_info->func(mpl, my_info->info); } } return; } int eval_within_domain ( MPL *mpl, DOMAIN *domain, /* not changed */ TUPLE *tuple, /* not changed */ void *info, void (*func)(MPL *mpl, void *info) ) { /* this routine performs evaluation within domain scope */ struct eval_domain_info _my_info, *my_info = &_my_info; if (domain == NULL) { xassert(tuple == NULL); func(mpl, info); my_info->failure = 0; } else { xassert(tuple != NULL); my_info->domain = domain; my_info->block = domain->list; my_info->tuple = tuple; my_info->info = info; my_info->func = func; my_info->failure = 0; /* enter the very first domain block */ eval_domain_func(mpl, my_info); } return my_info->failure; } /*---------------------------------------------------------------------- -- loop_within_domain - perform iterations within domain scope. -- -- This routine iteratively assigns new values (symbols) to the dummy -- indices of specified domain by enumerating all n-tuples, which are -- members of the domain set, and for every n-tuple it calls the formal -- routine func to evaluate some code within the domain scope. -- -- If the routine func returns non-zero, enumeration within the domain -- is prematurely terminated. -- -- For the sake of convenience it is allowed to specify domain as NULL, -- in which case this routine just calls the routine func only once and -- returns zero. -- -- This routine allows recursive calls from the routine func providing -- correct values of dummy indices for each instance. */ struct loop_domain_info { /* working info used by the routine loop_within_domain */ DOMAIN *domain; /* domain, which has to be entered */ DOMAIN_BLOCK *block; /* domain block, which is currently processed */ int looping; /* clearing this flag leads to terminating enumeration */ void *info; /* transit pointer passed to the formal routine func */ int (*func)(MPL *mpl, void *info); /* routine, which needs to be executed in the domain scope */ }; static void loop_domain_func(MPL *mpl, void *_my_info) { /* this routine enumerates all n-tuples in the basic set of the current domain block, enters recursively into the domain scope for every n-tuple, and then calls the routine func */ struct loop_domain_info *my_info = _my_info; if (my_info->block != NULL) { /* the current domain block to be entered exists */ DOMAIN_BLOCK *block; DOMAIN_SLOT *slot; TUPLE *bound; /* save pointer to the current domain block */ block = my_info->block; /* and get ready to enter the next block (if it exists) */ my_info->block = block->next; /* compute symbolic values, at which non-free dummy indices of the current domain block are bound; since that values don't depend on free dummy indices of the current block, they can be computed once out of the enumeration loop */ bound = create_tuple(mpl); for (slot = block->list; slot != NULL; slot = slot->next) { if (slot->code != NULL) bound = expand_tuple(mpl, bound, eval_symbolic(mpl, slot->code)); } /* start enumeration */ xassert(block->code != NULL); if (block->code->op == O_DOTS) { /* the basic set is "arithmetic", in which case it doesn't need to be computed explicitly */ TUPLE *tuple; int n, j; double t0, tf, dt; /* compute "parameters" of the basic set */ t0 = eval_numeric(mpl, block->code->arg.arg.x); tf = eval_numeric(mpl, block->code->arg.arg.y); if (block->code->arg.arg.z == NULL) dt = 1.0; else dt = eval_numeric(mpl, block->code->arg.arg.z); /* determine cardinality of the basic set */ n = arelset_size(mpl, t0, tf, dt); /* create dummy 1-tuple for members of the basic set */ tuple = expand_tuple(mpl, create_tuple(mpl), create_symbol_num(mpl, 0.0)); /* in case of "arithmetic" set there is exactly one dummy index, which cannot be non-free */ xassert(bound == NULL); /* walk through 1-tuples of the basic set */ for (j = 1; j <= n && my_info->looping; j++) { /* construct dummy 1-tuple for the current member */ tuple->sym->num = arelset_member(mpl, t0, tf, dt, j); /* enter the current domain block */ enter_domain_block(mpl, block, tuple, my_info, loop_domain_func); } /* delete dummy 1-tuple */ delete_tuple(mpl, tuple); } else { /* the basic set is of general kind, in which case it needs to be explicitly computed */ ELEMSET *set; MEMBER *memb; TUPLE *temp1, *temp2; /* compute the basic set */ set = eval_elemset(mpl, block->code); /* walk through all n-tuples of the basic set */ for (memb = set->head; memb != NULL && my_info->looping; memb = memb->next) { /* all components of the current n-tuple that correspond to non-free dummy indices must be feasible; otherwise the n-tuple is not in the basic set */ temp1 = memb->tuple; temp2 = bound; for (slot = block->list; slot != NULL; slot = slot->next) { xassert(temp1 != NULL); if (slot->code != NULL) { /* non-free dummy index */ xassert(temp2 != NULL); if (compare_symbols(mpl, temp1->sym, temp2->sym) != 0) { /* the n-tuple is not in the basic set */ goto skip; } temp2 = temp2->next; } temp1 = temp1->next; } xassert(temp1 == NULL); xassert(temp2 == NULL); /* enter the current domain block */ enter_domain_block(mpl, block, memb->tuple, my_info, loop_domain_func); skip: ; } /* delete the basic set */ delete_elemset(mpl, set); } /* delete symbolic values binding non-free dummy indices */ delete_tuple(mpl, bound); /* restore pointer to the current domain block */ my_info->block = block; } else { /* there are no more domain blocks, i.e. we have reached the domain scope */ /* check optional predicate specified for the domain */ if (my_info->domain->code != NULL && !eval_logical(mpl, my_info->domain->code)) { /* the predicate is false */ /* nop */; } else { /* the predicate is true; do the job */ my_info->looping = !my_info->func(mpl, my_info->info); } } return; } void loop_within_domain ( MPL *mpl, DOMAIN *domain, /* not changed */ void *info, int (*func)(MPL *mpl, void *info) ) { /* this routine performs iterations within domain scope */ struct loop_domain_info _my_info, *my_info = &_my_info; if (domain == NULL) func(mpl, info); else { my_info->domain = domain; my_info->block = domain->list; my_info->looping = 1; my_info->info = info; my_info->func = func; /* enter the very first domain block */ loop_domain_func(mpl, my_info); } return; } /*---------------------------------------------------------------------- -- out_of_domain - raise domain exception. -- -- This routine is called when a reference is made to a member of some -- model object, but its n-tuple is out of the object domain. */ void out_of_domain ( MPL *mpl, char *name, /* not changed */ TUPLE *tuple /* not changed */ ) { xassert(name != NULL); xassert(tuple != NULL); error(mpl, "%s%s out of domain", name, format_tuple(mpl, '[', tuple)); /* no return */ } /*---------------------------------------------------------------------- -- get_domain_tuple - obtain current n-tuple from domain. -- -- This routine constructs n-tuple, whose components are current values -- assigned to *free* dummy indices of specified domain. -- -- For the sake of convenience it is allowed to specify domain as NULL, -- in which case this routine returns 0-tuple. -- -- NOTE: This routine must not be called out of domain scope. */ TUPLE *get_domain_tuple ( MPL *mpl, DOMAIN *domain /* not changed */ ) { DOMAIN_BLOCK *block; DOMAIN_SLOT *slot; TUPLE *tuple; tuple = create_tuple(mpl); if (domain != NULL) { for (block = domain->list; block != NULL; block = block->next) { for (slot = block->list; slot != NULL; slot = slot->next) { if (slot->code == NULL) { xassert(slot->value != NULL); tuple = expand_tuple(mpl, tuple, copy_symbol(mpl, slot->value)); } } } } return tuple; } /*---------------------------------------------------------------------- -- clean_domain - clean domain. -- -- This routine cleans specified domain that assumes deleting all stuff -- dynamically allocated during the generation phase. */ void clean_domain(MPL *mpl, DOMAIN *domain) { DOMAIN_BLOCK *block; DOMAIN_SLOT *slot; /* if no domain is specified, do nothing */ if (domain == NULL) goto done; /* clean all domain blocks */ for (block = domain->list; block != NULL; block = block->next) { /* clean all domain slots */ for (slot = block->list; slot != NULL; slot = slot->next) { /* clean pseudo-code for computing bound value */ clean_code(mpl, slot->code); /* delete symbolic value assigned to dummy index */ if (slot->value != NULL) delete_symbol(mpl, slot->value), slot->value = NULL; } /* clean pseudo-code for computing basic set */ clean_code(mpl, block->code); } /* clean pseudo-code for computing domain predicate */ clean_code(mpl, domain->code); done: return; } /**********************************************************************/ /* * * MODEL SETS * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- check_elem_set - check elemental set assigned to set member. -- -- This routine checks if given elemental set being assigned to member -- of specified model set satisfies to all restrictions. -- -- NOTE: This routine must not be called out of domain scope. */ void check_elem_set ( MPL *mpl, SET *set, /* not changed */ TUPLE *tuple, /* not changed */ ELEMSET *refer /* not changed */ ) { WITHIN *within; MEMBER *memb; int eqno; /* elemental set must be within all specified supersets */ for (within = set->within, eqno = 1; within != NULL; within = within->next, eqno++) { xassert(within->code != NULL); for (memb = refer->head; memb != NULL; memb = memb->next) { if (!is_member(mpl, within->code, memb->tuple)) { char buf[255+1]; strcpy(buf, format_tuple(mpl, '(', memb->tuple)); xassert(strlen(buf) < sizeof(buf)); error(mpl, "%s%s contains %s which not within specified " "set; see (%d)", set->name, format_tuple(mpl, '[', tuple), buf, eqno); } } } return; } /*---------------------------------------------------------------------- -- take_member_set - obtain elemental set assigned to set member. -- -- This routine obtains a reference to elemental set assigned to given -- member of specified model set and returns it on exit. -- -- NOTE: This routine must not be called out of domain scope. */ ELEMSET *take_member_set /* returns reference, not value */ ( MPL *mpl, SET *set, /* not changed */ TUPLE *tuple /* not changed */ ) { MEMBER *memb; ELEMSET *refer; /* find member in the set array */ memb = find_member(mpl, set->array, tuple); if (memb != NULL) { /* member exists, so just take the reference */ refer = memb->value.set; } else if (set->assign != NULL) { /* compute value using assignment expression */ refer = eval_elemset(mpl, set->assign); add: /* check that the elemental set satisfies to all restrictions, assign it to new member, and add the member to the array */ check_elem_set(mpl, set, tuple, refer); memb = add_member(mpl, set->array, copy_tuple(mpl, tuple)); memb->value.set = refer; } else if (set->option != NULL) { /* compute default elemental set */ refer = eval_elemset(mpl, set->option); goto add; } else { /* no value (elemental set) is provided */ error(mpl, "no value for %s%s", set->name, format_tuple(mpl, '[', tuple)); } return refer; } /*---------------------------------------------------------------------- -- eval_member_set - evaluate elemental set assigned to set member. -- -- This routine evaluates a reference to elemental set assigned to given -- member of specified model set and returns it on exit. */ struct eval_set_info { /* working info used by the routine eval_member_set */ SET *set; /* model set */ TUPLE *tuple; /* n-tuple, which defines set member */ MEMBER *memb; /* normally this pointer is NULL; the routine uses this pointer to check data provided in the data section, in which case it points to a member currently checked; this check is performed automatically only once when a reference to any member occurs for the first time */ ELEMSET *refer; /* evaluated reference to elemental set */ }; static void eval_set_func(MPL *mpl, void *_info) { /* this is auxiliary routine to work within domain scope */ struct eval_set_info *info = _info; if (info->memb != NULL) { /* checking call; check elemental set being assigned */ check_elem_set(mpl, info->set, info->memb->tuple, info->memb->value.set); } else { /* normal call; evaluate member, which has given n-tuple */ info->refer = take_member_set(mpl, info->set, info->tuple); } return; } #if 1 /* 12/XII-2008 */ static void saturate_set(MPL *mpl, SET *set) { GADGET *gadget = set->gadget; ELEMSET *data; MEMBER *elem, *memb; TUPLE *tuple, *work[20]; int i; xprintf("Generating %s...\n", set->name); eval_whole_set(mpl, gadget->set); /* gadget set must have exactly one member */ xassert(gadget->set->array != NULL); xassert(gadget->set->array->head != NULL); xassert(gadget->set->array->head == gadget->set->array->tail); data = gadget->set->array->head->value.set; xassert(data->type == A_NONE); xassert(data->dim == gadget->set->dimen); /* walk thru all elements of the plain set */ for (elem = data->head; elem != NULL; elem = elem->next) { /* create a copy of n-tuple */ tuple = copy_tuple(mpl, elem->tuple); /* rearrange component of the n-tuple */ for (i = 0; i < gadget->set->dimen; i++) work[i] = NULL; for (i = 0; tuple != NULL; tuple = tuple->next) work[gadget->ind[i++]-1] = tuple; xassert(i == gadget->set->dimen); for (i = 0; i < gadget->set->dimen; i++) { xassert(work[i] != NULL); work[i]->next = work[i+1]; } /* construct subscript list from first set->dim components */ if (set->dim == 0) tuple = NULL; else tuple = work[0], work[set->dim-1]->next = NULL; /* find corresponding member of the set to be initialized */ memb = find_member(mpl, set->array, tuple); if (memb == NULL) { /* not found; add new member to the set and assign it empty elemental set */ memb = add_member(mpl, set->array, tuple); memb->value.set = create_elemset(mpl, set->dimen); } else { /* found; free subscript list */ delete_tuple(mpl, tuple); } /* construct new n-tuple from rest set->dimen components */ tuple = work[set->dim]; xassert(set->dim + set->dimen == gadget->set->dimen); work[gadget->set->dimen-1]->next = NULL; /* and add it to the elemental set assigned to the member (no check for duplicates is needed) */ add_tuple(mpl, memb->value.set, tuple); } /* the set has been saturated with data */ set->data = 1; return; } #endif ELEMSET *eval_member_set /* returns reference, not value */ ( MPL *mpl, SET *set, /* not changed */ TUPLE *tuple /* not changed */ ) { /* this routine evaluates set member */ struct eval_set_info _info, *info = &_info; xassert(set->dim == tuple_dimen(mpl, tuple)); info->set = set; info->tuple = tuple; #if 1 /* 12/XII-2008 */ if (set->gadget != NULL && set->data == 0) { /* initialize the set with data from a plain set */ saturate_set(mpl, set); } #endif if (set->data == 1) { /* check data, which are provided in the data section, but not checked yet */ /* save pointer to the last array member; note that during the check new members may be added beyond the last member due to references to the same parameter from default expression as well as from expressions that define restricting supersets; however, values assigned to the new members will be checked by other routine, so we don't need to check them here */ MEMBER *tail = set->array->tail; /* change the data status to prevent infinite recursive loop due to references to the same set during the check */ set->data = 2; /* check elemental sets assigned to array members in the data section until the marked member has been reached */ for (info->memb = set->array->head; info->memb != NULL; info->memb = info->memb->next) { if (eval_within_domain(mpl, set->domain, info->memb->tuple, info, eval_set_func)) out_of_domain(mpl, set->name, info->memb->tuple); if (info->memb == tail) break; } /* the check has been finished */ } /* evaluate member, which has given n-tuple */ info->memb = NULL; if (eval_within_domain(mpl, info->set->domain, info->tuple, info, eval_set_func)) out_of_domain(mpl, set->name, info->tuple); /* bring evaluated reference to the calling program */ return info->refer; } /*---------------------------------------------------------------------- -- eval_whole_set - evaluate model set over entire domain. -- -- This routine evaluates all members of specified model set over entire -- domain. */ static int whole_set_func(MPL *mpl, void *info) { /* this is auxiliary routine to work within domain scope */ SET *set = (SET *)info; TUPLE *tuple = get_domain_tuple(mpl, set->domain); eval_member_set(mpl, set, tuple); delete_tuple(mpl, tuple); return 0; } void eval_whole_set(MPL *mpl, SET *set) { loop_within_domain(mpl, set->domain, set, whole_set_func); return; } /*---------------------------------------------------------------------- -- clean set - clean model set. -- -- This routine cleans specified model set that assumes deleting all -- stuff dynamically allocated during the generation phase. */ void clean_set(MPL *mpl, SET *set) { WITHIN *within; MEMBER *memb; /* clean subscript domain */ clean_domain(mpl, set->domain); /* clean pseudo-code for computing supersets */ for (within = set->within; within != NULL; within = within->next) clean_code(mpl, within->code); /* clean pseudo-code for computing assigned value */ clean_code(mpl, set->assign); /* clean pseudo-code for computing default value */ clean_code(mpl, set->option); /* reset data status flag */ set->data = 0; /* delete content array */ for (memb = set->array->head; memb != NULL; memb = memb->next) delete_value(mpl, set->array->type, &memb->value); delete_array(mpl, set->array), set->array = NULL; return; } /**********************************************************************/ /* * * MODEL PARAMETERS * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- check_value_num - check numeric value assigned to parameter member. -- -- This routine checks if numeric value being assigned to some member -- of specified numeric model parameter satisfies to all restrictions. -- -- NOTE: This routine must not be called out of domain scope. */ void check_value_num ( MPL *mpl, PARAMETER *par, /* not changed */ TUPLE *tuple, /* not changed */ double value ) { CONDITION *cond; WITHIN *in; int eqno; /* the value must satisfy to the parameter type */ switch (par->type) { case A_NUMERIC: break; case A_INTEGER: if (value != floor(value)) error(mpl, "%s%s = %.*g not integer", par->name, format_tuple(mpl, '[', tuple), DBL_DIG, value); break; case A_BINARY: if (!(value == 0.0 || value == 1.0)) error(mpl, "%s%s = %.*g not binary", par->name, format_tuple(mpl, '[', tuple), DBL_DIG, value); break; default: xassert(par != par); } /* the value must satisfy to all specified conditions */ for (cond = par->cond, eqno = 1; cond != NULL; cond = cond->next, eqno++) { double bound; char *rho; xassert(cond->code != NULL); bound = eval_numeric(mpl, cond->code); switch (cond->rho) { case O_LT: if (!(value < bound)) { rho = "<"; err: error(mpl, "%s%s = %.*g not %s %.*g; see (%d)", par->name, format_tuple(mpl, '[', tuple), DBL_DIG, value, rho, DBL_DIG, bound, eqno); } break; case O_LE: if (!(value <= bound)) { rho = "<="; goto err; } break; case O_EQ: if (!(value == bound)) { rho = "="; goto err; } break; case O_GE: if (!(value >= bound)) { rho = ">="; goto err; } break; case O_GT: if (!(value > bound)) { rho = ">"; goto err; } break; case O_NE: if (!(value != bound)) { rho = "<>"; goto err; } break; default: xassert(cond != cond); } } /* the value must be in all specified supersets */ for (in = par->in, eqno = 1; in != NULL; in = in->next, eqno++) { TUPLE *dummy; xassert(in->code != NULL); xassert(in->code->dim == 1); dummy = expand_tuple(mpl, create_tuple(mpl), create_symbol_num(mpl, value)); if (!is_member(mpl, in->code, dummy)) error(mpl, "%s%s = %.*g not in specified set; see (%d)", par->name, format_tuple(mpl, '[', tuple), DBL_DIG, value, eqno); delete_tuple(mpl, dummy); } return; } /*---------------------------------------------------------------------- -- take_member_num - obtain num. value assigned to parameter member. -- -- This routine obtains a numeric value assigned to member of specified -- numeric model parameter and returns it on exit. -- -- NOTE: This routine must not be called out of domain scope. */ double take_member_num ( MPL *mpl, PARAMETER *par, /* not changed */ TUPLE *tuple /* not changed */ ) { MEMBER *memb; double value; /* find member in the parameter array */ memb = find_member(mpl, par->array, tuple); if (memb != NULL) { /* member exists, so just take its value */ value = memb->value.num; } else if (par->assign != NULL) { /* compute value using assignment expression */ value = eval_numeric(mpl, par->assign); add: /* check that the value satisfies to all restrictions, assign it to new member, and add the member to the array */ check_value_num(mpl, par, tuple, value); memb = add_member(mpl, par->array, copy_tuple(mpl, tuple)); memb->value.num = value; } else if (par->option != NULL) { /* compute default value */ value = eval_numeric(mpl, par->option); goto add; } else if (par->defval != NULL) { /* take default value provided in the data section */ if (par->defval->str != NULL) error(mpl, "cannot convert %s to floating-point number", format_symbol(mpl, par->defval)); value = par->defval->num; goto add; } else { /* no value is provided */ error(mpl, "no value for %s%s", par->name, format_tuple(mpl, '[', tuple)); } return value; } /*---------------------------------------------------------------------- -- eval_member_num - evaluate num. value assigned to parameter member. -- -- This routine evaluates a numeric value assigned to given member of -- specified numeric model parameter and returns it on exit. */ struct eval_num_info { /* working info used by the routine eval_member_num */ PARAMETER *par; /* model parameter */ TUPLE *tuple; /* n-tuple, which defines parameter member */ MEMBER *memb; /* normally this pointer is NULL; the routine uses this pointer to check data provided in the data section, in which case it points to a member currently checked; this check is performed automatically only once when a reference to any member occurs for the first time */ double value; /* evaluated numeric value */ }; static void eval_num_func(MPL *mpl, void *_info) { /* this is auxiliary routine to work within domain scope */ struct eval_num_info *info = _info; if (info->memb != NULL) { /* checking call; check numeric value being assigned */ check_value_num(mpl, info->par, info->memb->tuple, info->memb->value.num); } else { /* normal call; evaluate member, which has given n-tuple */ info->value = take_member_num(mpl, info->par, info->tuple); } return; } double eval_member_num ( MPL *mpl, PARAMETER *par, /* not changed */ TUPLE *tuple /* not changed */ ) { /* this routine evaluates numeric parameter member */ struct eval_num_info _info, *info = &_info; xassert(par->type == A_NUMERIC || par->type == A_INTEGER || par->type == A_BINARY); xassert(par->dim == tuple_dimen(mpl, tuple)); info->par = par; info->tuple = tuple; if (par->data == 1) { /* check data, which are provided in the data section, but not checked yet */ /* save pointer to the last array member; note that during the check new members may be added beyond the last member due to references to the same parameter from default expression as well as from expressions that define restricting conditions; however, values assigned to the new members will be checked by other routine, so we don't need to check them here */ MEMBER *tail = par->array->tail; /* change the data status to prevent infinite recursive loop due to references to the same parameter during the check */ par->data = 2; /* check values assigned to array members in the data section until the marked member has been reached */ for (info->memb = par->array->head; info->memb != NULL; info->memb = info->memb->next) { if (eval_within_domain(mpl, par->domain, info->memb->tuple, info, eval_num_func)) out_of_domain(mpl, par->name, info->memb->tuple); if (info->memb == tail) break; } /* the check has been finished */ } /* evaluate member, which has given n-tuple */ info->memb = NULL; if (eval_within_domain(mpl, info->par->domain, info->tuple, info, eval_num_func)) out_of_domain(mpl, par->name, info->tuple); /* bring evaluated value to the calling program */ return info->value; } /*---------------------------------------------------------------------- -- check_value_sym - check symbolic value assigned to parameter member. -- -- This routine checks if symbolic value being assigned to some member -- of specified symbolic model parameter satisfies to all restrictions. -- -- NOTE: This routine must not be called out of domain scope. */ void check_value_sym ( MPL *mpl, PARAMETER *par, /* not changed */ TUPLE *tuple, /* not changed */ SYMBOL *value /* not changed */ ) { CONDITION *cond; WITHIN *in; int eqno; /* the value must satisfy to all specified conditions */ for (cond = par->cond, eqno = 1; cond != NULL; cond = cond->next, eqno++) { SYMBOL *bound; char buf[255+1]; xassert(cond->code != NULL); bound = eval_symbolic(mpl, cond->code); switch (cond->rho) { #if 1 /* 13/VIII-2008 */ case O_LT: if (!(compare_symbols(mpl, value, bound) < 0)) { strcpy(buf, format_symbol(mpl, bound)); xassert(strlen(buf) < sizeof(buf)); error(mpl, "%s%s = %s not < %s", par->name, format_tuple(mpl, '[', tuple), format_symbol(mpl, value), buf, eqno); } break; case O_LE: if (!(compare_symbols(mpl, value, bound) <= 0)) { strcpy(buf, format_symbol(mpl, bound)); xassert(strlen(buf) < sizeof(buf)); error(mpl, "%s%s = %s not <= %s", par->name, format_tuple(mpl, '[', tuple), format_symbol(mpl, value), buf, eqno); } break; #endif case O_EQ: if (!(compare_symbols(mpl, value, bound) == 0)) { strcpy(buf, format_symbol(mpl, bound)); xassert(strlen(buf) < sizeof(buf)); error(mpl, "%s%s = %s not = %s", par->name, format_tuple(mpl, '[', tuple), format_symbol(mpl, value), buf, eqno); } break; #if 1 /* 13/VIII-2008 */ case O_GE: if (!(compare_symbols(mpl, value, bound) >= 0)) { strcpy(buf, format_symbol(mpl, bound)); xassert(strlen(buf) < sizeof(buf)); error(mpl, "%s%s = %s not >= %s", par->name, format_tuple(mpl, '[', tuple), format_symbol(mpl, value), buf, eqno); } break; case O_GT: if (!(compare_symbols(mpl, value, bound) > 0)) { strcpy(buf, format_symbol(mpl, bound)); xassert(strlen(buf) < sizeof(buf)); error(mpl, "%s%s = %s not > %s", par->name, format_tuple(mpl, '[', tuple), format_symbol(mpl, value), buf, eqno); } break; #endif case O_NE: if (!(compare_symbols(mpl, value, bound) != 0)) { strcpy(buf, format_symbol(mpl, bound)); xassert(strlen(buf) < sizeof(buf)); error(mpl, "%s%s = %s not <> %s", par->name, format_tuple(mpl, '[', tuple), format_symbol(mpl, value), buf, eqno); } break; default: xassert(cond != cond); } delete_symbol(mpl, bound); } /* the value must be in all specified supersets */ for (in = par->in, eqno = 1; in != NULL; in = in->next, eqno++) { TUPLE *dummy; xassert(in->code != NULL); xassert(in->code->dim == 1); dummy = expand_tuple(mpl, create_tuple(mpl), copy_symbol(mpl, value)); if (!is_member(mpl, in->code, dummy)) error(mpl, "%s%s = %s not in specified set; see (%d)", par->name, format_tuple(mpl, '[', tuple), format_symbol(mpl, value), eqno); delete_tuple(mpl, dummy); } return; } /*---------------------------------------------------------------------- -- take_member_sym - obtain symb. value assigned to parameter member. -- -- This routine obtains a symbolic value assigned to member of specified -- symbolic model parameter and returns it on exit. -- -- NOTE: This routine must not be called out of domain scope. */ SYMBOL *take_member_sym /* returns value, not reference */ ( MPL *mpl, PARAMETER *par, /* not changed */ TUPLE *tuple /* not changed */ ) { MEMBER *memb; SYMBOL *value; /* find member in the parameter array */ memb = find_member(mpl, par->array, tuple); if (memb != NULL) { /* member exists, so just take its value */ value = copy_symbol(mpl, memb->value.sym); } else if (par->assign != NULL) { /* compute value using assignment expression */ value = eval_symbolic(mpl, par->assign); add: /* check that the value satisfies to all restrictions, assign it to new member, and add the member to the array */ check_value_sym(mpl, par, tuple, value); memb = add_member(mpl, par->array, copy_tuple(mpl, tuple)); memb->value.sym = copy_symbol(mpl, value); } else if (par->option != NULL) { /* compute default value */ value = eval_symbolic(mpl, par->option); goto add; } else if (par->defval != NULL) { /* take default value provided in the data section */ value = copy_symbol(mpl, par->defval); goto add; } else { /* no value is provided */ error(mpl, "no value for %s%s", par->name, format_tuple(mpl, '[', tuple)); } return value; } /*---------------------------------------------------------------------- -- eval_member_sym - evaluate symb. value assigned to parameter member. -- -- This routine evaluates a symbolic value assigned to given member of -- specified symbolic model parameter and returns it on exit. */ struct eval_sym_info { /* working info used by the routine eval_member_sym */ PARAMETER *par; /* model parameter */ TUPLE *tuple; /* n-tuple, which defines parameter member */ MEMBER *memb; /* normally this pointer is NULL; the routine uses this pointer to check data provided in the data section, in which case it points to a member currently checked; this check is performed automatically only once when a reference to any member occurs for the first time */ SYMBOL *value; /* evaluated symbolic value */ }; static void eval_sym_func(MPL *mpl, void *_info) { /* this is auxiliary routine to work within domain scope */ struct eval_sym_info *info = _info; if (info->memb != NULL) { /* checking call; check symbolic value being assigned */ check_value_sym(mpl, info->par, info->memb->tuple, info->memb->value.sym); } else { /* normal call; evaluate member, which has given n-tuple */ info->value = take_member_sym(mpl, info->par, info->tuple); } return; } SYMBOL *eval_member_sym /* returns value, not reference */ ( MPL *mpl, PARAMETER *par, /* not changed */ TUPLE *tuple /* not changed */ ) { /* this routine evaluates symbolic parameter member */ struct eval_sym_info _info, *info = &_info; xassert(par->type == A_SYMBOLIC); xassert(par->dim == tuple_dimen(mpl, tuple)); info->par = par; info->tuple = tuple; if (par->data == 1) { /* check data, which are provided in the data section, but not checked yet */ /* save pointer to the last array member; note that during the check new members may be added beyond the last member due to references to the same parameter from default expression as well as from expressions that define restricting conditions; however, values assigned to the new members will be checked by other routine, so we don't need to check them here */ MEMBER *tail = par->array->tail; /* change the data status to prevent infinite recursive loop due to references to the same parameter during the check */ par->data = 2; /* check values assigned to array members in the data section until the marked member has been reached */ for (info->memb = par->array->head; info->memb != NULL; info->memb = info->memb->next) { if (eval_within_domain(mpl, par->domain, info->memb->tuple, info, eval_sym_func)) out_of_domain(mpl, par->name, info->memb->tuple); if (info->memb == tail) break; } /* the check has been finished */ } /* evaluate member, which has given n-tuple */ info->memb = NULL; if (eval_within_domain(mpl, info->par->domain, info->tuple, info, eval_sym_func)) out_of_domain(mpl, par->name, info->tuple); /* bring evaluated value to the calling program */ return info->value; } /*---------------------------------------------------------------------- -- eval_whole_par - evaluate model parameter over entire domain. -- -- This routine evaluates all members of specified model parameter over -- entire domain. */ static int whole_par_func(MPL *mpl, void *info) { /* this is auxiliary routine to work within domain scope */ PARAMETER *par = (PARAMETER *)info; TUPLE *tuple = get_domain_tuple(mpl, par->domain); switch (par->type) { case A_NUMERIC: case A_INTEGER: case A_BINARY: eval_member_num(mpl, par, tuple); break; case A_SYMBOLIC: delete_symbol(mpl, eval_member_sym(mpl, par, tuple)); break; default: xassert(par != par); } delete_tuple(mpl, tuple); return 0; } void eval_whole_par(MPL *mpl, PARAMETER *par) { loop_within_domain(mpl, par->domain, par, whole_par_func); return; } /*---------------------------------------------------------------------- -- clean_parameter - clean model parameter. -- -- This routine cleans specified model parameter that assumes deleting -- all stuff dynamically allocated during the generation phase. */ void clean_parameter(MPL *mpl, PARAMETER *par) { CONDITION *cond; WITHIN *in; MEMBER *memb; /* clean subscript domain */ clean_domain(mpl, par->domain); /* clean pseudo-code for computing restricting conditions */ for (cond = par->cond; cond != NULL; cond = cond->next) clean_code(mpl, cond->code); /* clean pseudo-code for computing restricting supersets */ for (in = par->in; in != NULL; in = in->next) clean_code(mpl, in->code); /* clean pseudo-code for computing assigned value */ clean_code(mpl, par->assign); /* clean pseudo-code for computing default value */ clean_code(mpl, par->option); /* reset data status flag */ par->data = 0; /* delete default symbolic value */ if (par->defval != NULL) delete_symbol(mpl, par->defval), par->defval = NULL; /* delete content array */ for (memb = par->array->head; memb != NULL; memb = memb->next) delete_value(mpl, par->array->type, &memb->value); delete_array(mpl, par->array), par->array = NULL; return; } /**********************************************************************/ /* * * MODEL VARIABLES * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- take_member_var - obtain reference to elemental variable. -- -- This routine obtains a reference to elemental variable assigned to -- given member of specified model variable and returns it on exit. If -- necessary, new elemental variable is created. -- -- NOTE: This routine must not be called out of domain scope. */ ELEMVAR *take_member_var /* returns reference */ ( MPL *mpl, VARIABLE *var, /* not changed */ TUPLE *tuple /* not changed */ ) { MEMBER *memb; ELEMVAR *refer; /* find member in the variable array */ memb = find_member(mpl, var->array, tuple); if (memb != NULL) { /* member exists, so just take the reference */ refer = memb->value.var; } else { /* member is referenced for the first time and therefore does not exist; create new elemental variable, assign it to new member, and add the member to the variable array */ memb = add_member(mpl, var->array, copy_tuple(mpl, tuple)); refer = (memb->value.var = dmp_get_atom(mpl->elemvars, sizeof(ELEMVAR))); refer->j = 0; refer->var = var; refer->memb = memb; /* compute lower bound */ if (var->lbnd == NULL) refer->lbnd = 0.0; else refer->lbnd = eval_numeric(mpl, var->lbnd); /* compute upper bound */ if (var->ubnd == NULL) refer->ubnd = 0.0; else if (var->ubnd == var->lbnd) refer->ubnd = refer->lbnd; else refer->ubnd = eval_numeric(mpl, var->ubnd); /* nullify working quantity */ refer->temp = 0.0; #if 1 /* 15/V-2010 */ /* solution has not been obtained by the solver yet */ refer->stat = 0; refer->prim = refer->dual = 0.0; #endif } return refer; } /*---------------------------------------------------------------------- -- eval_member_var - evaluate reference to elemental variable. -- -- This routine evaluates a reference to elemental variable assigned to -- member of specified model variable and returns it on exit. */ struct eval_var_info { /* working info used by the routine eval_member_var */ VARIABLE *var; /* model variable */ TUPLE *tuple; /* n-tuple, which defines variable member */ ELEMVAR *refer; /* evaluated reference to elemental variable */ }; static void eval_var_func(MPL *mpl, void *_info) { /* this is auxiliary routine to work within domain scope */ struct eval_var_info *info = _info; info->refer = take_member_var(mpl, info->var, info->tuple); return; } ELEMVAR *eval_member_var /* returns reference */ ( MPL *mpl, VARIABLE *var, /* not changed */ TUPLE *tuple /* not changed */ ) { /* this routine evaluates variable member */ struct eval_var_info _info, *info = &_info; xassert(var->dim == tuple_dimen(mpl, tuple)); info->var = var; info->tuple = tuple; /* evaluate member, which has given n-tuple */ if (eval_within_domain(mpl, info->var->domain, info->tuple, info, eval_var_func)) out_of_domain(mpl, var->name, info->tuple); /* bring evaluated reference to the calling program */ return info->refer; } /*---------------------------------------------------------------------- -- eval_whole_var - evaluate model variable over entire domain. -- -- This routine evaluates all members of specified model variable over -- entire domain. */ static int whole_var_func(MPL *mpl, void *info) { /* this is auxiliary routine to work within domain scope */ VARIABLE *var = (VARIABLE *)info; TUPLE *tuple = get_domain_tuple(mpl, var->domain); eval_member_var(mpl, var, tuple); delete_tuple(mpl, tuple); return 0; } void eval_whole_var(MPL *mpl, VARIABLE *var) { loop_within_domain(mpl, var->domain, var, whole_var_func); return; } /*---------------------------------------------------------------------- -- clean_variable - clean model variable. -- -- This routine cleans specified model variable that assumes deleting -- all stuff dynamically allocated during the generation phase. */ void clean_variable(MPL *mpl, VARIABLE *var) { MEMBER *memb; /* clean subscript domain */ clean_domain(mpl, var->domain); /* clean code for computing lower bound */ clean_code(mpl, var->lbnd); /* clean code for computing upper bound */ if (var->ubnd != var->lbnd) clean_code(mpl, var->ubnd); /* delete content array */ for (memb = var->array->head; memb != NULL; memb = memb->next) dmp_free_atom(mpl->elemvars, memb->value.var, sizeof(ELEMVAR)); delete_array(mpl, var->array), var->array = NULL; return; } /**********************************************************************/ /* * * MODEL CONSTRAINTS AND OBJECTIVES * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- take_member_con - obtain reference to elemental constraint. -- -- This routine obtains a reference to elemental constraint assigned -- to given member of specified model constraint and returns it on exit. -- If necessary, new elemental constraint is created. -- -- NOTE: This routine must not be called out of domain scope. */ ELEMCON *take_member_con /* returns reference */ ( MPL *mpl, CONSTRAINT *con, /* not changed */ TUPLE *tuple /* not changed */ ) { MEMBER *memb; ELEMCON *refer; /* find member in the constraint array */ memb = find_member(mpl, con->array, tuple); if (memb != NULL) { /* member exists, so just take the reference */ refer = memb->value.con; } else { /* member is referenced for the first time and therefore does not exist; create new elemental constraint, assign it to new member, and add the member to the constraint array */ memb = add_member(mpl, con->array, copy_tuple(mpl, tuple)); refer = (memb->value.con = dmp_get_atom(mpl->elemcons, sizeof(ELEMCON))); refer->i = 0; refer->con = con; refer->memb = memb; /* compute linear form */ xassert(con->code != NULL); refer->form = eval_formula(mpl, con->code); /* compute lower and upper bounds */ if (con->lbnd == NULL && con->ubnd == NULL) { /* objective has no bounds */ double temp; xassert(con->type == A_MINIMIZE || con->type == A_MAXIMIZE); /* carry the constant term to the right-hand side */ refer->form = remove_constant(mpl, refer->form, &temp); refer->lbnd = refer->ubnd = - temp; } else if (con->lbnd != NULL && con->ubnd == NULL) { /* constraint a * x + b >= c * y + d is transformed to the standard form a * x - c * y >= d - b */ double temp; xassert(con->type == A_CONSTRAINT); refer->form = linear_comb(mpl, +1.0, refer->form, -1.0, eval_formula(mpl, con->lbnd)); refer->form = remove_constant(mpl, refer->form, &temp); refer->lbnd = - temp; refer->ubnd = 0.0; } else if (con->lbnd == NULL && con->ubnd != NULL) { /* constraint a * x + b <= c * y + d is transformed to the standard form a * x - c * y <= d - b */ double temp; xassert(con->type == A_CONSTRAINT); refer->form = linear_comb(mpl, +1.0, refer->form, -1.0, eval_formula(mpl, con->ubnd)); refer->form = remove_constant(mpl, refer->form, &temp); refer->lbnd = 0.0; refer->ubnd = - temp; } else if (con->lbnd == con->ubnd) { /* constraint a * x + b = c * y + d is transformed to the standard form a * x - c * y = d - b */ double temp; xassert(con->type == A_CONSTRAINT); refer->form = linear_comb(mpl, +1.0, refer->form, -1.0, eval_formula(mpl, con->lbnd)); refer->form = remove_constant(mpl, refer->form, &temp); refer->lbnd = refer->ubnd = - temp; } else { /* ranged constraint c <= a * x + b <= d is transformed to the standard form c - b <= a * x <= d - b */ double temp, temp1, temp2; xassert(con->type == A_CONSTRAINT); refer->form = remove_constant(mpl, refer->form, &temp); xassert(remove_constant(mpl, eval_formula(mpl, con->lbnd), &temp1) == NULL); xassert(remove_constant(mpl, eval_formula(mpl, con->ubnd), &temp2) == NULL); refer->lbnd = fp_sub(mpl, temp1, temp); refer->ubnd = fp_sub(mpl, temp2, temp); } #if 1 /* 15/V-2010 */ /* solution has not been obtained by the solver yet */ refer->stat = 0; refer->prim = refer->dual = 0.0; #endif } return refer; } /*---------------------------------------------------------------------- -- eval_member_con - evaluate reference to elemental constraint. -- -- This routine evaluates a reference to elemental constraint assigned -- to member of specified model constraint and returns it on exit. */ struct eval_con_info { /* working info used by the routine eval_member_con */ CONSTRAINT *con; /* model constraint */ TUPLE *tuple; /* n-tuple, which defines constraint member */ ELEMCON *refer; /* evaluated reference to elemental constraint */ }; static void eval_con_func(MPL *mpl, void *_info) { /* this is auxiliary routine to work within domain scope */ struct eval_con_info *info = _info; info->refer = take_member_con(mpl, info->con, info->tuple); return; } ELEMCON *eval_member_con /* returns reference */ ( MPL *mpl, CONSTRAINT *con, /* not changed */ TUPLE *tuple /* not changed */ ) { /* this routine evaluates constraint member */ struct eval_con_info _info, *info = &_info; xassert(con->dim == tuple_dimen(mpl, tuple)); info->con = con; info->tuple = tuple; /* evaluate member, which has given n-tuple */ if (eval_within_domain(mpl, info->con->domain, info->tuple, info, eval_con_func)) out_of_domain(mpl, con->name, info->tuple); /* bring evaluated reference to the calling program */ return info->refer; } /*---------------------------------------------------------------------- -- eval_whole_con - evaluate model constraint over entire domain. -- -- This routine evaluates all members of specified model constraint over -- entire domain. */ static int whole_con_func(MPL *mpl, void *info) { /* this is auxiliary routine to work within domain scope */ CONSTRAINT *con = (CONSTRAINT *)info; TUPLE *tuple = get_domain_tuple(mpl, con->domain); eval_member_con(mpl, con, tuple); delete_tuple(mpl, tuple); return 0; } void eval_whole_con(MPL *mpl, CONSTRAINT *con) { loop_within_domain(mpl, con->domain, con, whole_con_func); return; } /*---------------------------------------------------------------------- -- clean_constraint - clean model constraint. -- -- This routine cleans specified model constraint that assumes deleting -- all stuff dynamically allocated during the generation phase. */ void clean_constraint(MPL *mpl, CONSTRAINT *con) { MEMBER *memb; /* clean subscript domain */ clean_domain(mpl, con->domain); /* clean code for computing main linear form */ clean_code(mpl, con->code); /* clean code for computing lower bound */ clean_code(mpl, con->lbnd); /* clean code for computing upper bound */ if (con->ubnd != con->lbnd) clean_code(mpl, con->ubnd); /* delete content array */ for (memb = con->array->head; memb != NULL; memb = memb->next) { delete_formula(mpl, memb->value.con->form); dmp_free_atom(mpl->elemcons, memb->value.con, sizeof(ELEMCON)); } delete_array(mpl, con->array), con->array = NULL; return; } /**********************************************************************/ /* * * PSEUDO-CODE * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- eval_numeric - evaluate pseudo-code to determine numeric value. -- -- This routine evaluates specified pseudo-code to determine resultant -- numeric value, which is returned on exit. */ struct iter_num_info { /* working info used by the routine iter_num_func */ CODE *code; /* pseudo-code for iterated operation to be performed */ double value; /* resultant value */ }; static int iter_num_func(MPL *mpl, void *_info) { /* this is auxiliary routine used to perform iterated operation on numeric "integrand" within domain scope */ struct iter_num_info *info = _info; double temp; temp = eval_numeric(mpl, info->code->arg.loop.x); switch (info->code->op) { case O_SUM: /* summation over domain */ info->value = fp_add(mpl, info->value, temp); break; case O_PROD: /* multiplication over domain */ info->value = fp_mul(mpl, info->value, temp); break; case O_MINIMUM: /* minimum over domain */ if (info->value > temp) info->value = temp; break; case O_MAXIMUM: /* maximum over domain */ if (info->value < temp) info->value = temp; break; default: xassert(info != info); } return 0; } double eval_numeric(MPL *mpl, CODE *code) { double value; xassert(code != NULL); xassert(code->type == A_NUMERIC); xassert(code->dim == 0); /* if the operation has a side effect, invalidate and delete the resultant value */ if (code->vflag && code->valid) { code->valid = 0; delete_value(mpl, code->type, &code->value); } /* if resultant value is valid, no evaluation is needed */ if (code->valid) { value = code->value.num; goto done; } /* evaluate pseudo-code recursively */ switch (code->op) { case O_NUMBER: /* take floating-point number */ value = code->arg.num; break; case O_MEMNUM: /* take member of numeric parameter */ { TUPLE *tuple; ARG_LIST *e; tuple = create_tuple(mpl); for (e = code->arg.par.list; e != NULL; e = e->next) tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl, e->x)); value = eval_member_num(mpl, code->arg.par.par, tuple); delete_tuple(mpl, tuple); } break; case O_MEMVAR: /* take computed value of elemental variable */ { TUPLE *tuple; ARG_LIST *e; #if 1 /* 15/V-2010 */ ELEMVAR *var; #endif tuple = create_tuple(mpl); for (e = code->arg.var.list; e != NULL; e = e->next) tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl, e->x)); #if 0 /* 15/V-2010 */ value = eval_member_var(mpl, code->arg.var.var, tuple) ->value; #else var = eval_member_var(mpl, code->arg.var.var, tuple); switch (code->arg.var.suff) { case DOT_LB: if (var->var->lbnd == NULL) value = -DBL_MAX; else value = var->lbnd; break; case DOT_UB: if (var->var->ubnd == NULL) value = +DBL_MAX; else value = var->ubnd; break; case DOT_STATUS: value = var->stat; break; case DOT_VAL: value = var->prim; break; case DOT_DUAL: value = var->dual; break; default: xassert(code != code); } #endif delete_tuple(mpl, tuple); } break; #if 1 /* 15/V-2010 */ case O_MEMCON: /* take computed value of elemental constraint */ { TUPLE *tuple; ARG_LIST *e; ELEMCON *con; tuple = create_tuple(mpl); for (e = code->arg.con.list; e != NULL; e = e->next) tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl, e->x)); con = eval_member_con(mpl, code->arg.con.con, tuple); switch (code->arg.con.suff) { case DOT_LB: if (con->con->lbnd == NULL) value = -DBL_MAX; else value = con->lbnd; break; case DOT_UB: if (con->con->ubnd == NULL) value = +DBL_MAX; else value = con->ubnd; break; case DOT_STATUS: value = con->stat; break; case DOT_VAL: value = con->prim; break; case DOT_DUAL: value = con->dual; break; default: xassert(code != code); } delete_tuple(mpl, tuple); } break; #endif case O_IRAND224: /* pseudo-random in [0, 2^24-1] */ value = fp_irand224(mpl); break; case O_UNIFORM01: /* pseudo-random in [0, 1) */ value = fp_uniform01(mpl); break; case O_NORMAL01: /* gaussian random, mu = 0, sigma = 1 */ value = fp_normal01(mpl); break; case O_GMTIME: /* current calendar time */ value = fn_gmtime(mpl); break; case O_CVTNUM: /* conversion to numeric */ { SYMBOL *sym; sym = eval_symbolic(mpl, code->arg.arg.x); #if 0 /* 23/XI-2008 */ if (sym->str != NULL) error(mpl, "cannot convert %s to floating-point numbe" "r", format_symbol(mpl, sym)); value = sym->num; #else if (sym->str == NULL) value = sym->num; else { if (str2num(sym->str, &value)) error(mpl, "cannot convert %s to floating-point nu" "mber", format_symbol(mpl, sym)); } #endif delete_symbol(mpl, sym); } break; case O_PLUS: /* unary plus */ value = + eval_numeric(mpl, code->arg.arg.x); break; case O_MINUS: /* unary minus */ value = - eval_numeric(mpl, code->arg.arg.x); break; case O_ABS: /* absolute value */ value = fabs(eval_numeric(mpl, code->arg.arg.x)); break; case O_CEIL: /* round upward ("ceiling of x") */ value = ceil(eval_numeric(mpl, code->arg.arg.x)); break; case O_FLOOR: /* round downward ("floor of x") */ value = floor(eval_numeric(mpl, code->arg.arg.x)); break; case O_EXP: /* base-e exponential */ value = fp_exp(mpl, eval_numeric(mpl, code->arg.arg.x)); break; case O_LOG: /* natural logarithm */ value = fp_log(mpl, eval_numeric(mpl, code->arg.arg.x)); break; case O_LOG10: /* common (decimal) logarithm */ value = fp_log10(mpl, eval_numeric(mpl, code->arg.arg.x)); break; case O_SQRT: /* square root */ value = fp_sqrt(mpl, eval_numeric(mpl, code->arg.arg.x)); break; case O_SIN: /* trigonometric sine */ value = fp_sin(mpl, eval_numeric(mpl, code->arg.arg.x)); break; case O_COS: /* trigonometric cosine */ value = fp_cos(mpl, eval_numeric(mpl, code->arg.arg.x)); break; case O_ATAN: /* trigonometric arctangent (one argument) */ value = fp_atan(mpl, eval_numeric(mpl, code->arg.arg.x)); break; case O_ATAN2: /* trigonometric arctangent (two arguments) */ value = fp_atan2(mpl, eval_numeric(mpl, code->arg.arg.x), eval_numeric(mpl, code->arg.arg.y)); break; case O_ROUND: /* round to nearest integer */ value = fp_round(mpl, eval_numeric(mpl, code->arg.arg.x), 0.0); break; case O_ROUND2: /* round to n fractional digits */ value = fp_round(mpl, eval_numeric(mpl, code->arg.arg.x), eval_numeric(mpl, code->arg.arg.y)); break; case O_TRUNC: /* truncate to nearest integer */ value = fp_trunc(mpl, eval_numeric(mpl, code->arg.arg.x), 0.0); break; case O_TRUNC2: /* truncate to n fractional digits */ value = fp_trunc(mpl, eval_numeric(mpl, code->arg.arg.x), eval_numeric(mpl, code->arg.arg.y)); break; case O_ADD: /* addition */ value = fp_add(mpl, eval_numeric(mpl, code->arg.arg.x), eval_numeric(mpl, code->arg.arg.y)); break; case O_SUB: /* subtraction */ value = fp_sub(mpl, eval_numeric(mpl, code->arg.arg.x), eval_numeric(mpl, code->arg.arg.y)); break; case O_LESS: /* non-negative subtraction */ value = fp_less(mpl, eval_numeric(mpl, code->arg.arg.x), eval_numeric(mpl, code->arg.arg.y)); break; case O_MUL: /* multiplication */ value = fp_mul(mpl, eval_numeric(mpl, code->arg.arg.x), eval_numeric(mpl, code->arg.arg.y)); break; case O_DIV: /* division */ value = fp_div(mpl, eval_numeric(mpl, code->arg.arg.x), eval_numeric(mpl, code->arg.arg.y)); break; case O_IDIV: /* quotient of exact division */ value = fp_idiv(mpl, eval_numeric(mpl, code->arg.arg.x), eval_numeric(mpl, code->arg.arg.y)); break; case O_MOD: /* remainder of exact division */ value = fp_mod(mpl, eval_numeric(mpl, code->arg.arg.x), eval_numeric(mpl, code->arg.arg.y)); break; case O_POWER: /* exponentiation (raise to power) */ value = fp_power(mpl, eval_numeric(mpl, code->arg.arg.x), eval_numeric(mpl, code->arg.arg.y)); break; case O_UNIFORM: /* pseudo-random in [a, b) */ value = fp_uniform(mpl, eval_numeric(mpl, code->arg.arg.x), eval_numeric(mpl, code->arg.arg.y)); break; case O_NORMAL: /* gaussian random, given mu and sigma */ value = fp_normal(mpl, eval_numeric(mpl, code->arg.arg.x), eval_numeric(mpl, code->arg.arg.y)); break; case O_CARD: { ELEMSET *set; set = eval_elemset(mpl, code->arg.arg.x); value = set->size; delete_array(mpl, set); } break; case O_LENGTH: { SYMBOL *sym; char str[MAX_LENGTH+1]; sym = eval_symbolic(mpl, code->arg.arg.x); if (sym->str == NULL) sprintf(str, "%.*g", DBL_DIG, sym->num); else fetch_string(mpl, sym->str, str); delete_symbol(mpl, sym); value = strlen(str); } break; case O_STR2TIME: { SYMBOL *sym; char str[MAX_LENGTH+1], fmt[MAX_LENGTH+1]; sym = eval_symbolic(mpl, code->arg.arg.x); if (sym->str == NULL) sprintf(str, "%.*g", DBL_DIG, sym->num); else fetch_string(mpl, sym->str, str); delete_symbol(mpl, sym); sym = eval_symbolic(mpl, code->arg.arg.y); if (sym->str == NULL) sprintf(fmt, "%.*g", DBL_DIG, sym->num); else fetch_string(mpl, sym->str, fmt); delete_symbol(mpl, sym); value = fn_str2time(mpl, str, fmt); } break; case O_FORK: /* if-then-else */ if (eval_logical(mpl, code->arg.arg.x)) value = eval_numeric(mpl, code->arg.arg.y); else if (code->arg.arg.z == NULL) value = 0.0; else value = eval_numeric(mpl, code->arg.arg.z); break; case O_MIN: /* minimal value (n-ary) */ { ARG_LIST *e; double temp; value = +DBL_MAX; for (e = code->arg.list; e != NULL; e = e->next) { temp = eval_numeric(mpl, e->x); if (value > temp) value = temp; } } break; case O_MAX: /* maximal value (n-ary) */ { ARG_LIST *e; double temp; value = -DBL_MAX; for (e = code->arg.list; e != NULL; e = e->next) { temp = eval_numeric(mpl, e->x); if (value < temp) value = temp; } } break; case O_SUM: /* summation over domain */ { struct iter_num_info _info, *info = &_info; info->code = code; info->value = 0.0; loop_within_domain(mpl, code->arg.loop.domain, info, iter_num_func); value = info->value; } break; case O_PROD: /* multiplication over domain */ { struct iter_num_info _info, *info = &_info; info->code = code; info->value = 1.0; loop_within_domain(mpl, code->arg.loop.domain, info, iter_num_func); value = info->value; } break; case O_MINIMUM: /* minimum over domain */ { struct iter_num_info _info, *info = &_info; info->code = code; info->value = +DBL_MAX; loop_within_domain(mpl, code->arg.loop.domain, info, iter_num_func); if (info->value == +DBL_MAX) error(mpl, "min{} over empty set; result undefined"); value = info->value; } break; case O_MAXIMUM: /* maximum over domain */ { struct iter_num_info _info, *info = &_info; info->code = code; info->value = -DBL_MAX; loop_within_domain(mpl, code->arg.loop.domain, info, iter_num_func); if (info->value == -DBL_MAX) error(mpl, "max{} over empty set; result undefined"); value = info->value; } break; default: xassert(code != code); } /* save resultant value */ xassert(!code->valid); code->valid = 1; code->value.num = value; done: return value; } /*---------------------------------------------------------------------- -- eval_symbolic - evaluate pseudo-code to determine symbolic value. -- -- This routine evaluates specified pseudo-code to determine resultant -- symbolic value, which is returned on exit. */ SYMBOL *eval_symbolic(MPL *mpl, CODE *code) { SYMBOL *value; xassert(code != NULL); xassert(code->type == A_SYMBOLIC); xassert(code->dim == 0); /* if the operation has a side effect, invalidate and delete the resultant value */ if (code->vflag && code->valid) { code->valid = 0; delete_value(mpl, code->type, &code->value); } /* if resultant value is valid, no evaluation is needed */ if (code->valid) { value = copy_symbol(mpl, code->value.sym); goto done; } /* evaluate pseudo-code recursively */ switch (code->op) { case O_STRING: /* take character string */ value = create_symbol_str(mpl, create_string(mpl, code->arg.str)); break; case O_INDEX: /* take dummy index */ xassert(code->arg.index.slot->value != NULL); value = copy_symbol(mpl, code->arg.index.slot->value); break; case O_MEMSYM: /* take member of symbolic parameter */ { TUPLE *tuple; ARG_LIST *e; tuple = create_tuple(mpl); for (e = code->arg.par.list; e != NULL; e = e->next) tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl, e->x)); value = eval_member_sym(mpl, code->arg.par.par, tuple); delete_tuple(mpl, tuple); } break; case O_CVTSYM: /* conversion to symbolic */ value = create_symbol_num(mpl, eval_numeric(mpl, code->arg.arg.x)); break; case O_CONCAT: /* concatenation */ value = concat_symbols(mpl, eval_symbolic(mpl, code->arg.arg.x), eval_symbolic(mpl, code->arg.arg.y)); break; case O_FORK: /* if-then-else */ if (eval_logical(mpl, code->arg.arg.x)) value = eval_symbolic(mpl, code->arg.arg.y); else if (code->arg.arg.z == NULL) value = create_symbol_num(mpl, 0.0); else value = eval_symbolic(mpl, code->arg.arg.z); break; case O_SUBSTR: case O_SUBSTR3: { double pos, len; char str[MAX_LENGTH+1]; value = eval_symbolic(mpl, code->arg.arg.x); if (value->str == NULL) sprintf(str, "%.*g", DBL_DIG, value->num); else fetch_string(mpl, value->str, str); delete_symbol(mpl, value); if (code->op == O_SUBSTR) { pos = eval_numeric(mpl, code->arg.arg.y); if (pos != floor(pos)) error(mpl, "substr('...', %.*g); non-integer secon" "d argument", DBL_DIG, pos); if (pos < 1 || pos > strlen(str) + 1) error(mpl, "substr('...', %.*g); substring out of " "range", DBL_DIG, pos); } else { pos = eval_numeric(mpl, code->arg.arg.y); len = eval_numeric(mpl, code->arg.arg.z); if (pos != floor(pos) || len != floor(len)) error(mpl, "substr('...', %.*g, %.*g); non-integer" " second and/or third argument", DBL_DIG, pos, DBL_DIG, len); if (pos < 1 || len < 0 || pos + len > strlen(str) + 1) error(mpl, "substr('...', %.*g, %.*g); substring o" "ut of range", DBL_DIG, pos, DBL_DIG, len); str[(int)pos + (int)len - 1] = '\0'; } value = create_symbol_str(mpl, create_string(mpl, str + (int)pos - 1)); } break; case O_TIME2STR: { double num; SYMBOL *sym; char str[MAX_LENGTH+1], fmt[MAX_LENGTH+1]; num = eval_numeric(mpl, code->arg.arg.x); sym = eval_symbolic(mpl, code->arg.arg.y); if (sym->str == NULL) sprintf(fmt, "%.*g", DBL_DIG, sym->num); else fetch_string(mpl, sym->str, fmt); delete_symbol(mpl, sym); fn_time2str(mpl, str, num, fmt); value = create_symbol_str(mpl, create_string(mpl, str)); } break; default: xassert(code != code); } /* save resultant value */ xassert(!code->valid); code->valid = 1; code->value.sym = copy_symbol(mpl, value); done: return value; } /*---------------------------------------------------------------------- -- eval_logical - evaluate pseudo-code to determine logical value. -- -- This routine evaluates specified pseudo-code to determine resultant -- logical value, which is returned on exit. */ struct iter_log_info { /* working info used by the routine iter_log_func */ CODE *code; /* pseudo-code for iterated operation to be performed */ int value; /* resultant value */ }; static int iter_log_func(MPL *mpl, void *_info) { /* this is auxiliary routine used to perform iterated operation on logical "integrand" within domain scope */ struct iter_log_info *info = _info; int ret = 0; switch (info->code->op) { case O_FORALL: /* conjunction over domain */ info->value &= eval_logical(mpl, info->code->arg.loop.x); if (!info->value) ret = 1; break; case O_EXISTS: /* disjunction over domain */ info->value |= eval_logical(mpl, info->code->arg.loop.x); if (info->value) ret = 1; break; default: xassert(info != info); } return ret; } int eval_logical(MPL *mpl, CODE *code) { int value; xassert(code->type == A_LOGICAL); xassert(code->dim == 0); /* if the operation has a side effect, invalidate and delete the resultant value */ if (code->vflag && code->valid) { code->valid = 0; delete_value(mpl, code->type, &code->value); } /* if resultant value is valid, no evaluation is needed */ if (code->valid) { value = code->value.bit; goto done; } /* evaluate pseudo-code recursively */ switch (code->op) { case O_CVTLOG: /* conversion to logical */ value = (eval_numeric(mpl, code->arg.arg.x) != 0.0); break; case O_NOT: /* negation (logical "not") */ value = !eval_logical(mpl, code->arg.arg.x); break; case O_LT: /* comparison on 'less than' */ #if 0 /* 02/VIII-2008 */ value = (eval_numeric(mpl, code->arg.arg.x) < eval_numeric(mpl, code->arg.arg.y)); #else xassert(code->arg.arg.x != NULL); if (code->arg.arg.x->type == A_NUMERIC) value = (eval_numeric(mpl, code->arg.arg.x) < eval_numeric(mpl, code->arg.arg.y)); else { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x); SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y); value = (compare_symbols(mpl, sym1, sym2) < 0); delete_symbol(mpl, sym1); delete_symbol(mpl, sym2); } #endif break; case O_LE: /* comparison on 'not greater than' */ #if 0 /* 02/VIII-2008 */ value = (eval_numeric(mpl, code->arg.arg.x) <= eval_numeric(mpl, code->arg.arg.y)); #else xassert(code->arg.arg.x != NULL); if (code->arg.arg.x->type == A_NUMERIC) value = (eval_numeric(mpl, code->arg.arg.x) <= eval_numeric(mpl, code->arg.arg.y)); else { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x); SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y); value = (compare_symbols(mpl, sym1, sym2) <= 0); delete_symbol(mpl, sym1); delete_symbol(mpl, sym2); } #endif break; case O_EQ: /* comparison on 'equal to' */ xassert(code->arg.arg.x != NULL); if (code->arg.arg.x->type == A_NUMERIC) value = (eval_numeric(mpl, code->arg.arg.x) == eval_numeric(mpl, code->arg.arg.y)); else { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x); SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y); value = (compare_symbols(mpl, sym1, sym2) == 0); delete_symbol(mpl, sym1); delete_symbol(mpl, sym2); } break; case O_GE: /* comparison on 'not less than' */ #if 0 /* 02/VIII-2008 */ value = (eval_numeric(mpl, code->arg.arg.x) >= eval_numeric(mpl, code->arg.arg.y)); #else xassert(code->arg.arg.x != NULL); if (code->arg.arg.x->type == A_NUMERIC) value = (eval_numeric(mpl, code->arg.arg.x) >= eval_numeric(mpl, code->arg.arg.y)); else { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x); SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y); value = (compare_symbols(mpl, sym1, sym2) >= 0); delete_symbol(mpl, sym1); delete_symbol(mpl, sym2); } #endif break; case O_GT: /* comparison on 'greater than' */ #if 0 /* 02/VIII-2008 */ value = (eval_numeric(mpl, code->arg.arg.x) > eval_numeric(mpl, code->arg.arg.y)); #else xassert(code->arg.arg.x != NULL); if (code->arg.arg.x->type == A_NUMERIC) value = (eval_numeric(mpl, code->arg.arg.x) > eval_numeric(mpl, code->arg.arg.y)); else { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x); SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y); value = (compare_symbols(mpl, sym1, sym2) > 0); delete_symbol(mpl, sym1); delete_symbol(mpl, sym2); } #endif break; case O_NE: /* comparison on 'not equal to' */ xassert(code->arg.arg.x != NULL); if (code->arg.arg.x->type == A_NUMERIC) value = (eval_numeric(mpl, code->arg.arg.x) != eval_numeric(mpl, code->arg.arg.y)); else { SYMBOL *sym1 = eval_symbolic(mpl, code->arg.arg.x); SYMBOL *sym2 = eval_symbolic(mpl, code->arg.arg.y); value = (compare_symbols(mpl, sym1, sym2) != 0); delete_symbol(mpl, sym1); delete_symbol(mpl, sym2); } break; case O_AND: /* conjunction (logical "and") */ value = eval_logical(mpl, code->arg.arg.x) && eval_logical(mpl, code->arg.arg.y); break; case O_OR: /* disjunction (logical "or") */ value = eval_logical(mpl, code->arg.arg.x) || eval_logical(mpl, code->arg.arg.y); break; case O_IN: /* test on 'x in Y' */ { TUPLE *tuple; tuple = eval_tuple(mpl, code->arg.arg.x); value = is_member(mpl, code->arg.arg.y, tuple); delete_tuple(mpl, tuple); } break; case O_NOTIN: /* test on 'x not in Y' */ { TUPLE *tuple; tuple = eval_tuple(mpl, code->arg.arg.x); value = !is_member(mpl, code->arg.arg.y, tuple); delete_tuple(mpl, tuple); } break; case O_WITHIN: /* test on 'X within Y' */ { ELEMSET *set; MEMBER *memb; set = eval_elemset(mpl, code->arg.arg.x); value = 1; for (memb = set->head; memb != NULL; memb = memb->next) { if (!is_member(mpl, code->arg.arg.y, memb->tuple)) { value = 0; break; } } delete_elemset(mpl, set); } break; case O_NOTWITHIN: /* test on 'X not within Y' */ { ELEMSET *set; MEMBER *memb; set = eval_elemset(mpl, code->arg.arg.x); value = 1; for (memb = set->head; memb != NULL; memb = memb->next) { if (is_member(mpl, code->arg.arg.y, memb->tuple)) { value = 0; break; } } delete_elemset(mpl, set); } break; case O_FORALL: /* conjunction (A-quantification) */ { struct iter_log_info _info, *info = &_info; info->code = code; info->value = 1; loop_within_domain(mpl, code->arg.loop.domain, info, iter_log_func); value = info->value; } break; case O_EXISTS: /* disjunction (E-quantification) */ { struct iter_log_info _info, *info = &_info; info->code = code; info->value = 0; loop_within_domain(mpl, code->arg.loop.domain, info, iter_log_func); value = info->value; } break; default: xassert(code != code); } /* save resultant value */ xassert(!code->valid); code->valid = 1; code->value.bit = value; done: return value; } /*---------------------------------------------------------------------- -- eval_tuple - evaluate pseudo-code to construct n-tuple. -- -- This routine evaluates specified pseudo-code to construct resultant -- n-tuple, which is returned on exit. */ TUPLE *eval_tuple(MPL *mpl, CODE *code) { TUPLE *value; xassert(code != NULL); xassert(code->type == A_TUPLE); xassert(code->dim > 0); /* if the operation has a side effect, invalidate and delete the resultant value */ if (code->vflag && code->valid) { code->valid = 0; delete_value(mpl, code->type, &code->value); } /* if resultant value is valid, no evaluation is needed */ if (code->valid) { value = copy_tuple(mpl, code->value.tuple); goto done; } /* evaluate pseudo-code recursively */ switch (code->op) { case O_TUPLE: /* make n-tuple */ { ARG_LIST *e; value = create_tuple(mpl); for (e = code->arg.list; e != NULL; e = e->next) value = expand_tuple(mpl, value, eval_symbolic(mpl, e->x)); } break; case O_CVTTUP: /* convert to 1-tuple */ value = expand_tuple(mpl, create_tuple(mpl), eval_symbolic(mpl, code->arg.arg.x)); break; default: xassert(code != code); } /* save resultant value */ xassert(!code->valid); code->valid = 1; code->value.tuple = copy_tuple(mpl, value); done: return value; } /*---------------------------------------------------------------------- -- eval_elemset - evaluate pseudo-code to construct elemental set. -- -- This routine evaluates specified pseudo-code to construct resultant -- elemental set, which is returned on exit. */ struct iter_set_info { /* working info used by the routine iter_set_func */ CODE *code; /* pseudo-code for iterated operation to be performed */ ELEMSET *value; /* resultant value */ }; static int iter_set_func(MPL *mpl, void *_info) { /* this is auxiliary routine used to perform iterated operation on n-tuple "integrand" within domain scope */ struct iter_set_info *info = _info; TUPLE *tuple; switch (info->code->op) { case O_SETOF: /* compute next n-tuple and add it to the set; in this case duplicate n-tuples are silently ignored */ tuple = eval_tuple(mpl, info->code->arg.loop.x); if (find_tuple(mpl, info->value, tuple) == NULL) add_tuple(mpl, info->value, tuple); else delete_tuple(mpl, tuple); break; case O_BUILD: /* construct next n-tuple using current values assigned to *free* dummy indices as its components and add it to the set; in this case duplicate n-tuples cannot appear */ add_tuple(mpl, info->value, get_domain_tuple(mpl, info->code->arg.loop.domain)); break; default: xassert(info != info); } return 0; } ELEMSET *eval_elemset(MPL *mpl, CODE *code) { ELEMSET *value; xassert(code != NULL); xassert(code->type == A_ELEMSET); xassert(code->dim > 0); /* if the operation has a side effect, invalidate and delete the resultant value */ if (code->vflag && code->valid) { code->valid = 0; delete_value(mpl, code->type, &code->value); } /* if resultant value is valid, no evaluation is needed */ if (code->valid) { value = copy_elemset(mpl, code->value.set); goto done; } /* evaluate pseudo-code recursively */ switch (code->op) { case O_MEMSET: /* take member of set */ { TUPLE *tuple; ARG_LIST *e; tuple = create_tuple(mpl); for (e = code->arg.set.list; e != NULL; e = e->next) tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl, e->x)); value = copy_elemset(mpl, eval_member_set(mpl, code->arg.set.set, tuple)); delete_tuple(mpl, tuple); } break; case O_MAKE: /* make elemental set of n-tuples */ { ARG_LIST *e; value = create_elemset(mpl, code->dim); for (e = code->arg.list; e != NULL; e = e->next) check_then_add(mpl, value, eval_tuple(mpl, e->x)); } break; case O_UNION: /* union of two elemental sets */ value = set_union(mpl, eval_elemset(mpl, code->arg.arg.x), eval_elemset(mpl, code->arg.arg.y)); break; case O_DIFF: /* difference between two elemental sets */ value = set_diff(mpl, eval_elemset(mpl, code->arg.arg.x), eval_elemset(mpl, code->arg.arg.y)); break; case O_SYMDIFF: /* symmetric difference between two elemental sets */ value = set_symdiff(mpl, eval_elemset(mpl, code->arg.arg.x), eval_elemset(mpl, code->arg.arg.y)); break; case O_INTER: /* intersection of two elemental sets */ value = set_inter(mpl, eval_elemset(mpl, code->arg.arg.x), eval_elemset(mpl, code->arg.arg.y)); break; case O_CROSS: /* cross (Cartesian) product of two elemental sets */ value = set_cross(mpl, eval_elemset(mpl, code->arg.arg.x), eval_elemset(mpl, code->arg.arg.y)); break; case O_DOTS: /* build "arithmetic" elemental set */ value = create_arelset(mpl, eval_numeric(mpl, code->arg.arg.x), eval_numeric(mpl, code->arg.arg.y), code->arg.arg.z == NULL ? 1.0 : eval_numeric(mpl, code->arg.arg.z)); break; case O_FORK: /* if-then-else */ if (eval_logical(mpl, code->arg.arg.x)) value = eval_elemset(mpl, code->arg.arg.y); else value = eval_elemset(mpl, code->arg.arg.z); break; case O_SETOF: /* compute elemental set */ { struct iter_set_info _info, *info = &_info; info->code = code; info->value = create_elemset(mpl, code->dim); loop_within_domain(mpl, code->arg.loop.domain, info, iter_set_func); value = info->value; } break; case O_BUILD: /* build elemental set identical to domain set */ { struct iter_set_info _info, *info = &_info; info->code = code; info->value = create_elemset(mpl, code->dim); loop_within_domain(mpl, code->arg.loop.domain, info, iter_set_func); value = info->value; } break; default: xassert(code != code); } /* save resultant value */ xassert(!code->valid); code->valid = 1; code->value.set = copy_elemset(mpl, value); done: return value; } /*---------------------------------------------------------------------- -- is_member - check if n-tuple is in set specified by pseudo-code. -- -- This routine checks if given n-tuple is a member of elemental set -- specified in the form of pseudo-code (i.e. by expression). -- -- The n-tuple may have more components that dimension of the elemental -- set, in which case the extra components are ignored. */ static void null_func(MPL *mpl, void *info) { /* this is dummy routine used to enter the domain scope */ xassert(mpl == mpl); xassert(info == NULL); return; } int is_member(MPL *mpl, CODE *code, TUPLE *tuple) { int value; xassert(code != NULL); xassert(code->type == A_ELEMSET); xassert(code->dim > 0); xassert(tuple != NULL); switch (code->op) { case O_MEMSET: /* check if given n-tuple is member of elemental set, which is assigned to member of model set */ { ARG_LIST *e; TUPLE *temp; ELEMSET *set; /* evaluate reference to elemental set */ temp = create_tuple(mpl); for (e = code->arg.set.list; e != NULL; e = e->next) temp = expand_tuple(mpl, temp, eval_symbolic(mpl, e->x)); set = eval_member_set(mpl, code->arg.set.set, temp); delete_tuple(mpl, temp); /* check if the n-tuple is contained in the set array */ temp = build_subtuple(mpl, tuple, set->dim); value = (find_tuple(mpl, set, temp) != NULL); delete_tuple(mpl, temp); } break; case O_MAKE: /* check if given n-tuple is member of literal set */ { ARG_LIST *e; TUPLE *temp, *that; value = 0; temp = build_subtuple(mpl, tuple, code->dim); for (e = code->arg.list; e != NULL; e = e->next) { that = eval_tuple(mpl, e->x); value = (compare_tuples(mpl, temp, that) == 0); delete_tuple(mpl, that); if (value) break; } delete_tuple(mpl, temp); } break; case O_UNION: value = is_member(mpl, code->arg.arg.x, tuple) || is_member(mpl, code->arg.arg.y, tuple); break; case O_DIFF: value = is_member(mpl, code->arg.arg.x, tuple) && !is_member(mpl, code->arg.arg.y, tuple); break; case O_SYMDIFF: { int in1 = is_member(mpl, code->arg.arg.x, tuple); int in2 = is_member(mpl, code->arg.arg.y, tuple); value = (in1 && !in2) || (!in1 && in2); } break; case O_INTER: value = is_member(mpl, code->arg.arg.x, tuple) && is_member(mpl, code->arg.arg.y, tuple); break; case O_CROSS: { int j; value = is_member(mpl, code->arg.arg.x, tuple); if (value) { for (j = 1; j <= code->arg.arg.x->dim; j++) { xassert(tuple != NULL); tuple = tuple->next; } value = is_member(mpl, code->arg.arg.y, tuple); } } break; case O_DOTS: /* check if given 1-tuple is member of "arithmetic" set */ { int j; double x, t0, tf, dt; xassert(code->dim == 1); /* compute "parameters" of the "arithmetic" set */ t0 = eval_numeric(mpl, code->arg.arg.x); tf = eval_numeric(mpl, code->arg.arg.y); if (code->arg.arg.z == NULL) dt = 1.0; else dt = eval_numeric(mpl, code->arg.arg.z); /* make sure the parameters are correct */ arelset_size(mpl, t0, tf, dt); /* if component of 1-tuple is symbolic, not numeric, the 1-tuple cannot be member of "arithmetic" set */ xassert(tuple->sym != NULL); if (tuple->sym->str != NULL) { value = 0; break; } /* determine numeric value of the component */ x = tuple->sym->num; /* if the component value is out of the set range, the 1-tuple is not in the set */ if (dt > 0.0 && !(t0 <= x && x <= tf) || dt < 0.0 && !(tf <= x && x <= t0)) { value = 0; break; } /* estimate ordinal number of the 1-tuple in the set */ j = (int)(((x - t0) / dt) + 0.5) + 1; /* perform the main check */ value = (arelset_member(mpl, t0, tf, dt, j) == x); } break; case O_FORK: /* check if given n-tuple is member of conditional set */ if (eval_logical(mpl, code->arg.arg.x)) value = is_member(mpl, code->arg.arg.y, tuple); else value = is_member(mpl, code->arg.arg.z, tuple); break; case O_SETOF: /* check if given n-tuple is member of computed set */ /* it is not clear how to efficiently perform the check not computing the entire elemental set :+( */ error(mpl, "implementation restriction; in/within setof{} n" "ot allowed"); break; case O_BUILD: /* check if given n-tuple is member of domain set */ { TUPLE *temp; temp = build_subtuple(mpl, tuple, code->dim); /* try to enter the domain scope; if it is successful, the n-tuple is in the domain set */ value = (eval_within_domain(mpl, code->arg.loop.domain, temp, NULL, null_func) == 0); delete_tuple(mpl, temp); } break; default: xassert(code != code); } return value; } /*---------------------------------------------------------------------- -- eval_formula - evaluate pseudo-code to construct linear form. -- -- This routine evaluates specified pseudo-code to construct resultant -- linear form, which is returned on exit. */ struct iter_form_info { /* working info used by the routine iter_form_func */ CODE *code; /* pseudo-code for iterated operation to be performed */ FORMULA *value; /* resultant value */ FORMULA *tail; /* pointer to the last term */ }; static int iter_form_func(MPL *mpl, void *_info) { /* this is auxiliary routine used to perform iterated operation on linear form "integrand" within domain scope */ struct iter_form_info *info = _info; switch (info->code->op) { case O_SUM: /* summation over domain */ #if 0 info->value = linear_comb(mpl, +1.0, info->value, +1.0, eval_formula(mpl, info->code->arg.loop.x)); #else /* the routine linear_comb needs to look through all terms of both linear forms to reduce identical terms, so using it here is not a good idea (for example, evaluation of sum{i in 1..n} x[i] required quadratic time); the better idea is to gather all terms of the integrand in one list and reduce identical terms only once after all terms of the resultant linear form have been evaluated */ { FORMULA *form, *term; form = eval_formula(mpl, info->code->arg.loop.x); if (info->value == NULL) { xassert(info->tail == NULL); info->value = form; } else { xassert(info->tail != NULL); info->tail->next = form; } for (term = form; term != NULL; term = term->next) info->tail = term; } #endif break; default: xassert(info != info); } return 0; } FORMULA *eval_formula(MPL *mpl, CODE *code) { FORMULA *value; xassert(code != NULL); xassert(code->type == A_FORMULA); xassert(code->dim == 0); /* if the operation has a side effect, invalidate and delete the resultant value */ if (code->vflag && code->valid) { code->valid = 0; delete_value(mpl, code->type, &code->value); } /* if resultant value is valid, no evaluation is needed */ if (code->valid) { value = copy_formula(mpl, code->value.form); goto done; } /* evaluate pseudo-code recursively */ switch (code->op) { case O_MEMVAR: /* take member of variable */ { TUPLE *tuple; ARG_LIST *e; tuple = create_tuple(mpl); for (e = code->arg.var.list; e != NULL; e = e->next) tuple = expand_tuple(mpl, tuple, eval_symbolic(mpl, e->x)); #if 1 /* 15/V-2010 */ xassert(code->arg.var.suff == DOT_NONE); #endif value = single_variable(mpl, eval_member_var(mpl, code->arg.var.var, tuple)); delete_tuple(mpl, tuple); } break; case O_CVTLFM: /* convert to linear form */ value = constant_term(mpl, eval_numeric(mpl, code->arg.arg.x)); break; case O_PLUS: /* unary plus */ value = linear_comb(mpl, 0.0, constant_term(mpl, 0.0), +1.0, eval_formula(mpl, code->arg.arg.x)); break; case O_MINUS: /* unary minus */ value = linear_comb(mpl, 0.0, constant_term(mpl, 0.0), -1.0, eval_formula(mpl, code->arg.arg.x)); break; case O_ADD: /* addition */ value = linear_comb(mpl, +1.0, eval_formula(mpl, code->arg.arg.x), +1.0, eval_formula(mpl, code->arg.arg.y)); break; case O_SUB: /* subtraction */ value = linear_comb(mpl, +1.0, eval_formula(mpl, code->arg.arg.x), -1.0, eval_formula(mpl, code->arg.arg.y)); break; case O_MUL: /* multiplication */ xassert(code->arg.arg.x != NULL); xassert(code->arg.arg.y != NULL); if (code->arg.arg.x->type == A_NUMERIC) { xassert(code->arg.arg.y->type == A_FORMULA); value = linear_comb(mpl, eval_numeric(mpl, code->arg.arg.x), eval_formula(mpl, code->arg.arg.y), 0.0, constant_term(mpl, 0.0)); } else { xassert(code->arg.arg.x->type == A_FORMULA); xassert(code->arg.arg.y->type == A_NUMERIC); value = linear_comb(mpl, eval_numeric(mpl, code->arg.arg.y), eval_formula(mpl, code->arg.arg.x), 0.0, constant_term(mpl, 0.0)); } break; case O_DIV: /* division */ value = linear_comb(mpl, fp_div(mpl, 1.0, eval_numeric(mpl, code->arg.arg.y)), eval_formula(mpl, code->arg.arg.x), 0.0, constant_term(mpl, 0.0)); break; case O_FORK: /* if-then-else */ if (eval_logical(mpl, code->arg.arg.x)) value = eval_formula(mpl, code->arg.arg.y); else if (code->arg.arg.z == NULL) value = constant_term(mpl, 0.0); else value = eval_formula(mpl, code->arg.arg.z); break; case O_SUM: /* summation over domain */ { struct iter_form_info _info, *info = &_info; info->code = code; info->value = constant_term(mpl, 0.0); info->tail = NULL; loop_within_domain(mpl, code->arg.loop.domain, info, iter_form_func); value = reduce_terms(mpl, info->value); } break; default: xassert(code != code); } /* save resultant value */ xassert(!code->valid); code->valid = 1; code->value.form = copy_formula(mpl, value); done: return value; } /*---------------------------------------------------------------------- -- clean_code - clean pseudo-code. -- -- This routine recursively cleans specified pseudo-code that assumes -- deleting all temporary resultant values. */ void clean_code(MPL *mpl, CODE *code) { ARG_LIST *e; /* if no pseudo-code is specified, do nothing */ if (code == NULL) goto done; /* if resultant value is valid (exists), delete it */ if (code->valid) { code->valid = 0; delete_value(mpl, code->type, &code->value); } /* recursively clean pseudo-code for operands */ switch (code->op) { case O_NUMBER: case O_STRING: case O_INDEX: break; case O_MEMNUM: case O_MEMSYM: for (e = code->arg.par.list; e != NULL; e = e->next) clean_code(mpl, e->x); break; case O_MEMSET: for (e = code->arg.set.list; e != NULL; e = e->next) clean_code(mpl, e->x); break; case O_MEMVAR: for (e = code->arg.var.list; e != NULL; e = e->next) clean_code(mpl, e->x); break; #if 1 /* 15/V-2010 */ case O_MEMCON: for (e = code->arg.con.list; e != NULL; e = e->next) clean_code(mpl, e->x); break; #endif case O_TUPLE: case O_MAKE: for (e = code->arg.list; e != NULL; e = e->next) clean_code(mpl, e->x); break; case O_SLICE: xassert(code != code); case O_IRAND224: case O_UNIFORM01: case O_NORMAL01: case O_GMTIME: break; case O_CVTNUM: case O_CVTSYM: case O_CVTLOG: case O_CVTTUP: case O_CVTLFM: case O_PLUS: case O_MINUS: case O_NOT: case O_ABS: case O_CEIL: case O_FLOOR: case O_EXP: case O_LOG: case O_LOG10: case O_SQRT: case O_SIN: case O_COS: case O_ATAN: case O_ROUND: case O_TRUNC: case O_CARD: case O_LENGTH: /* unary operation */ clean_code(mpl, code->arg.arg.x); break; case O_ADD: case O_SUB: case O_LESS: case O_MUL: case O_DIV: case O_IDIV: case O_MOD: case O_POWER: case O_ATAN2: case O_ROUND2: case O_TRUNC2: case O_UNIFORM: case O_NORMAL: case O_CONCAT: case O_LT: case O_LE: case O_EQ: case O_GE: case O_GT: case O_NE: case O_AND: case O_OR: case O_UNION: case O_DIFF: case O_SYMDIFF: case O_INTER: case O_CROSS: case O_IN: case O_NOTIN: case O_WITHIN: case O_NOTWITHIN: case O_SUBSTR: case O_STR2TIME: case O_TIME2STR: /* binary operation */ clean_code(mpl, code->arg.arg.x); clean_code(mpl, code->arg.arg.y); break; case O_DOTS: case O_FORK: case O_SUBSTR3: /* ternary operation */ clean_code(mpl, code->arg.arg.x); clean_code(mpl, code->arg.arg.y); clean_code(mpl, code->arg.arg.z); break; case O_MIN: case O_MAX: /* n-ary operation */ for (e = code->arg.list; e != NULL; e = e->next) clean_code(mpl, e->x); break; case O_SUM: case O_PROD: case O_MINIMUM: case O_MAXIMUM: case O_FORALL: case O_EXISTS: case O_SETOF: case O_BUILD: /* iterated operation */ clean_domain(mpl, code->arg.loop.domain); clean_code(mpl, code->arg.loop.x); break; default: xassert(code->op != code->op); } done: return; } #if 1 /* 11/II-2008 */ /**********************************************************************/ /* * * DATA TABLES * * */ /**********************************************************************/ int mpl_tab_num_args(TABDCA *dca) { /* returns the number of arguments */ return dca->na; } const char *mpl_tab_get_arg(TABDCA *dca, int k) { /* returns pointer to k-th argument */ xassert(1 <= k && k <= dca->na); return dca->arg[k]; } int mpl_tab_num_flds(TABDCA *dca) { /* returns the number of fields */ return dca->nf; } const char *mpl_tab_get_name(TABDCA *dca, int k) { /* returns pointer to name of k-th field */ xassert(1 <= k && k <= dca->nf); return dca->name[k]; } int mpl_tab_get_type(TABDCA *dca, int k) { /* returns type of k-th field */ xassert(1 <= k && k <= dca->nf); return dca->type[k]; } double mpl_tab_get_num(TABDCA *dca, int k) { /* returns numeric value of k-th field */ xassert(1 <= k && k <= dca->nf); xassert(dca->type[k] == 'N'); return dca->num[k]; } const char *mpl_tab_get_str(TABDCA *dca, int k) { /* returns pointer to string value of k-th field */ xassert(1 <= k && k <= dca->nf); xassert(dca->type[k] == 'S'); xassert(dca->str[k] != NULL); return dca->str[k]; } void mpl_tab_set_num(TABDCA *dca, int k, double num) { /* assign numeric value to k-th field */ xassert(1 <= k && k <= dca->nf); xassert(dca->type[k] == '?'); dca->type[k] = 'N'; dca->num[k] = num; return; } void mpl_tab_set_str(TABDCA *dca, int k, const char *str) { /* assign string value to k-th field */ xassert(1 <= k && k <= dca->nf); xassert(dca->type[k] == '?'); xassert(strlen(str) <= MAX_LENGTH); xassert(dca->str[k] != NULL); dca->type[k] = 'S'; strcpy(dca->str[k], str); return; } static int write_func(MPL *mpl, void *info) { /* this is auxiliary routine to work within domain scope */ TABLE *tab = info; TABDCA *dca = mpl->dca; TABOUT *out; SYMBOL *sym; int k; char buf[MAX_LENGTH+1]; /* evaluate field values */ k = 0; for (out = tab->u.out.list; out != NULL; out = out->next) { k++; switch (out->code->type) { case A_NUMERIC: dca->type[k] = 'N'; dca->num[k] = eval_numeric(mpl, out->code); dca->str[k][0] = '\0'; break; case A_SYMBOLIC: sym = eval_symbolic(mpl, out->code); if (sym->str == NULL) { dca->type[k] = 'N'; dca->num[k] = sym->num; dca->str[k][0] = '\0'; } else { dca->type[k] = 'S'; dca->num[k] = 0.0; fetch_string(mpl, sym->str, buf); strcpy(dca->str[k], buf); } delete_symbol(mpl, sym); break; default: xassert(out != out); } } /* write record to output table */ mpl_tab_drv_write(mpl); return 0; } void execute_table(MPL *mpl, TABLE *tab) { /* execute table statement */ TABARG *arg; TABFLD *fld; TABIN *in; TABOUT *out; TABDCA *dca; SET *set; int k; char buf[MAX_LENGTH+1]; /* allocate table driver communication area */ xassert(mpl->dca == NULL); mpl->dca = dca = xmalloc(sizeof(TABDCA)); dca->id = 0; dca->link = NULL; dca->na = 0; dca->arg = NULL; dca->nf = 0; dca->name = NULL; dca->type = NULL; dca->num = NULL; dca->str = NULL; /* allocate arguments */ xassert(dca->na == 0); for (arg = tab->arg; arg != NULL; arg = arg->next) dca->na++; dca->arg = xcalloc(1+dca->na, sizeof(char *)); #if 1 /* 28/IX-2008 */ for (k = 1; k <= dca->na; k++) dca->arg[k] = NULL; #endif /* evaluate argument values */ k = 0; for (arg = tab->arg; arg != NULL; arg = arg->next) { SYMBOL *sym; k++; xassert(arg->code->type == A_SYMBOLIC); sym = eval_symbolic(mpl, arg->code); if (sym->str == NULL) sprintf(buf, "%.*g", DBL_DIG, sym->num); else fetch_string(mpl, sym->str, buf); delete_symbol(mpl, sym); dca->arg[k] = xmalloc(strlen(buf)+1); strcpy(dca->arg[k], buf); } /* perform table input/output */ switch (tab->type) { case A_INPUT: goto read_table; case A_OUTPUT: goto write_table; default: xassert(tab != tab); } read_table: /* read data from input table */ /* add the only member to the control set and assign it empty elemental set */ set = tab->u.in.set; if (set != NULL) { if (set->data) error(mpl, "%s already provided with data", set->name); xassert(set->array->head == NULL); add_member(mpl, set->array, NULL)->value.set = create_elemset(mpl, set->dimen); set->data = 1; } /* check parameters specified in the input list */ for (in = tab->u.in.list; in != NULL; in = in->next) { if (in->par->data) error(mpl, "%s already provided with data", in->par->name); in->par->data = 1; } /* allocate and initialize fields */ xassert(dca->nf == 0); for (fld = tab->u.in.fld; fld != NULL; fld = fld->next) dca->nf++; for (in = tab->u.in.list; in != NULL; in = in->next) dca->nf++; dca->name = xcalloc(1+dca->nf, sizeof(char *)); dca->type = xcalloc(1+dca->nf, sizeof(int)); dca->num = xcalloc(1+dca->nf, sizeof(double)); dca->str = xcalloc(1+dca->nf, sizeof(char *)); k = 0; for (fld = tab->u.in.fld; fld != NULL; fld = fld->next) { k++; dca->name[k] = fld->name; dca->type[k] = '?'; dca->num[k] = 0.0; dca->str[k] = xmalloc(MAX_LENGTH+1); dca->str[k][0] = '\0'; } for (in = tab->u.in.list; in != NULL; in = in->next) { k++; dca->name[k] = in->name; dca->type[k] = '?'; dca->num[k] = 0.0; dca->str[k] = xmalloc(MAX_LENGTH+1); dca->str[k][0] = '\0'; } /* open input table */ mpl_tab_drv_open(mpl, 'R'); /* read and process records */ for (;;) { TUPLE *tup; /* reset field types */ for (k = 1; k <= dca->nf; k++) dca->type[k] = '?'; /* read next record */ if (mpl_tab_drv_read(mpl)) break; /* all fields must be set by the driver */ for (k = 1; k <= dca->nf; k++) { if (dca->type[k] == '?') error(mpl, "field %s missing in input table", dca->name[k]); } /* construct n-tuple */ tup = create_tuple(mpl); k = 0; for (fld = tab->u.in.fld; fld != NULL; fld = fld->next) { k++; xassert(k <= dca->nf); switch (dca->type[k]) { case 'N': tup = expand_tuple(mpl, tup, create_symbol_num(mpl, dca->num[k])); break; case 'S': xassert(strlen(dca->str[k]) <= MAX_LENGTH); tup = expand_tuple(mpl, tup, create_symbol_str(mpl, create_string(mpl, dca->str[k]))); break; default: xassert(dca != dca); } } /* add n-tuple just read to the control set */ if (tab->u.in.set != NULL) check_then_add(mpl, tab->u.in.set->array->head->value.set, copy_tuple(mpl, tup)); /* assign values to the parameters in the input list */ for (in = tab->u.in.list; in != NULL; in = in->next) { MEMBER *memb; k++; xassert(k <= dca->nf); /* there must be no member with the same n-tuple */ if (find_member(mpl, in->par->array, tup) != NULL) error(mpl, "%s%s already defined", in->par->name, format_tuple(mpl, '[', tup)); /* create new parameter member with given n-tuple */ memb = add_member(mpl, in->par->array, copy_tuple(mpl, tup)) ; /* assign value to the parameter member */ switch (in->par->type) { case A_NUMERIC: case A_INTEGER: case A_BINARY: if (dca->type[k] != 'N') error(mpl, "%s requires numeric data", in->par->name); memb->value.num = dca->num[k]; break; case A_SYMBOLIC: switch (dca->type[k]) { case 'N': memb->value.sym = create_symbol_num(mpl, dca->num[k]); break; case 'S': xassert(strlen(dca->str[k]) <= MAX_LENGTH); memb->value.sym = create_symbol_str(mpl, create_string(mpl,dca->str[k])); break; default: xassert(dca != dca); } break; default: xassert(in != in); } } /* n-tuple is no more needed */ delete_tuple(mpl, tup); } /* close input table */ mpl_tab_drv_close(mpl); goto done; write_table: /* write data to output table */ /* allocate and initialize fields */ xassert(dca->nf == 0); for (out = tab->u.out.list; out != NULL; out = out->next) dca->nf++; dca->name = xcalloc(1+dca->nf, sizeof(char *)); dca->type = xcalloc(1+dca->nf, sizeof(int)); dca->num = xcalloc(1+dca->nf, sizeof(double)); dca->str = xcalloc(1+dca->nf, sizeof(char *)); k = 0; for (out = tab->u.out.list; out != NULL; out = out->next) { k++; dca->name[k] = out->name; dca->type[k] = '?'; dca->num[k] = 0.0; dca->str[k] = xmalloc(MAX_LENGTH+1); dca->str[k][0] = '\0'; } /* open output table */ mpl_tab_drv_open(mpl, 'W'); /* evaluate fields and write records */ loop_within_domain(mpl, tab->u.out.domain, tab, write_func); /* close output table */ mpl_tab_drv_close(mpl); done: /* free table driver communication area */ free_dca(mpl); return; } void free_dca(MPL *mpl) { /* free table driver communucation area */ TABDCA *dca = mpl->dca; int k; if (dca != NULL) { if (dca->link != NULL) mpl_tab_drv_close(mpl); if (dca->arg != NULL) { for (k = 1; k <= dca->na; k++) #if 1 /* 28/IX-2008 */ if (dca->arg[k] != NULL) #endif xfree(dca->arg[k]); xfree(dca->arg); } if (dca->name != NULL) xfree(dca->name); if (dca->type != NULL) xfree(dca->type); if (dca->num != NULL) xfree(dca->num); if (dca->str != NULL) { for (k = 1; k <= dca->nf; k++) xfree(dca->str[k]); xfree(dca->str); } xfree(dca), mpl->dca = NULL; } return; } void clean_table(MPL *mpl, TABLE *tab) { /* clean table statement */ TABARG *arg; TABOUT *out; /* clean string list */ for (arg = tab->arg; arg != NULL; arg = arg->next) clean_code(mpl, arg->code); switch (tab->type) { case A_INPUT: break; case A_OUTPUT: /* clean subscript domain */ clean_domain(mpl, tab->u.out.domain); /* clean output list */ for (out = tab->u.out.list; out != NULL; out = out->next) clean_code(mpl, out->code); break; default: xassert(tab != tab); } return; } #endif /**********************************************************************/ /* * * MODEL STATEMENTS * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- execute_check - execute check statement. -- -- This routine executes specified check statement. */ static int check_func(MPL *mpl, void *info) { /* this is auxiliary routine to work within domain scope */ CHECK *chk = (CHECK *)info; if (!eval_logical(mpl, chk->code)) error(mpl, "check%s failed", format_tuple(mpl, '[', get_domain_tuple(mpl, chk->domain))); return 0; } void execute_check(MPL *mpl, CHECK *chk) { loop_within_domain(mpl, chk->domain, chk, check_func); return; } /*---------------------------------------------------------------------- -- clean_check - clean check statement. -- -- This routine cleans specified check statement that assumes deleting -- all stuff dynamically allocated on generating/postsolving phase. */ void clean_check(MPL *mpl, CHECK *chk) { /* clean subscript domain */ clean_domain(mpl, chk->domain); /* clean pseudo-code for computing predicate */ clean_code(mpl, chk->code); return; } /*---------------------------------------------------------------------- -- execute_display - execute display statement. -- -- This routine executes specified display statement. */ static void display_set(MPL *mpl, SET *set, MEMBER *memb) { /* display member of model set */ ELEMSET *s = memb->value.set; MEMBER *m; write_text(mpl, "%s%s%s\n", set->name, format_tuple(mpl, '[', memb->tuple), s->head == NULL ? " is empty" : ":"); for (m = s->head; m != NULL; m = m->next) write_text(mpl, " %s\n", format_tuple(mpl, '(', m->tuple)); return; } static void display_par(MPL *mpl, PARAMETER *par, MEMBER *memb) { /* display member of model parameter */ switch (par->type) { case A_NUMERIC: case A_INTEGER: case A_BINARY: write_text(mpl, "%s%s = %.*g\n", par->name, format_tuple(mpl, '[', memb->tuple), DBL_DIG, memb->value.num); break; case A_SYMBOLIC: write_text(mpl, "%s%s = %s\n", par->name, format_tuple(mpl, '[', memb->tuple), format_symbol(mpl, memb->value.sym)); break; default: xassert(par != par); } return; } #if 1 /* 15/V-2010 */ static void display_var(MPL *mpl, VARIABLE *var, MEMBER *memb, int suff) { /* display member of model variable */ if (suff == DOT_NONE || suff == DOT_VAL) write_text(mpl, "%s%s.val = %.*g\n", var->name, format_tuple(mpl, '[', memb->tuple), DBL_DIG, memb->value.var->prim); else if (suff == DOT_LB) write_text(mpl, "%s%s.lb = %.*g\n", var->name, format_tuple(mpl, '[', memb->tuple), DBL_DIG, memb->value.var->var->lbnd == NULL ? -DBL_MAX : memb->value.var->lbnd); else if (suff == DOT_UB) write_text(mpl, "%s%s.ub = %.*g\n", var->name, format_tuple(mpl, '[', memb->tuple), DBL_DIG, memb->value.var->var->ubnd == NULL ? +DBL_MAX : memb->value.var->ubnd); else if (suff == DOT_STATUS) write_text(mpl, "%s%s.status = %d\n", var->name, format_tuple (mpl, '[', memb->tuple), memb->value.var->stat); else if (suff == DOT_DUAL) write_text(mpl, "%s%s.dual = %.*g\n", var->name, format_tuple(mpl, '[', memb->tuple), DBL_DIG, memb->value.var->dual); else xassert(suff != suff); return; } #endif #if 1 /* 15/V-2010 */ static void display_con(MPL *mpl, CONSTRAINT *con, MEMBER *memb, int suff) { /* display member of model constraint */ if (suff == DOT_NONE || suff == DOT_VAL) write_text(mpl, "%s%s.val = %.*g\n", con->name, format_tuple(mpl, '[', memb->tuple), DBL_DIG, memb->value.con->prim); else if (suff == DOT_LB) write_text(mpl, "%s%s.lb = %.*g\n", con->name, format_tuple(mpl, '[', memb->tuple), DBL_DIG, memb->value.con->con->lbnd == NULL ? -DBL_MAX : memb->value.con->lbnd); else if (suff == DOT_UB) write_text(mpl, "%s%s.ub = %.*g\n", con->name, format_tuple(mpl, '[', memb->tuple), DBL_DIG, memb->value.con->con->ubnd == NULL ? +DBL_MAX : memb->value.con->ubnd); else if (suff == DOT_STATUS) write_text(mpl, "%s%s.status = %d\n", con->name, format_tuple (mpl, '[', memb->tuple), memb->value.con->stat); else if (suff == DOT_DUAL) write_text(mpl, "%s%s.dual = %.*g\n", con->name, format_tuple(mpl, '[', memb->tuple), DBL_DIG, memb->value.con->dual); else xassert(suff != suff); return; } #endif static void display_memb(MPL *mpl, CODE *code) { /* display member specified by pseudo-code */ MEMBER memb; ARG_LIST *e; xassert(code->op == O_MEMNUM || code->op == O_MEMSYM || code->op == O_MEMSET || code->op == O_MEMVAR || code->op == O_MEMCON); memb.tuple = create_tuple(mpl); for (e = code->arg.par.list; e != NULL; e = e->next) memb.tuple = expand_tuple(mpl, memb.tuple, eval_symbolic(mpl, e->x)); switch (code->op) { case O_MEMNUM: memb.value.num = eval_member_num(mpl, code->arg.par.par, memb.tuple); display_par(mpl, code->arg.par.par, &memb); break; case O_MEMSYM: memb.value.sym = eval_member_sym(mpl, code->arg.par.par, memb.tuple); display_par(mpl, code->arg.par.par, &memb); delete_symbol(mpl, memb.value.sym); break; case O_MEMSET: memb.value.set = eval_member_set(mpl, code->arg.set.set, memb.tuple); display_set(mpl, code->arg.set.set, &memb); break; case O_MEMVAR: memb.value.var = eval_member_var(mpl, code->arg.var.var, memb.tuple); display_var (mpl, code->arg.var.var, &memb, code->arg.var.suff); break; case O_MEMCON: memb.value.con = eval_member_con(mpl, code->arg.con.con, memb.tuple); display_con (mpl, code->arg.con.con, &memb, code->arg.con.suff); break; default: xassert(code != code); } delete_tuple(mpl, memb.tuple); return; } static void display_code(MPL *mpl, CODE *code) { /* display value of expression */ switch (code->type) { case A_NUMERIC: /* numeric value */ { double num; num = eval_numeric(mpl, code); write_text(mpl, "%.*g\n", DBL_DIG, num); } break; case A_SYMBOLIC: /* symbolic value */ { SYMBOL *sym; sym = eval_symbolic(mpl, code); write_text(mpl, "%s\n", format_symbol(mpl, sym)); delete_symbol(mpl, sym); } break; case A_LOGICAL: /* logical value */ { int bit; bit = eval_logical(mpl, code); write_text(mpl, "%s\n", bit ? "true" : "false"); } break; case A_TUPLE: /* n-tuple */ { TUPLE *tuple; tuple = eval_tuple(mpl, code); write_text(mpl, "%s\n", format_tuple(mpl, '(', tuple)); delete_tuple(mpl, tuple); } break; case A_ELEMSET: /* elemental set */ { ELEMSET *set; MEMBER *memb; set = eval_elemset(mpl, code); if (set->head == 0) write_text(mpl, "set is empty\n"); for (memb = set->head; memb != NULL; memb = memb->next) write_text(mpl, " %s\n", format_tuple(mpl, '(', memb->tuple)); delete_elemset(mpl, set); } break; case A_FORMULA: /* linear form */ { FORMULA *form, *term; form = eval_formula(mpl, code); if (form == NULL) write_text(mpl, "linear form is empty\n"); for (term = form; term != NULL; term = term->next) { if (term->var == NULL) write_text(mpl, " %.*g\n", term->coef); else write_text(mpl, " %.*g %s%s\n", DBL_DIG, term->coef, term->var->var->name, format_tuple(mpl, '[', term->var->memb->tuple)); } delete_formula(mpl, form); } break; default: xassert(code != code); } return; } static int display_func(MPL *mpl, void *info) { /* this is auxiliary routine to work within domain scope */ DISPLAY *dpy = (DISPLAY *)info; DISPLAY1 *entry; for (entry = dpy->list; entry != NULL; entry = entry->next) { if (entry->type == A_INDEX) { /* dummy index */ DOMAIN_SLOT *slot = entry->u.slot; write_text(mpl, "%s = %s\n", slot->name, format_symbol(mpl, slot->value)); } else if (entry->type == A_SET) { /* model set */ SET *set = entry->u.set; MEMBER *memb; if (set->assign != NULL) { /* the set has assignment expression; evaluate all its members over entire domain */ eval_whole_set(mpl, set); } else { /* the set has no assignment expression; refer to its any existing member ignoring resultant value to check the data provided the data section */ #if 1 /* 12/XII-2008 */ if (set->gadget != NULL && set->data == 0) { /* initialize the set with data from a plain set */ saturate_set(mpl, set); } #endif if (set->array->head != NULL) eval_member_set(mpl, set, set->array->head->tuple); } /* display all members of the set array */ if (set->array->head == NULL) write_text(mpl, "%s has empty content\n", set->name); for (memb = set->array->head; memb != NULL; memb = memb->next) display_set(mpl, set, memb); } else if (entry->type == A_PARAMETER) { /* model parameter */ PARAMETER *par = entry->u.par; MEMBER *memb; if (par->assign != NULL) { /* the parameter has an assignment expression; evaluate all its member over entire domain */ eval_whole_par(mpl, par); } else { /* the parameter has no assignment expression; refer to its any existing member ignoring resultant value to check the data provided in the data section */ if (par->array->head != NULL) { if (par->type != A_SYMBOLIC) eval_member_num(mpl, par, par->array->head->tuple); else delete_symbol(mpl, eval_member_sym(mpl, par, par->array->head->tuple)); } } /* display all members of the parameter array */ if (par->array->head == NULL) write_text(mpl, "%s has empty content\n", par->name); for (memb = par->array->head; memb != NULL; memb = memb->next) display_par(mpl, par, memb); } else if (entry->type == A_VARIABLE) { /* model variable */ VARIABLE *var = entry->u.var; MEMBER *memb; xassert(mpl->flag_p); /* display all members of the variable array */ if (var->array->head == NULL) write_text(mpl, "%s has empty content\n", var->name); for (memb = var->array->head; memb != NULL; memb = memb->next) display_var(mpl, var, memb, DOT_NONE); } else if (entry->type == A_CONSTRAINT) { /* model constraint */ CONSTRAINT *con = entry->u.con; MEMBER *memb; xassert(mpl->flag_p); /* display all members of the constraint array */ if (con->array->head == NULL) write_text(mpl, "%s has empty content\n", con->name); for (memb = con->array->head; memb != NULL; memb = memb->next) display_con(mpl, con, memb, DOT_NONE); } else if (entry->type == A_EXPRESSION) { /* expression */ CODE *code = entry->u.code; if (code->op == O_MEMNUM || code->op == O_MEMSYM || code->op == O_MEMSET || code->op == O_MEMVAR || code->op == O_MEMCON) display_memb(mpl, code); else display_code(mpl, code); } else xassert(entry != entry); } return 0; } void execute_display(MPL *mpl, DISPLAY *dpy) { loop_within_domain(mpl, dpy->domain, dpy, display_func); return; } /*---------------------------------------------------------------------- -- clean_display - clean display statement. -- -- This routine cleans specified display statement that assumes deleting -- all stuff dynamically allocated on generating/postsolving phase. */ void clean_display(MPL *mpl, DISPLAY *dpy) { DISPLAY1 *d; #if 0 /* 15/V-2010 */ ARG_LIST *e; #endif /* clean subscript domain */ clean_domain(mpl, dpy->domain); /* clean display list */ for (d = dpy->list; d != NULL; d = d->next) { /* clean pseudo-code for computing expression */ if (d->type == A_EXPRESSION) clean_code(mpl, d->u.code); #if 0 /* 15/V-2010 */ /* clean pseudo-code for computing subscripts */ for (e = d->list; e != NULL; e = e->next) clean_code(mpl, e->x); #endif } return; } /*---------------------------------------------------------------------- -- execute_printf - execute printf statement. -- -- This routine executes specified printf statement. */ #if 1 /* 14/VII-2006 */ static void print_char(MPL *mpl, int c) { if (mpl->prt_fp == NULL) write_char(mpl, c); else xfputc(c, mpl->prt_fp); return; } static void print_text(MPL *mpl, char *fmt, ...) { va_list arg; char buf[OUTBUF_SIZE], *c; va_start(arg, fmt); vsprintf(buf, fmt, arg); xassert(strlen(buf) < sizeof(buf)); va_end(arg); for (c = buf; *c != '\0'; c++) print_char(mpl, *c); return; } #endif static int printf_func(MPL *mpl, void *info) { /* this is auxiliary routine to work within domain scope */ PRINTF *prt = (PRINTF *)info; PRINTF1 *entry; SYMBOL *sym; char fmt[MAX_LENGTH+1], *c, *from, save; /* evaluate format control string */ sym = eval_symbolic(mpl, prt->fmt); if (sym->str == NULL) sprintf(fmt, "%.*g", DBL_DIG, sym->num); else fetch_string(mpl, sym->str, fmt); delete_symbol(mpl, sym); /* scan format control string and perform formatting output */ entry = prt->list; for (c = fmt; *c != '\0'; c++) { if (*c == '%') { /* scan format specifier */ from = c++; if (*c == '%') { print_char(mpl, '%'); continue; } if (entry == NULL) break; /* scan optional flags */ while (*c == '-' || *c == '+' || *c == ' ' || *c == '#' || *c == '0') c++; /* scan optional minimum field width */ while (isdigit((unsigned char)*c)) c++; /* scan optional precision */ if (*c == '.') { c++; while (isdigit((unsigned char)*c)) c++; } /* scan conversion specifier and perform formatting */ save = *(c+1), *(c+1) = '\0'; if (*c == 'd' || *c == 'i' || *c == 'e' || *c == 'E' || *c == 'f' || *c == 'F' || *c == 'g' || *c == 'G') { /* the specifier requires numeric value */ double value; xassert(entry != NULL); switch (entry->code->type) { case A_NUMERIC: value = eval_numeric(mpl, entry->code); break; case A_SYMBOLIC: sym = eval_symbolic(mpl, entry->code); if (sym->str != NULL) error(mpl, "cannot convert %s to floating-point" " number", format_symbol(mpl, sym)); value = sym->num; delete_symbol(mpl, sym); break; case A_LOGICAL: if (eval_logical(mpl, entry->code)) value = 1.0; else value = 0.0; break; default: xassert(entry != entry); } if (*c == 'd' || *c == 'i') { double int_max = (double)INT_MAX; if (!(-int_max <= value && value <= +int_max)) error(mpl, "cannot convert %.*g to integer", DBL_DIG, value); print_text(mpl, from, (int)floor(value + 0.5)); } else print_text(mpl, from, value); } else if (*c == 's') { /* the specifier requires symbolic value */ char value[MAX_LENGTH+1]; switch (entry->code->type) { case A_NUMERIC: sprintf(value, "%.*g", DBL_DIG, eval_numeric(mpl, entry->code)); break; case A_LOGICAL: if (eval_logical(mpl, entry->code)) strcpy(value, "T"); else strcpy(value, "F"); break; case A_SYMBOLIC: sym = eval_symbolic(mpl, entry->code); if (sym->str == NULL) sprintf(value, "%.*g", DBL_DIG, sym->num); else fetch_string(mpl, sym->str, value); delete_symbol(mpl, sym); break; default: xassert(entry != entry); } print_text(mpl, from, value); } else error(mpl, "format specifier missing or invalid"); *(c+1) = save; entry = entry->next; } else if (*c == '\\') { /* write some control character */ c++; if (*c == 't') print_char(mpl, '\t'); else if (*c == 'n') print_char(mpl, '\n'); #if 1 /* 28/X-2010 */ else if (*c == '\0') { /* format string ends with backslash */ error(mpl, "invalid use of escape character \\ in format" " control string"); } #endif else print_char(mpl, *c); } else { /* write character without formatting */ print_char(mpl, *c); } } return 0; } #if 0 /* 14/VII-2006 */ void execute_printf(MPL *mpl, PRINTF *prt) { loop_within_domain(mpl, prt->domain, prt, printf_func); return; } #else void execute_printf(MPL *mpl, PRINTF *prt) { if (prt->fname == NULL) { /* switch to the standard output */ if (mpl->prt_fp != NULL) { xfclose(mpl->prt_fp), mpl->prt_fp = NULL; xfree(mpl->prt_file), mpl->prt_file = NULL; } } else { /* evaluate file name string */ SYMBOL *sym; char fname[MAX_LENGTH+1]; sym = eval_symbolic(mpl, prt->fname); if (sym->str == NULL) sprintf(fname, "%.*g", DBL_DIG, sym->num); else fetch_string(mpl, sym->str, fname); delete_symbol(mpl, sym); /* close the current print file, if necessary */ if (mpl->prt_fp != NULL && (!prt->app || strcmp(mpl->prt_file, fname) != 0)) { xfclose(mpl->prt_fp), mpl->prt_fp = NULL; xfree(mpl->prt_file), mpl->prt_file = NULL; } /* open the specified print file, if necessary */ if (mpl->prt_fp == NULL) { mpl->prt_fp = xfopen(fname, prt->app ? "a" : "w"); if (mpl->prt_fp == NULL) error(mpl, "unable to open `%s' for writing - %s", fname, xerrmsg()); mpl->prt_file = xmalloc(strlen(fname)+1); strcpy(mpl->prt_file, fname); } } loop_within_domain(mpl, prt->domain, prt, printf_func); if (mpl->prt_fp != NULL) { xfflush(mpl->prt_fp); if (xferror(mpl->prt_fp)) error(mpl, "writing error to `%s' - %s", mpl->prt_file, xerrmsg()); } return; } #endif /*---------------------------------------------------------------------- -- clean_printf - clean printf statement. -- -- This routine cleans specified printf statement that assumes deleting -- all stuff dynamically allocated on generating/postsolving phase. */ void clean_printf(MPL *mpl, PRINTF *prt) { PRINTF1 *p; /* clean subscript domain */ clean_domain(mpl, prt->domain); /* clean pseudo-code for computing format string */ clean_code(mpl, prt->fmt); /* clean printf list */ for (p = prt->list; p != NULL; p = p->next) { /* clean pseudo-code for computing value to be printed */ clean_code(mpl, p->code); } #if 1 /* 14/VII-2006 */ /* clean pseudo-code for computing file name string */ clean_code(mpl, prt->fname); #endif return; } /*---------------------------------------------------------------------- -- execute_for - execute for statement. -- -- This routine executes specified for statement. */ static int for_func(MPL *mpl, void *info) { /* this is auxiliary routine to work within domain scope */ FOR *fur = (FOR *)info; STATEMENT *stmt, *save; save = mpl->stmt; for (stmt = fur->list; stmt != NULL; stmt = stmt->next) execute_statement(mpl, stmt); mpl->stmt = save; return 0; } void execute_for(MPL *mpl, FOR *fur) { loop_within_domain(mpl, fur->domain, fur, for_func); return; } /*---------------------------------------------------------------------- -- clean_for - clean for statement. -- -- This routine cleans specified for statement that assumes deleting all -- stuff dynamically allocated on generating/postsolving phase. */ void clean_for(MPL *mpl, FOR *fur) { STATEMENT *stmt; /* clean subscript domain */ clean_domain(mpl, fur->domain); /* clean all sub-statements */ for (stmt = fur->list; stmt != NULL; stmt = stmt->next) clean_statement(mpl, stmt); return; } /*---------------------------------------------------------------------- -- execute_statement - execute specified model statement. -- -- This routine executes specified model statement. */ void execute_statement(MPL *mpl, STATEMENT *stmt) { mpl->stmt = stmt; switch (stmt->type) { case A_SET: case A_PARAMETER: case A_VARIABLE: break; case A_CONSTRAINT: xprintf("Generating %s...\n", stmt->u.con->name); eval_whole_con(mpl, stmt->u.con); break; case A_TABLE: switch (stmt->u.tab->type) { case A_INPUT: xprintf("Reading %s...\n", stmt->u.tab->name); break; case A_OUTPUT: xprintf("Writing %s...\n", stmt->u.tab->name); break; default: xassert(stmt != stmt); } execute_table(mpl, stmt->u.tab); break; case A_SOLVE: break; case A_CHECK: xprintf("Checking (line %d)...\n", stmt->line); execute_check(mpl, stmt->u.chk); break; case A_DISPLAY: write_text(mpl, "Display statement at line %d\n", stmt->line); execute_display(mpl, stmt->u.dpy); break; case A_PRINTF: execute_printf(mpl, stmt->u.prt); break; case A_FOR: execute_for(mpl, stmt->u.fur); break; default: xassert(stmt != stmt); } return; } /*---------------------------------------------------------------------- -- clean_statement - clean specified model statement. -- -- This routine cleans specified model statement that assumes deleting -- all stuff dynamically allocated on generating/postsolving phase. */ void clean_statement(MPL *mpl, STATEMENT *stmt) { switch(stmt->type) { case A_SET: clean_set(mpl, stmt->u.set); break; case A_PARAMETER: clean_parameter(mpl, stmt->u.par); break; case A_VARIABLE: clean_variable(mpl, stmt->u.var); break; case A_CONSTRAINT: clean_constraint(mpl, stmt->u.con); break; #if 1 /* 11/II-2008 */ case A_TABLE: clean_table(mpl, stmt->u.tab); break; #endif case A_SOLVE: break; case A_CHECK: clean_check(mpl, stmt->u.chk); break; case A_DISPLAY: clean_display(mpl, stmt->u.dpy); break; case A_PRINTF: clean_printf(mpl, stmt->u.prt); break; case A_FOR: clean_for(mpl, stmt->u.fur); break; default: xassert(stmt != stmt); } return; } /* eof */ Rglpk/src/GLPK/env.h0000644000176000001440000001474412245352174013665 0ustar ripleyusers/* env.h (GLPK environment) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef ENV_H #define ENV_H #include "stdc.h" typedef struct ENV ENV; typedef struct MBD MBD; #define SIZE_T_MAX (~(size_t)0) /* largest value of size_t type */ #define TBUF_SIZE 4096 /* terminal output buffer size, in bytes */ /* enable/disable flag: */ #define GLP_ON 1 #define GLP_OFF 0 struct ENV { /* GLPK environment block */ char version[7+1]; /* version string returned by the routine glp_version */ ENV *self; /* pointer to this block to check its validity */ /*--------------------------------------------------------------*/ /* terminal output */ char *term_buf; /* char term_buf[TBUF_SIZE]; */ /* terminal output buffer */ int term_out; /* flag to enable/disable terminal output */ int (*term_hook)(void *info, const char *s); /* user-defined routine to intercept terminal output */ void *term_info; /* transit pointer (cookie) passed to the routine term_hook */ FILE *tee_file; /* output stream used to copy terminal output */ /*--------------------------------------------------------------*/ /* error handling */ const char *err_file; /* value of the __FILE__ macro passed to glp_error */ int err_line; /* value of the __LINE__ macro passed to glp_error */ void (*err_hook)(void *info); /* user-defined routine to intercept abnormal termination */ void *err_info; /* transit pointer (cookie) passed to the routine err_hook */ /*--------------------------------------------------------------*/ /* dynamic memory allocation */ size_t mem_limit; /* maximal amount of memory, in bytes, available for dynamic allocation */ MBD *mem_ptr; /* pointer to the linked list of allocated memory blocks */ int mem_count; /* total number of currently allocated memory blocks */ int mem_cpeak; /* peak value of mem_count */ size_t mem_total; /* total amount of currently allocated memory, in bytes; it is the sum of the size field over all memory block descriptors */ size_t mem_tpeak; /* peak value of mem_total */ /*--------------------------------------------------------------*/ /* shared libraries support (optional) */ void *h_odbc; /* handle to ODBC shared library */ void *h_mysql; /* handle to MySQL shared library */ }; struct MBD { /* memory block descriptor */ size_t size; /* size of block, in bytes, including descriptor */ MBD *self; /* pointer to this descriptor to check its validity */ MBD *prev; /* pointer to previous memory block descriptor */ MBD *next; /* pointer to next memory block descriptor */ }; #define get_env_ptr _glp_get_env_ptr ENV *get_env_ptr(void); /* retrieve pointer to environment block */ #define tls_set_ptr _glp_tls_set_ptr void tls_set_ptr(void *ptr); /* store global pointer in TLS */ #define tls_get_ptr _glp_tls_get_ptr void *tls_get_ptr(void); /* retrieve global pointer from TLS */ #define xputs glp_puts void glp_puts(const char *s); /* write string on terminal */ #define xprintf glp_printf void glp_printf(const char *fmt, ...); /* write formatted output on terminal */ #define xvprintf glp_vprintf void glp_vprintf(const char *fmt, va_list arg); /* write formatted output on terminal */ int glp_term_out(int flag); /* enable/disable terminal output */ void glp_term_hook(int (*func)(void *info, const char *s), void *info); /* install hook to intercept terminal output */ int glp_open_tee(const char *fname); /* start copying terminal output to text file */ int glp_close_tee(void); /* stop copying terminal output to text file */ #ifndef GLP_ERRFUNC_DEFINED #define GLP_ERRFUNC_DEFINED typedef void (*glp_errfunc)(const char *fmt, ...); #endif #define xerror glp_error_(__FILE__, __LINE__) glp_errfunc glp_error_(const char *file, int line); /* display fatal error message and terminate execution */ #define xassert(expr) \ ((void)((expr) || (glp_assert_(#expr, __FILE__, __LINE__), 1))) void glp_assert_(const char *expr, const char *file, int line); /* check for logical condition */ void glp_error_hook(void (*func)(void *info), void *info); /* install hook to intercept abnormal termination */ #define xmalloc(size) glp_alloc(1, size) /* allocate memory block (obsolete) */ #define xcalloc(n, size) glp_alloc(n, size) /* allocate memory block (obsolete) */ #define xalloc(n, size) glp_alloc(n, size) #define talloc(n, type) ((type *)glp_alloc(n, sizeof(type))) void *glp_alloc(int n, int size); /* allocate memory block */ #define xrealloc(ptr, n, size) glp_realloc(ptr, n, size) #define trealloc(ptr, n, type) ((type *)glp_realloc(ptr, n, \ sizeof(type))) void *glp_realloc(void *ptr, int n, int size); /* reallocate memory block */ #define xfree(ptr) glp_free(ptr) #define tfree(ptr) glp_free(ptr) void glp_free(void *ptr); /* free memory block */ void glp_mem_limit(int limit); /* set memory usage limit */ void glp_mem_usage(int *count, int *cpeak, size_t *total, size_t *tpeak); /* get memory usage information */ #define xtime glp_time double glp_time(void); /* determine current universal time */ #define xdifftime glp_difftime double glp_difftime(double t1, double t0); /* compute difference between two time values */ #define xdlopen _glp_xdlopen void *xdlopen(const char *module); #define xdlsym _glp_xdlsym void *xdlsym(void *h, const char *symbol); #define xdlclose _glp_xdlclose void xdlclose(void *h); #endif /* eof */ Rglpk/src/GLPK/Makefile0000644000176000001440000000434212245352174014355 0ustar ripleyusers#-*- Makefile -*- # include $(R_HOME)/etc$(R_ARCH)/Makeconf SOURCES= \ ./minisat/minisat.c \ ./glptsp.c \ ./sgf.c \ ./glprgr.c \ ./lufint.c \ ./triang.c \ ./glpnpp01.c \ ./glpapi09.c \ ./glpios08.c \ ./glpscl.c \ ./glpavl.c \ ./glpapi15.c \ ./glpios05.c \ ./glpios12.c \ ./glpios09.c \ ./glpapi12.c \ ./glpssx01.c \ ./glpcpx.c \ ./glpapi17.c \ ./glpmpl06.c \ ./glpmpl03.c \ ./glpnpp03.c \ ./glpgmp.c \ ./glpios02.c \ ./glpapi10.c \ ./glpnpp02.c \ ./glpsdf.c \ ./glpapi16.c \ ./glpipm.c \ ./glpspx01.c \ ./colamd/colamd.c \ ./zlib/gzclose.c \ ./zlib/gzread.c \ ./zlib/inftrees.c \ ./zlib/zutil.c \ ./zlib/uncompr.c \ ./zlib/deflate.c \ ./zlib/gzwrite.c \ ./zlib/adler32.c \ ./zlib/inflate.c \ ./zlib/trees.c \ ./zlib/zio.c \ ./zlib/inffast.c \ ./zlib/compress.c \ ./zlib/gzlib.c \ ./zlib/crc32.c \ ./qmd.c \ ./glpapi13.c \ ./dmp.c \ ./glpapi03.c \ ./glpnpp06.c \ ./glpapi06.c \ ./glphbm.c \ ./tls.c \ ./time.c \ ./glpios01.c \ ./glpmpl02.c \ ./glpios04.c \ ./glpenv08.c \ ./proxy/main.c \ ./proxy/proxy.c \ ./proxy/proxy1.c \ ./glpapi11.c \ ./glpspm.c \ ./glpssx02.c \ ./glpnpp04.c \ ./fhvint.c \ ./glplpx02.c \ ./glplux.c \ ./glpmpl04.c \ ./bignum.c \ ./glpnet05.c \ ./okalg.c \ ./glpmpl01.c \ ./glpios03.c \ ./glplpf.c \ ./glpnpp05.c \ ./glpapi20.c \ ./rng1.c \ ./error.c \ ./glpios11.c \ ./glpmps.c \ ./amd/amd_order.c \ ./amd/amd_defaults.c \ ./amd/amd_postorder.c \ ./amd/amd_info.c \ ./amd/amd_dump.c \ ./amd/amd_control.c \ ./amd/amd_valid.c \ ./amd/amd_1.c \ ./amd/amd_post_tree.c \ ./amd/amd_aat.c \ ./amd/amd_2.c \ ./amd/amd_preprocess.c \ ./cfg1.c \ ./glplpx01.c \ ./glpapi19.c \ ./glpapi01.c \ ./glpapi18.c \ ./glpdmx.c \ ./glplib03.c \ ./glpmat.c \ ./glpspx02.c \ ./glpapi07.c \ ./glpbfd.c \ ./glpnet03.c \ ./glpenv07.c \ ./glpapi05.c \ ./keller.c \ ./glpapi04.c \ ./luf.c \ ./env.c \ ./glplpx03.c \ ./mc13d.c \ ./glpapi08.c \ ./sva.c \ ./stdout.c \ ./ffalg.c \ ./rng.c \ ./alloc.c \ ./glpnet04.c \ ./glpbfx.c \ ./glpapi14.c \ ./glpapi21.c \ ./wclique.c \ ./fhv.c \ ./glpini01.c \ ./mc21a.c \ ./glpapi02.c \ ./cfg.c \ ./glpios10.c \ ./glpmpl05.c \ ./wclique1.c \ ./jd.c \ ./glpios07.c \ ./glpsql.c \ ./glpios06.c \ ./glpini02.c \ ./glpscf.c \ ./relax4.c \ OBJS = $(SOURCES:.c=.o) PKG_CPPFLAGS = -I. all: libglpk.a libglpk.a: $(OBJS) $(AR) crs $@ $(OBJS) Rglpk/src/GLPK/glpapi04.c0000644000176000001440000001104012245352174014472 0ustar ripleyusers/* glpapi04.c (problem scaling routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpapi.h" /*********************************************************************** * NAME * * glp_set_rii - set (change) row scale factor * * SYNOPSIS * * void glp_set_rii(glp_prob *lp, int i, double rii); * * DESCRIPTION * * The routine glp_set_rii sets (changes) the scale factor r[i,i] for * i-th row of the specified problem object. */ void glp_set_rii(glp_prob *lp, int i, double rii) { if (!(1 <= i && i <= lp->m)) xerror("glp_set_rii: i = %d; row number out of range\n", i); if (rii <= 0.0) xerror("glp_set_rii: i = %d; rii = %g; invalid scale factor\n", i, rii); if (lp->valid && lp->row[i]->rii != rii) { GLPAIJ *aij; for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next) { if (aij->col->stat == GLP_BS) { /* invalidate the basis factorization */ lp->valid = 0; break; } } } lp->row[i]->rii = rii; return; } /*********************************************************************** * NAME * * glp_set sjj - set (change) column scale factor * * SYNOPSIS * * void glp_set_sjj(glp_prob *lp, int j, double sjj); * * DESCRIPTION * * The routine glp_set_sjj sets (changes) the scale factor s[j,j] for * j-th column of the specified problem object. */ void glp_set_sjj(glp_prob *lp, int j, double sjj) { if (!(1 <= j && j <= lp->n)) xerror("glp_set_sjj: j = %d; column number out of range\n", j); if (sjj <= 0.0) xerror("glp_set_sjj: j = %d; sjj = %g; invalid scale factor\n", j, sjj); if (lp->valid && lp->col[j]->sjj != sjj && lp->col[j]->stat == GLP_BS) { /* invalidate the basis factorization */ lp->valid = 0; } lp->col[j]->sjj = sjj; return; } /*********************************************************************** * NAME * * glp_get_rii - retrieve row scale factor * * SYNOPSIS * * double glp_get_rii(glp_prob *lp, int i); * * RETURNS * * The routine glp_get_rii returns current scale factor r[i,i] for i-th * row of the specified problem object. */ double glp_get_rii(glp_prob *lp, int i) { if (!(1 <= i && i <= lp->m)) xerror("glp_get_rii: i = %d; row number out of range\n", i); return lp->row[i]->rii; } /*********************************************************************** * NAME * * glp_get_sjj - retrieve column scale factor * * SYNOPSIS * * double glp_get_sjj(glp_prob *lp, int j); * * RETURNS * * The routine glp_get_sjj returns current scale factor s[j,j] for j-th * column of the specified problem object. */ double glp_get_sjj(glp_prob *lp, int j) { if (!(1 <= j && j <= lp->n)) xerror("glp_get_sjj: j = %d; column number out of range\n", j); return lp->col[j]->sjj; } /*********************************************************************** * NAME * * glp_unscale_prob - unscale problem data * * SYNOPSIS * * void glp_unscale_prob(glp_prob *lp); * * DESCRIPTION * * The routine glp_unscale_prob performs unscaling of problem data for * the specified problem object. * * "Unscaling" means replacing the current scaling matrices R and S by * unity matrices that cancels the scaling effect. */ void glp_unscale_prob(glp_prob *lp) { int m = glp_get_num_rows(lp); int n = glp_get_num_cols(lp); int i, j; for (i = 1; i <= m; i++) glp_set_rii(lp, i, 1.0); for (j = 1; j <= n; j++) glp_set_sjj(lp, j, 1.0); return; } /* eof */ Rglpk/src/GLPK/glpnpp05.c0000644000176000001440000006401112245352174014525 0ustar ripleyusers/* glpnpp05.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpnpp.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 */ Rglpk/src/GLPK/cfg1.c0000644000176000001440000006034512245352174013706 0ustar ripleyusers/* cfg1.c (conflict graph) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "cfg.h" #include "glpapi.h" #include "wclique.h" #include "wclique1.h" /*********************************************************************** * cfg_build_graph - build conflict graph * * This routine builds the conflict graph. It analyzes the specified * problem object to discover original and implied packing inequalities * and adds corresponding cliques to the conflict graph. * * Packing inequality has the form: * * sum z[j] <= 1, (1) * j in J * * where z[j] = x[j] or z[j] = 1 - x[j], x[j] is an original binary * variable. Every packing inequality (1) is equivalent to a set of * edge inequalities: * * z[i] + z[j] <= 1 for all i, j in J, i != j, (2) * * and since every edge inequality (2) defines an edge in the conflict * graph, corresponding packing inequality (1) defines a clique. * * To discover packing inequalities the routine analyzes constraints * of the specified MIP. To simplify the analysis each constraint is * analyzed separately. The analysis is performed as follows. * * Let some original constraint be the following: * * L <= sum a[j] x[j] <= U. (3) * * To analyze it the routine analyzes two constraints of "not greater * than" type: * * sum (-a[j]) x[j] <= -L, (4) * * sum (+a[j]) x[j] <= +U, (5) * * which are relaxations of the original constraint (3). (If, however, * L = -oo, or U = +oo, corresponding constraint being redundant is not * analyzed.) * * Let a constraint of "not greater than" type be the following: * * sum a[j] x[j] + sum a[j] x[j] <= b, (6) * j in J j in J' * * where J is a subset of binary variables, J' is a subset of other * (continues and non-binary integer) variables. The constraint (6) is * is relaxed as follows, to eliminate non-binary variables: * * sum a[j] x[j] <= b - sum a[j] x[j] <= b', (7) * j in J j in J' * * b' = sup(b - sum a[j] x[j]) = * j in J' * * = b - inf(sum a[j] x[j]) = * * = b - sum inf(a[j] x[j]) = (8) * * = b - sum a[j] inf(x[j]) - sum a[j] sup(x[j]) = * a[j]>0 a[j]<0 * * = b - sum a[j] l[j] - sum a[j] u[j], * a[j]>0 a[j]<0 * * where l[j] and u[j] are, resp., lower and upper bounds of x[j]. * * Then the routine transforms the relaxed constraint containing only * binary variables: * * sum a[j] x[j] <= b (9) * * to an equivalent 0-1 knapsack constraint as follows: * * sum a[j] x[j] + sum a[j] x[j] <= b ==> * a[j]>0 a[j]<0 * * sum a[j] x[j] + sum a[j] (1 - x[j]) <= b ==> * a[j]>0 a[j]<0 (10) * * sum (+a[j]) x[j] + sum (-a[j]) x[j] <= b + sum (-a[j]) ==> * a[j]>0 a[j]<0 a[j]<0 * * sum a'[j] z[j] <= b', * * where a'[j] = |a[j]| > 0, and * * ( x[j] if a[j] > 0 * z[j] = < * ( 1 - x[j] if a[j] < 0 * * is a binary variable, which is either original binary variable x[j] * or its complement. * * Finally, the routine analyzes the resultant 0-1 knapsack inequality: * * sum a[j] z[j] <= b, (11) * j in J * * where all a[j] are positive, to discover clique inequalities (1), * which are valid for (11) and therefore valid for (3). (It is assumed * that the original MIP has been preprocessed, so it is not checked, * for example, that b > 0 or that a[j] <= b.) * * In principle, to discover any edge inequalities valid for (11) it * is sufficient to check whether a[i] + a[j] > b for all i, j in J, * i < j. However, this way requires O(|J|^2) checks, so the routine * analyses (11) in the following way, which is much more efficient in * many practical cases. * * 1. Let a[p] and a[q] be two minimal coefficients: * * a[p] = min a[j], (12) * * a[q] = min a[j], j != p, (13) * * such that * * a[p] + a[q] > b. (14) * * This means that a[i] + a[j] > b for any i, j in J, i != j, so * * z[i] + z[j] <= 1 (15) * * are valid for (11) for any i, j in J, i != j. This case means that * J define a clique in the conflict graph. * * 2. Otherwise, let a[p] and [q] be two maximal coefficients: * * a[p] = max a[j], (16) * * a[q] = max a[j], j != p, (17) * * such that * * a[p] + a[q] <= b. (18) * * This means that a[i] + a[j] <= b for any i, j in J, i != j, so in * this case no valid edge inequalities for (11) exist. * * 3. Otherwise, let all a[j] be ordered by descending their values: * * a[1] >= a[2] >= ... >= a[p-1] >= a[p] >= a[p+1] >= ... (19) * * where p is such that * * a[p-1] + a[p] > b, (20) * * a[p] + a[p+1] <= b. (21) * * (May note that due to the former two cases in this case we always * have 2 <= p <= |J|-1.) * * Since a[p] and a[p-1] are two minimal coefficients in the set * J' = {1, ..., p}, J' define a clique in the conflict graph for the * same reason as in the first case. Similarly, since a[p] and a[p+1] * are two maximal coefficients in the set J" = {p, ..., |J|}, no edge * inequalities exist for all i, j in J" for the same reason as in the * second case. Thus, to discover other edge inequalities (15) valid * for (11), the routine checks if a[i] + a[j] > b for all i in J', * j in J", i != j. */ #define is_binary(j) \ (P->col[j]->kind == GLP_IV && P->col[j]->type == GLP_DB && \ P->col[j]->lb == 0.0 && P->col[j]->ub == 1.0) /* check if x[j] is binary variable */ struct term { int ind; double val; }; /* term a[j] * z[j] used to sort a[j]'s */ static int fcmp(const void *e1, const void *e2) { /* auxiliary routine called from qsort */ const struct term *t1 = e1, *t2 = e2; if (t1->val > t2->val) return -1; else if (t1->val < t2->val) return +1; else return 0; } static void analyze_ineq(glp_prob *P, CFG *G, int len, int ind[], double val[], double rhs, struct term t[]) { /* analyze inequality constraint (6) */ /* P is the original MIP * G is the conflict graph to be built * len is the number of terms in the constraint * ind[1], ..., ind[len] are indices of variables x[j] * val[1], ..., val[len] are constraint coefficients a[j] * rhs is the right-hand side b * t[1+len] is a working array */ int j, k, kk, p, q, type, new_len; /* eliminate non-binary variables; see (7) and (8) */ new_len = 0; for (k = 1; k <= len; k++) { /* get index of variable x[j] */ j = ind[k]; if (is_binary(j)) { /* x[j] remains in relaxed constraint */ new_len++; ind[new_len] = j; val[new_len] = val[k]; } else if (val[k] > 0.0) { /* eliminate non-binary x[j] in case a[j] > 0 */ /* b := b - a[j] * l[j]; see (8) */ type = P->col[j]->type; if (type == GLP_FR || type == GLP_UP) { /* x[j] has no lower bound */ goto done; } rhs -= val[k] * P->col[j]->lb; } else /* val[j] < 0.0 */ { /* eliminate non-binary x[j] in case a[j] < 0 */ /* b := b - a[j] * u[j]; see (8) */ type = P->col[j]->type; if (type == GLP_FR || type == GLP_LO) { /* x[j] has no upper bound */ goto done; } rhs -= val[k] * P->col[j]->ub; } } len = new_len; /* now we have the constraint (9) */ if (len <= 1) { /* at least two terms are needed */ goto done; } /* make all constraint coefficients positive; see (10) */ for (k = 1; k <= len; k++) { if (val[k] < 0.0) { /* a[j] < 0; substitute x[j] = 1 - x'[j], where x'[j] is * a complement binary variable */ ind[k] = -ind[k]; val[k] = -val[k]; rhs += val[k]; } } /* now we have 0-1 knapsack inequality (11) */ /* increase the right-hand side a bit to avoid false checks due * to rounding errors */ rhs += 0.001 * (1.0 + fabs(rhs)); /*** first case ***/ /* find two minimal coefficients a[p] and a[q] */ p = 0; for (k = 1; k <= len; k++) { if (p == 0 || val[p] > val[k]) p = k; } q = 0; for (k = 1; k <= len; k++) { if (k != p && (q == 0 || val[q] > val[k])) q = k; } xassert(p != 0 && q != 0 && p != q); /* check condition (14) */ if (val[p] + val[q] > rhs) { /* all z[j] define a clique in the conflict graph */ cfg_add_clique(G, len, ind); goto done; } /*** second case ***/ /* find two maximal coefficients a[p] and a[q] */ p = 0; for (k = 1; k <= len; k++) { if (p == 0 || val[p] < val[k]) p = k; } q = 0; for (k = 1; k <= len; k++) { if (k != p && (q == 0 || val[q] < val[k])) q = k; } xassert(p != 0 && q != 0 && p != q); /* check condition (18) */ if (val[p] + val[q] <= rhs) { /* no valid edge inequalities exist */ goto done; } /*** third case ***/ xassert(len >= 3); /* sort terms in descending order of coefficient values */ for (k = 1; k <= len; k++) { t[k].ind = ind[k]; t[k].val = val[k]; } qsort(&t[1], len, sizeof(struct term), fcmp); for (k = 1; k <= len; k++) { ind[k] = t[k].ind; val[k] = t[k].val; } /* now a[1] >= a[2] >= ... >= a[len-1] >= a[len] */ /* note that a[1] + a[2] > b and a[len-1] + a[len] <= b due two * the former two cases */ xassert(val[1] + val[2] > rhs); xassert(val[len-1] + val[len] <= rhs); /* find p according to conditions (20) and (21) */ for (p = 2; p < len; p++) { if (val[p] + val[p+1] <= rhs) break; } xassert(p < len); /* z[1], ..., z[p] define a clique in the conflict graph */ cfg_add_clique(G, p, ind); /* discover other edge inequalities */ for (k = 1; k <= p; k++) { for (kk = p; kk <= len; kk++) { if (k != kk && val[k] + val[kk] > rhs) { int iii[1+2]; iii[1] = ind[k]; iii[2] = ind[kk]; cfg_add_clique(G, 2, iii); } } } done: return; } CFG *cfg_build_graph(void *P_) { glp_prob *P = P_; int m = P->m; int n = P->n; CFG *G; int i, k, type, len, *ind; double *val; struct term *t; /* create the conflict graph (number of its vertices cannot be * greater than double number of binary variables) */ G = cfg_create_graph(n, 2 * glp_get_num_bin(P)); /* allocate working arrays */ ind = talloc(1+n, int); val = talloc(1+n, double); t = talloc(1+n, struct term); /* analyze constraints to discover edge inequalities */ for (i = 1; i <= m; i++) { type = P->row[i]->type; if (type == GLP_LO || type == GLP_DB || type == GLP_FX) { /* i-th row has lower bound */ /* analyze inequality sum (-a[j]) * x[j] <= -lb */ len = glp_get_mat_row(P, i, ind, val); for (k = 1; k <= len; k++) val[k] = -val[k]; analyze_ineq(P, G, len, ind, val, -P->row[i]->lb, t); } if (type == GLP_UP || type == GLP_DB || type == GLP_FX) { /* i-th row has upper bound */ /* analyze inequality sum (+a[j]) * x[j] <= +ub */ len = glp_get_mat_row(P, i, ind, val); analyze_ineq(P, G, len, ind, val, +P->row[i]->ub, t); } } /* free working arrays */ tfree(ind); tfree(val); tfree(t); return G; } /*********************************************************************** * cfg_find_clique - find maximum weight clique in conflict graph * * This routine finds a maximum weight clique in the conflict graph * G = (V, E), where the weight of vertex v in V is the value of * corresponding binary variable z (which is either an original binary * variable or its complement) in the optimal solution to LP relaxation * provided in the problem object. The goal is to find a clique in G, * whose weight is greater than 1, in which case corresponding packing * inequality is violated at the optimal point. * * On exit the routine stores vertex indices of the conflict graph * included in the clique found to locations ind[1], ..., ind[len], and * returns len, which is the clique size. The clique weight is stored * in location pointed to by the parameter sum. If no clique has been * found, the routine returns 0. * * Since the conflict graph may have a big number of vertices and be * quite dense, the routine uses an induced subgraph G' = (V', E'), * which is constructed as follows: * * 1. If the weight of some vertex v in V is zero (close to zero), it * is not included in V'. Obviously, including in a clique * zero-weight vertices does not change its weight, so if in G there * exist a clique of a non-zero weight, in G' exists a clique of the * same weight. This point is extremely important, because dropping * out zero-weight vertices can be done without retrieving lists of * adjacent vertices whose size may be very large. * * 2. Cumulative weight of vertex v in V is the sum of the weight of v * and weights of all vertices in V adjacent to v. Obviously, if * a clique includes a vertex v, the clique weight cannot be greater * than the cumulative weight of v. Since we are interested only in * cliques whose weight is greater than 1, vertices of V, whose * cumulative weight is not greater than 1, are not included in V'. * * May note that in many practical cases the size of the induced * subgraph G' is much less than the size of the original conflict * graph G due to many binary variables, whose optimal values are zero * or close to zero. For example, it may happen that |V| = 100,000 and * |E| = 1e9 while |V'| = 50 and |E'| = 1000. */ struct csa { /* common storage area */ glp_prob *P; /* original MIP */ CFG *G; /* original conflict graph G = (V, E), |V| = nv */ int *ind; /* int ind[1+nv]; */ /* working array */ /*--------------------------------------------------------------*/ /* induced subgraph G' = (V', E') of original conflict graph */ int nn; /* number of vertices in V' */ int *vtoi; /* int vtoi[1+nv]; */ /* vtoi[v] = i, 1 <= v <= nv, means that vertex v in V is vertex * i in V'; vtoi[v] = 0 means that vertex v is not included in * the subgraph */ int *itov; /* int itov[1+nv]; */ /* itov[i] = v, 1 <= i <= nn, means that vertex i in V' is vertex * v in V */ double *wgt; /* double wgt[1+nv]; */ /* wgt[i], 1 <= i <= nn, is a weight of vertex i in V', which is * the value of corresponding binary variable in optimal solution * to LP relaxation */ }; static void build_subgraph(struct csa *csa) { /* build induced subgraph */ glp_prob *P = csa->P; int n = P->n; CFG *G = csa->G; int *ind = csa->ind; int *pos = G->pos; int *neg = G->neg; int nv = G->nv; int *ref = G->ref; int *vtoi = csa->vtoi; int *itov = csa->itov; double *wgt = csa->wgt; int j, k, v, w, nn, len; double z, sum; /* initially induced subgraph is empty */ nn = 0; /* walk thru vertices of original conflict graph */ for (v = 1; v <= nv; v++) { /* determine value of binary variable z[j] that corresponds to * vertex v */ j = ref[v]; xassert(1 <= j && j <= n); if (pos[j] == v) { /* z[j] = x[j], where x[j] is original variable */ z = P->col[j]->prim; } else if (neg[j] == v) { /* z[j] = 1 - x[j], where x[j] is original variable */ z = 1.0 - P->col[j]->prim; } else xassert(v != v); /* if z[j] is close to zero, do not include v in the induced * subgraph */ if (z < 0.001) { vtoi[v] = 0; continue; } /* calculate cumulative weight of vertex v */ sum = z; /* walk thru all vertices adjacent to v */ len = cfg_get_adjacent(G, v, ind); for (k = 1; k <= len; k++) { /* there is an edge (v,w) in the conflict graph */ w = ind[k]; xassert(w != v); /* add value of z[j] that corresponds to vertex w */ j = ref[w]; xassert(1 <= j && j <= n); if (pos[j] == w) sum += P->col[j]->prim; else if (neg[j] == w) sum += 1.0 - P->col[j]->prim; else xassert(w != w); } /* cumulative weight of vertex v is an upper bound of weight * of any clique containing v; so if it not greater than 1, do * not include v in the induced subgraph */ if (sum < 1.010) { vtoi[v] = 0; continue; } /* include vertex v in the induced subgraph */ nn++; vtoi[v] = nn; itov[nn] = v; wgt[nn] = z; } /* induced subgraph has been built */ csa->nn = nn; return; } static int sub_adjacent(struct csa *csa, int i, int adj[]) { /* retrieve vertices of induced subgraph adjacent to specified * vertex */ CFG *G = csa->G; int nv = G->nv; int *ind = csa->ind; int nn = csa->nn; int *vtoi = csa->vtoi; int *itov = csa->itov; int j, k, v, w, len, len1; /* determine original vertex v corresponding to vertex i */ xassert(1 <= i && i <= nn); v = itov[i]; /* retrieve vertices adjacent to vertex v in original graph */ len1 = cfg_get_adjacent(G, v, ind); /* keep only adjacent vertices which are in induced subgraph and * change their numbers appropriately */ len = 0; for (k = 1; k <= len1; k++) { /* there exists edge (v, w) in original graph */ w = ind[k]; xassert(1 <= w && w <= nv && w != v); j = vtoi[w]; if (j != 0) { /* vertex w is vertex j in induced subgraph */ xassert(1 <= j && j <= nn && j != i); adj[++len] = j; } } return len; } static int find_clique(struct csa *csa, int c_ind[]) { /* find maximum weight clique in induced subgraph with exact * Ostergard's algorithm */ int nn = csa->nn; double *wgt = csa->wgt; int i, j, k, p, q, t, ne, nb, len, *iwt, *ind; unsigned char *a; xassert(nn >= 2); /* allocate working array */ ind = talloc(1+nn, int); /* calculate the number of elements in lower triangle (without * diagonal) of adjacency matrix of induced subgraph */ ne = (nn * (nn - 1)) / 2; /* calculate the number of bytes needed to store lower triangle * of adjacency matrix */ nb = (ne + (CHAR_BIT - 1)) / CHAR_BIT; /* allocate lower triangle of adjacency matrix */ a = talloc(nb, unsigned char); /* fill lower triangle of adjacency matrix */ memset(a, 0, nb); for (p = 1; p <= nn; p++) { /* retrieve vertices adjacent to vertex p */ len = sub_adjacent(csa, p, ind); for (k = 1; k <= len; k++) { /* there exists edge (p, q) in induced subgraph */ q = ind[k]; xassert(1 <= q && q <= nn && q != p); /* determine row and column indices of this edge in lower * triangle of adjacency matrix */ if (p > q) i = p, j = q; else /* p < q */ i = q, j = p; /* set bit a[i,j] to 1, i > j */ t = ((i - 1) * (i - 2)) / 2 + (j - 1); a[t / CHAR_BIT] |= (unsigned char)(1 << ((CHAR_BIT - 1) - t % CHAR_BIT)); } } /* scale vertex weights by 1000 and convert them to integers as * required by Ostergard's algorithm */ iwt = ind; for (i = 1; i <= nn; i++) { /* it is assumed that 0 <= wgt[i] <= 1 */ t = (int)(1000.0 * wgt[i] + 0.5); if (t < 0) t = 0; else if (t > 1000) t = 1000; iwt[i] = t; } /* find maximum weight clique */ len = wclique(nn, iwt, a, c_ind); /* free working arrays */ tfree(ind); tfree(a); /* return clique size to calling routine */ return len; } static int func(void *info, int i, int ind[]) { /* auxiliary routine used by routine find_clique1 */ struct csa *csa = info; xassert(1 <= i && i <= csa->nn); return sub_adjacent(csa, i, ind); } static int find_clique1(struct csa *csa, int c_ind[]) { /* find maximum weight clique in induced subgraph with greedy * heuristic */ int nn = csa->nn; double *wgt = csa->wgt; int len; xassert(nn >= 2); len = wclique1(nn, wgt, func, csa, c_ind); /* return clique size to calling routine */ return len; } int cfg_find_clique(void *P, CFG *G, int ind[], double *sum_) { int nv = G->nv; struct csa csa; int i, k, len; double sum; /* initialize common storage area */ csa.P = P; csa.G = G; csa.ind = talloc(1+nv, int); csa.nn = -1; csa.vtoi = talloc(1+nv, int); csa.itov = talloc(1+nv, int); csa.wgt = talloc(1+nv, double); /* build induced subgraph */ build_subgraph(&csa); #ifdef GLP_DEBUG xprintf("nn = %d\n", csa.nn); #endif /* if subgraph has less than two vertices, do nothing */ if (csa.nn < 2) { len = 0; sum = 0.0; goto skip; } /* find maximum weight clique in induced subgraph */ #if 1 /* FIXME */ if (csa.nn <= 50) #endif { /* induced subgraph is small; use exact algorithm */ len = find_clique(&csa, ind); } else { /* induced subgraph is large; use greedy heuristic */ len = find_clique1(&csa, ind); } /* do not report clique, if it has less than two vertices */ if (len < 2) { len = 0; sum = 0.0; goto skip; } /* convert indices of clique vertices from induced subgraph to * original conflict graph and compute clique weight */ sum = 0.0; for (k = 1; k <= len; k++) { i = ind[k]; xassert(1 <= i && i <= csa.nn); sum += csa.wgt[i]; ind[k] = csa.itov[i]; } skip: /* free working arrays */ tfree(csa.ind); tfree(csa.vtoi); tfree(csa.itov); tfree(csa.wgt); /* return to calling routine */ *sum_ = sum; return len; } /* eof */ Rglpk/src/GLPK/glplpf.c0000644000176000001440000007745312245352174014362 0ustar ripleyusers/* glplpf.c (LP basis factorization, Schur complement version) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glplpf.h" #include "env.h" #define xfault xerror #define GLPLPF_DEBUG 0 /* CAUTION: DO NOT CHANGE THE LIMIT BELOW */ #define M_MAX 100000000 /* = 100*10^6 */ /* maximal order of the basis matrix */ /*********************************************************************** * NAME * * lpf_create_it - create LP basis factorization * * SYNOPSIS * * #include "glplpf.h" * LPF *lpf_create_it(void); * * DESCRIPTION * * The routine lpf_create_it creates a program object, which represents * a factorization of LP basis. * * RETURNS * * The routine lpf_create_it returns a pointer to the object created. */ LPF *lpf_create_it(void) { LPF *lpf; #if GLPLPF_DEBUG xprintf("lpf_create_it: warning: debug mode enabled\n"); #endif lpf = xmalloc(sizeof(LPF)); lpf->valid = 0; lpf->m0_max = lpf->m0 = 0; #if 0 /* 06/VI-2013 */ lpf->luf = luf_create_it(); #else lpf->lufint = lufint_create(); #endif lpf->m = 0; lpf->B = NULL; lpf->n_max = 50; lpf->n = 0; lpf->R_ptr = lpf->R_len = NULL; lpf->S_ptr = lpf->S_len = NULL; lpf->scf = NULL; lpf->P_row = lpf->P_col = NULL; lpf->Q_row = lpf->Q_col = NULL; lpf->v_size = 1000; lpf->v_ptr = 0; lpf->v_ind = NULL; lpf->v_val = NULL; lpf->work1 = lpf->work2 = NULL; return lpf; } /*********************************************************************** * NAME * * lpf_factorize - compute LP basis factorization * * SYNOPSIS * * #include "glplpf.h" * int lpf_factorize(LPF *lpf, int m, const int bh[], int (*col) * (void *info, int j, int ind[], double val[]), void *info); * * DESCRIPTION * * The routine lpf_factorize computes the factorization of the basis * matrix B specified by the routine col. * * The parameter lpf specified the basis factorization data structure * created with the routine lpf_create_it. * * The parameter m specifies the order of B, m > 0. * * The array bh specifies the basis header: bh[j], 1 <= j <= m, is the * number of j-th column of B in some original matrix. The array bh is * optional and can be specified as NULL. * * The formal routine col specifies the matrix B to be factorized. To * obtain j-th column of A the routine lpf_factorize calls the routine * col with the parameter j (1 <= j <= n). In response the routine col * should store row indices and numerical values of non-zero elements * of j-th column of B to locations ind[1,...,len] and val[1,...,len], * respectively, where len is the number of non-zeros in j-th column * returned on exit. Neither zero nor duplicate elements are allowed. * * The parameter info is a transit pointer passed to the routine col. * * RETURNS * * 0 The factorization has been successfully computed. * * LPF_ESING * The specified matrix is singular within the working precision. * * LPF_ECOND * The specified matrix is ill-conditioned. * * For more details see comments to the routine luf_factorize. */ int lpf_factorize(LPF *lpf, int m, const int bh[], int (*col) (void *info, int j, int ind[], double val[]), void *info) { int k, ret; #if GLPLPF_DEBUG int i, j, len, *ind; double *B, *val; #endif xassert(bh == bh); if (m < 1) xfault("lpf_factorize: m = %d; invalid parameter\n", m); if (m > M_MAX) xfault("lpf_factorize: m = %d; matrix too big\n", m); lpf->m0 = lpf->m = m; /* invalidate the factorization */ lpf->valid = 0; /* allocate/reallocate arrays, if necessary */ if (lpf->R_ptr == NULL) lpf->R_ptr = xcalloc(1+lpf->n_max, sizeof(int)); if (lpf->R_len == NULL) lpf->R_len = xcalloc(1+lpf->n_max, sizeof(int)); if (lpf->S_ptr == NULL) lpf->S_ptr = xcalloc(1+lpf->n_max, sizeof(int)); if (lpf->S_len == NULL) lpf->S_len = xcalloc(1+lpf->n_max, sizeof(int)); if (lpf->scf == NULL) lpf->scf = scf_create_it(lpf->n_max); if (lpf->v_ind == NULL) lpf->v_ind = xcalloc(1+lpf->v_size, sizeof(int)); if (lpf->v_val == NULL) lpf->v_val = xcalloc(1+lpf->v_size, sizeof(double)); if (lpf->m0_max < m) { if (lpf->P_row != NULL) xfree(lpf->P_row); if (lpf->P_col != NULL) xfree(lpf->P_col); if (lpf->Q_row != NULL) xfree(lpf->Q_row); if (lpf->Q_col != NULL) xfree(lpf->Q_col); if (lpf->work1 != NULL) xfree(lpf->work1); if (lpf->work2 != NULL) xfree(lpf->work2); lpf->m0_max = m + 100; lpf->P_row = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int)); lpf->P_col = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int)); lpf->Q_row = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int)); lpf->Q_col = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int)); lpf->work1 = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(double)); lpf->work2 = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(double)); } /* try to factorize the basis matrix */ #if 0 /* 06/VI-2013 */ switch (luf_factorize(lpf->luf, m, col, info)) { case 0: break; case LUF_ESING: ret = LPF_ESING; goto done; case LUF_ECOND: ret = LPF_ECOND; goto done; default: xassert(lpf != lpf); } #else if (lufint_factorize(lpf->lufint, m, col, info) != 0) { ret = LPF_ESING; goto done; } #endif /* the basis matrix has been successfully factorized */ lpf->valid = 1; #if GLPLPF_DEBUG /* store the basis matrix for debugging */ if (lpf->B != NULL) xfree(lpf->B); xassert(m <= 32767); lpf->B = B = xcalloc(1+m*m, sizeof(double)); ind = xcalloc(1+m, sizeof(int)); val = xcalloc(1+m, sizeof(double)); for (k = 1; k <= m * m; k++) B[k] = 0.0; for (j = 1; j <= m; j++) { len = col(info, j, ind, val); xassert(0 <= len && len <= m); for (k = 1; k <= len; k++) { i = ind[k]; xassert(1 <= i && i <= m); xassert(B[(i - 1) * m + j] == 0.0); xassert(val[k] != 0.0); B[(i - 1) * m + j] = val[k]; } } xfree(ind); xfree(val); #endif /* B = B0, so there are no additional rows/columns */ lpf->n = 0; /* reset the Schur complement factorization */ scf_reset_it(lpf->scf); /* P := Q := I */ for (k = 1; k <= m; k++) { lpf->P_row[k] = lpf->P_col[k] = k; lpf->Q_row[k] = lpf->Q_col[k] = k; } /* make all SVA locations free */ lpf->v_ptr = 1; ret = 0; done: /* return to the calling program */ return ret; } /*********************************************************************** * The routine r_prod computes the product y := y + alpha * R * x, * where x is a n-vector, alpha is a scalar, y is a m0-vector. * * Since matrix R is available by columns, the product is computed as * a linear combination: * * y := y + alpha * (R[1] * x[1] + ... + R[n] * x[n]), * * where R[j] is j-th column of R. */ static void r_prod(LPF *lpf, double y[], double a, const double x[]) { int n = lpf->n; int *R_ptr = lpf->R_ptr; int *R_len = lpf->R_len; int *v_ind = lpf->v_ind; double *v_val = lpf->v_val; int j, beg, end, ptr; double t; for (j = 1; j <= n; j++) { if (x[j] == 0.0) continue; /* y := y + alpha * R[j] * x[j] */ t = a * x[j]; beg = R_ptr[j]; end = beg + R_len[j]; for (ptr = beg; ptr < end; ptr++) y[v_ind[ptr]] += t * v_val[ptr]; } return; } /*********************************************************************** * The routine rt_prod computes the product y := y + alpha * R' * x, * where R' is a matrix transposed to R, x is a m0-vector, alpha is a * scalar, y is a n-vector. * * Since matrix R is available by columns, the product components are * computed as inner products: * * y[j] := y[j] + alpha * (j-th column of R) * x * * for j = 1, 2, ..., n. */ static void rt_prod(LPF *lpf, double y[], double a, const double x[]) { int n = lpf->n; int *R_ptr = lpf->R_ptr; int *R_len = lpf->R_len; int *v_ind = lpf->v_ind; double *v_val = lpf->v_val; int j, beg, end, ptr; double t; for (j = 1; j <= n; j++) { /* t := (j-th column of R) * x */ t = 0.0; beg = R_ptr[j]; end = beg + R_len[j]; for (ptr = beg; ptr < end; ptr++) t += v_val[ptr] * x[v_ind[ptr]]; /* y[j] := y[j] + alpha * t */ y[j] += a * t; } return; } /*********************************************************************** * The routine s_prod computes the product y := y + alpha * S * x, * where x is a m0-vector, alpha is a scalar, y is a n-vector. * * Since matrix S is available by rows, the product components are * computed as inner products: * * y[i] = y[i] + alpha * (i-th row of S) * x * * for i = 1, 2, ..., n. */ static void s_prod(LPF *lpf, double y[], double a, const double x[]) { int n = lpf->n; int *S_ptr = lpf->S_ptr; int *S_len = lpf->S_len; int *v_ind = lpf->v_ind; double *v_val = lpf->v_val; int i, beg, end, ptr; double t; for (i = 1; i <= n; i++) { /* t := (i-th row of S) * x */ t = 0.0; beg = S_ptr[i]; end = beg + S_len[i]; for (ptr = beg; ptr < end; ptr++) t += v_val[ptr] * x[v_ind[ptr]]; /* y[i] := y[i] + alpha * t */ y[i] += a * t; } return; } /*********************************************************************** * The routine st_prod computes the product y := y + alpha * S' * x, * where S' is a matrix transposed to S, x is a n-vector, alpha is a * scalar, y is m0-vector. * * Since matrix R is available by rows, the product is computed as a * linear combination: * * y := y + alpha * (S'[1] * x[1] + ... + S'[n] * x[n]), * * where S'[i] is i-th row of S. */ static void st_prod(LPF *lpf, double y[], double a, const double x[]) { int n = lpf->n; int *S_ptr = lpf->S_ptr; int *S_len = lpf->S_len; int *v_ind = lpf->v_ind; double *v_val = lpf->v_val; int i, beg, end, ptr; double t; for (i = 1; i <= n; i++) { if (x[i] == 0.0) continue; /* y := y + alpha * S'[i] * x[i] */ t = a * x[i]; beg = S_ptr[i]; end = beg + S_len[i]; for (ptr = beg; ptr < end; ptr++) y[v_ind[ptr]] += t * v_val[ptr]; } return; } #if GLPLPF_DEBUG /*********************************************************************** * The routine check_error computes the maximal relative error between * left- and right-hand sides for the system B * x = b (if tr is zero) * or B' * x = b (if tr is non-zero), where B' is a matrix transposed * to B. (This routine is intended for debugging only.) */ static void check_error(LPF *lpf, int tr, const double x[], const double b[]) { int m = lpf->m; double *B = lpf->B; int i, j; double d, dmax = 0.0, s, t, tmax; for (i = 1; i <= m; i++) { s = 0.0; tmax = 1.0; for (j = 1; j <= m; j++) { if (!tr) t = B[m * (i - 1) + j] * x[j]; else t = B[m * (j - 1) + i] * x[j]; if (tmax < fabs(t)) tmax = fabs(t); s += t; } d = fabs(s - b[i]) / tmax; if (dmax < d) dmax = d; } if (dmax > 1e-8) xprintf("%s: dmax = %g; relative error too large\n", !tr ? "lpf_ftran" : "lpf_btran", dmax); return; } #endif /*********************************************************************** * NAME * * lpf_ftran - perform forward transformation (solve system B*x = b) * * SYNOPSIS * * #include "glplpf.h" * void lpf_ftran(LPF *lpf, double x[]); * * DESCRIPTION * * The routine lpf_ftran performs forward transformation, i.e. solves * the system B*x = b, where B is the basis matrix, x is the vector of * unknowns to be computed, b is the vector of right-hand sides. * * On entry elements of the vector b should be stored in dense format * in locations x[1], ..., x[m], where m is the number of rows. On exit * the routine stores elements of the vector x in the same locations. * * BACKGROUND * * Solution of the system B * x = b can be obtained by solving the * following augmented system: * * ( B F^) ( x ) ( b ) * ( ) ( ) = ( ) * ( G^ H^) ( y ) ( 0 ) * * which, using the main equality, can be written as follows: * * ( L0 0 ) ( U0 R ) ( x ) ( b ) * P ( ) ( ) Q ( ) = ( ) * ( S I ) ( 0 C ) ( y ) ( 0 ) * * therefore, * * ( x ) ( U0 R )-1 ( L0 0 )-1 ( b ) * ( ) = Q' ( ) ( ) P' ( ) * ( y ) ( 0 C ) ( S I ) ( 0 ) * * Thus, computing the solution includes the following steps: * * 1. Compute * * ( f ) ( b ) * ( ) = P' ( ) * ( g ) ( 0 ) * * 2. Solve the system * * ( f1 ) ( L0 0 )-1 ( f ) ( L0 0 ) ( f1 ) ( f ) * ( ) = ( ) ( ) => ( ) ( ) = ( ) * ( g1 ) ( S I ) ( g ) ( S I ) ( g1 ) ( g ) * * from which it follows that: * * { L0 * f1 = f f1 = inv(L0) * f * { => * { S * f1 + g1 = g g1 = g - S * f1 * * 3. Solve the system * * ( f2 ) ( U0 R )-1 ( f1 ) ( U0 R ) ( f2 ) ( f1 ) * ( ) = ( ) ( ) => ( ) ( ) = ( ) * ( g2 ) ( 0 C ) ( g1 ) ( 0 C ) ( g2 ) ( g1 ) * * from which it follows that: * * { U0 * f2 + R * g2 = f1 f2 = inv(U0) * (f1 - R * g2) * { => * { C * g2 = g1 g2 = inv(C) * g1 * * 4. Compute * * ( x ) ( f2 ) * ( ) = Q' ( ) * ( y ) ( g2 ) */ void lpf_ftran(LPF *lpf, double x[]) { int m0 = lpf->m0; int m = lpf->m; int n = lpf->n; int *P_col = lpf->P_col; int *Q_col = lpf->Q_col; double *fg = lpf->work1; double *f = fg; double *g = fg + m0; int i, ii; #if GLPLPF_DEBUG double *b; #endif if (!lpf->valid) xfault("lpf_ftran: the factorization is not valid\n"); xassert(0 <= m && m <= m0 + n); #if GLPLPF_DEBUG /* save the right-hand side vector */ b = xcalloc(1+m, sizeof(double)); for (i = 1; i <= m; i++) b[i] = x[i]; #endif /* (f g) := inv(P) * (b 0) */ for (i = 1; i <= m0 + n; i++) fg[i] = ((ii = P_col[i]) <= m ? x[ii] : 0.0); /* f1 := inv(L0) * f */ #if 0 /* 06/VI-2013 */ luf_f_solve(lpf->luf, 0, f); #else luf_f_solve(lpf->lufint->luf, f); #endif /* g1 := g - S * f1 */ s_prod(lpf, g, -1.0, f); /* g2 := inv(C) * g1 */ scf_solve_it(lpf->scf, 0, g); /* f2 := inv(U0) * (f1 - R * g2) */ r_prod(lpf, f, -1.0, g); #if 0 /* 06/VI-2013 */ luf_v_solve(lpf->luf, 0, f); #else { double *work = lpf->lufint->sgf->work; luf_v_solve(lpf->lufint->luf, f, work); memcpy(&f[1], &work[1], m0 * sizeof(double)); } #endif /* (x y) := inv(Q) * (f2 g2) */ for (i = 1; i <= m; i++) x[i] = fg[Q_col[i]]; #if GLPLPF_DEBUG /* check relative error in solution */ check_error(lpf, 0, x, b); xfree(b); #endif return; } /*********************************************************************** * NAME * * lpf_btran - perform backward transformation (solve system B'*x = b) * * SYNOPSIS * * #include "glplpf.h" * void lpf_btran(LPF *lpf, double x[]); * * DESCRIPTION * * The routine lpf_btran performs backward transformation, i.e. solves * the system B'*x = b, where B' is a matrix transposed to the basis * matrix B, x is the vector of unknowns to be computed, b is the vector * of right-hand sides. * * On entry elements of the vector b should be stored in dense format * in locations x[1], ..., x[m], where m is the number of rows. On exit * the routine stores elements of the vector x in the same locations. * * BACKGROUND * * Solution of the system B' * x = b, where B' is a matrix transposed * to B, can be obtained by solving the following augmented system: * * ( B F^)T ( x ) ( b ) * ( ) ( ) = ( ) * ( G^ H^) ( y ) ( 0 ) * * which, using the main equality, can be written as follows: * * T ( U0 R )T ( L0 0 )T T ( x ) ( b ) * Q ( ) ( ) P ( ) = ( ) * ( 0 C ) ( S I ) ( y ) ( 0 ) * * or, equivalently, as follows: * * ( U'0 0 ) ( L'0 S') ( x ) ( b ) * Q' ( ) ( ) P' ( ) = ( ) * ( R' C') ( 0 I ) ( y ) ( 0 ) * * therefore, * * ( x ) ( L'0 S')-1 ( U'0 0 )-1 ( b ) * ( ) = P ( ) ( ) Q ( ) * ( y ) ( 0 I ) ( R' C') ( 0 ) * * Thus, computing the solution includes the following steps: * * 1. Compute * * ( f ) ( b ) * ( ) = Q ( ) * ( g ) ( 0 ) * * 2. Solve the system * * ( f1 ) ( U'0 0 )-1 ( f ) ( U'0 0 ) ( f1 ) ( f ) * ( ) = ( ) ( ) => ( ) ( ) = ( ) * ( g1 ) ( R' C') ( g ) ( R' C') ( g1 ) ( g ) * * from which it follows that: * * { U'0 * f1 = f f1 = inv(U'0) * f * { => * { R' * f1 + C' * g1 = g g1 = inv(C') * (g - R' * f1) * * 3. Solve the system * * ( f2 ) ( L'0 S')-1 ( f1 ) ( L'0 S') ( f2 ) ( f1 ) * ( ) = ( ) ( ) => ( ) ( ) = ( ) * ( g2 ) ( 0 I ) ( g1 ) ( 0 I ) ( g2 ) ( g1 ) * * from which it follows that: * * { L'0 * f2 + S' * g2 = f1 * { => f2 = inv(L'0) * ( f1 - S' * g2) * { g2 = g1 * * 4. Compute * * ( x ) ( f2 ) * ( ) = P ( ) * ( y ) ( g2 ) */ void lpf_btran(LPF *lpf, double x[]) { int m0 = lpf->m0; int m = lpf->m; int n = lpf->n; int *P_row = lpf->P_row; int *Q_row = lpf->Q_row; double *fg = lpf->work1; double *f = fg; double *g = fg + m0; int i, ii; #if GLPLPF_DEBUG double *b; #endif if (!lpf->valid) xfault("lpf_btran: the factorization is not valid\n"); xassert(0 <= m && m <= m0 + n); #if GLPLPF_DEBUG /* save the right-hand side vector */ b = xcalloc(1+m, sizeof(double)); for (i = 1; i <= m; i++) b[i] = x[i]; #endif /* (f g) := Q * (b 0) */ for (i = 1; i <= m0 + n; i++) fg[i] = ((ii = Q_row[i]) <= m ? x[ii] : 0.0); /* f1 := inv(U'0) * f */ #if 0 /* 06/VI-2013 */ luf_v_solve(lpf->luf, 1, f); #else { double *work = lpf->lufint->sgf->work; luf_vt_solve(lpf->lufint->luf, f, work); memcpy(&f[1], &work[1], m0 * sizeof(double)); } #endif /* g1 := inv(C') * (g - R' * f1) */ rt_prod(lpf, g, -1.0, f); scf_solve_it(lpf->scf, 1, g); /* g2 := g1 */ g = g; /* f2 := inv(L'0) * (f1 - S' * g2) */ st_prod(lpf, f, -1.0, g); #if 0 /* 06/VI-2013 */ luf_f_solve(lpf->luf, 1, f); #else luf_ft_solve(lpf->lufint->luf, f); #endif /* (x y) := P * (f2 g2) */ for (i = 1; i <= m; i++) x[i] = fg[P_row[i]]; #if GLPLPF_DEBUG /* check relative error in solution */ check_error(lpf, 1, x, b); xfree(b); #endif return; } /*********************************************************************** * The routine enlarge_sva enlarges the Sparse Vector Area to new_size * locations by reallocating the arrays v_ind and v_val. */ static void enlarge_sva(LPF *lpf, int new_size) { int v_size = lpf->v_size; int used = lpf->v_ptr - 1; int *v_ind = lpf->v_ind; double *v_val = lpf->v_val; xassert(v_size < new_size); while (v_size < new_size) v_size += v_size; lpf->v_size = v_size; lpf->v_ind = xcalloc(1+v_size, sizeof(int)); lpf->v_val = xcalloc(1+v_size, sizeof(double)); xassert(used >= 0); memcpy(&lpf->v_ind[1], &v_ind[1], used * sizeof(int)); memcpy(&lpf->v_val[1], &v_val[1], used * sizeof(double)); xfree(v_ind); xfree(v_val); return; } /*********************************************************************** * NAME * * lpf_update_it - update LP basis factorization * * SYNOPSIS * * #include "glplpf.h" * int lpf_update_it(LPF *lpf, int j, int bh, int len, const int ind[], * const double val[]); * * DESCRIPTION * * The routine lpf_update_it updates the factorization of the basis * matrix B after replacing its j-th column by a new vector. * * The parameter j specifies the number of column of B, which has been * replaced, 1 <= j <= m, where m is the order of B. * * The parameter bh specifies the basis header entry for the new column * of B, which is the number of the new column in some original matrix. * This parameter is optional and can be specified as 0. * * Row indices and numerical values of non-zero elements of the new * column of B should be placed in locations ind[1], ..., ind[len] and * val[1], ..., val[len], resp., where len is the number of non-zeros * in the column. Neither zero nor duplicate elements are allowed. * * RETURNS * * 0 The factorization has been successfully updated. * * LPF_ESING * New basis B is singular within the working precision. * * LPF_ELIMIT * Maximal number of additional rows and columns has been reached. * * BACKGROUND * * Let j-th column of the current basis matrix B have to be replaced by * a new column a. This replacement is equivalent to removing the old * j-th column by fixing it at zero and introducing the new column as * follows: * * ( B F^| a ) * ( B F^) ( | ) * ( ) ---> ( G^ H^| 0 ) * ( G^ H^) (-------+---) * ( e'j 0 | 0 ) * * where ej is a unit vector with 1 in j-th position which used to fix * the old j-th column of B (at zero). Then using the main equality we * have: * * ( B F^| a ) ( B0 F | f ) * ( | ) ( P 0 ) ( | ) ( Q 0 ) * ( G^ H^| 0 ) = ( ) ( G H | g ) ( ) = * (-------+---) ( 0 1 ) (-------+---) ( 0 1 ) * ( e'j 0 | 0 ) ( v' w'| 0 ) * * [ ( B0 F )| ( f ) ] [ ( B0 F ) | ( f ) ] * [ P ( )| P ( ) ] ( Q 0 ) [ P ( ) Q| P ( ) ] * = [ ( G H )| ( g ) ] ( ) = [ ( G H ) | ( g ) ] * [------------+-------- ] ( 0 1 ) [-------------+---------] * [ ( v' w')| 0 ] [ ( v' w') Q| 0 ] * * where: * * ( a ) ( f ) ( f ) ( a ) * ( ) = P ( ) => ( ) = P' * ( ) * ( 0 ) ( g ) ( g ) ( 0 ) * * ( ej ) ( v ) ( v ) ( ej ) * ( e'j 0 ) = ( v' w' ) Q => ( ) = Q' ( ) => ( ) = Q ( ) * ( 0 ) ( w ) ( w ) ( 0 ) * * On the other hand: * * ( B0| F f ) * ( P 0 ) (---+------) ( Q 0 ) ( B0 new F ) * ( ) ( G | H g ) ( ) = new P ( ) new Q * ( 0 1 ) ( | ) ( 0 1 ) ( new G new H ) * ( v'| w' 0 ) * * where: * ( G ) ( H g ) * new F = ( F f ), new G = ( ), new H = ( ), * ( v') ( w' 0 ) * * ( P 0 ) ( Q 0 ) * new P = ( ) , new Q = ( ) . * ( 0 1 ) ( 0 1 ) * * The factorization structure for the new augmented matrix remains the * same, therefore: * * ( B0 new F ) ( L0 0 ) ( U0 new R ) * new P ( ) new Q = ( ) ( ) * ( new G new H ) ( new S I ) ( 0 new C ) * * where: * * new F = L0 * new R => * * new R = inv(L0) * new F = inv(L0) * (F f) = ( R inv(L0)*f ) * * new G = new S * U0 => * * ( G ) ( S ) * new S = new G * inv(U0) = ( ) * inv(U0) = ( ) * ( v') ( v'*inv(U0) ) * * new H = new S * new R + new C => * * new C = new H - new S * new R = * * ( H g ) ( S ) * = ( ) - ( ) * ( R inv(L0)*f ) = * ( w' 0 ) ( v'*inv(U0) ) * * ( H - S*R g - S*inv(L0)*f ) ( C x ) * = ( ) = ( ) * ( w'- v'*inv(U0)*R -v'*inv(U0)*inv(L0)*f) ( y' z ) * * Note that new C is resulted by expanding old C with new column x, * row y', and diagonal element z, where: * * x = g - S * inv(L0) * f = g - S * (new column of R) * * y = w - R'* inv(U'0)* v = w - R'* (new row of S) * * z = - (new row of S) * (new column of R) * * Finally, to replace old B by new B we have to permute j-th and last * (just added) columns of the matrix * * ( B F^| a ) * ( | ) * ( G^ H^| 0 ) * (-------+---) * ( e'j 0 | 0 ) * * and to keep the main equality do the same for matrix Q. */ int lpf_update_it(LPF *lpf, int j, int bh, int len, const int ind[], const double val[]) { int m0 = lpf->m0; int m = lpf->m; #if GLPLPF_DEBUG double *B = lpf->B; #endif int n = lpf->n; int *R_ptr = lpf->R_ptr; int *R_len = lpf->R_len; int *S_ptr = lpf->S_ptr; int *S_len = lpf->S_len; int *P_row = lpf->P_row; int *P_col = lpf->P_col; int *Q_row = lpf->Q_row; int *Q_col = lpf->Q_col; int v_ptr = lpf->v_ptr; int *v_ind = lpf->v_ind; double *v_val = lpf->v_val; double *a = lpf->work2; /* new column */ double *fg = lpf->work1, *f = fg, *g = fg + m0; double *vw = lpf->work2, *v = vw, *w = vw + m0; double *x = g, *y = w, z; int i, ii, k, ret; xassert(bh == bh); if (!lpf->valid) xfault("lpf_update_it: the factorization is not valid\n"); if (!(1 <= j && j <= m)) xfault("lpf_update_it: j = %d; column number out of range\n", j); xassert(0 <= m && m <= m0 + n); /* check if the basis factorization can be expanded */ if (n == lpf->n_max) { lpf->valid = 0; ret = LPF_ELIMIT; goto done; } /* convert new j-th column of B to dense format */ for (i = 1; i <= m; i++) a[i] = 0.0; for (k = 1; k <= len; k++) { i = ind[k]; if (!(1 <= i && i <= m)) xfault("lpf_update_it: ind[%d] = %d; row number out of rang" "e\n", k, i); if (a[i] != 0.0) xfault("lpf_update_it: ind[%d] = %d; duplicate row index no" "t allowed\n", k, i); if (val[k] == 0.0) xfault("lpf_update_it: val[%d] = %g; zero element not allow" "ed\n", k, val[k]); a[i] = val[k]; } #if GLPLPF_DEBUG /* change column in the basis matrix for debugging */ for (i = 1; i <= m; i++) B[(i - 1) * m + j] = a[i]; #endif /* (f g) := inv(P) * (a 0) */ for (i = 1; i <= m0+n; i++) fg[i] = ((ii = P_col[i]) <= m ? a[ii] : 0.0); /* (v w) := Q * (ej 0) */ for (i = 1; i <= m0+n; i++) vw[i] = 0.0; vw[Q_col[j]] = 1.0; /* f1 := inv(L0) * f (new column of R) */ #if 0 /* 06/VI-2013 */ luf_f_solve(lpf->luf, 0, f); #else luf_f_solve(lpf->lufint->luf, f); #endif /* v1 := inv(U'0) * v (new row of S) */ #if 0 /* 06/VI-2013 */ luf_v_solve(lpf->luf, 1, v); #else { double *work = lpf->lufint->sgf->work; luf_vt_solve(lpf->lufint->luf, v, work); memcpy(&v[1], &work[1], m0 * sizeof(double)); } #endif /* we need at most 2 * m0 available locations in the SVA to store new column of matrix R and new row of matrix S */ if (lpf->v_size < v_ptr + m0 + m0) { enlarge_sva(lpf, v_ptr + m0 + m0); v_ind = lpf->v_ind; v_val = lpf->v_val; } /* store new column of R */ R_ptr[n+1] = v_ptr; for (i = 1; i <= m0; i++) { if (f[i] != 0.0) v_ind[v_ptr] = i, v_val[v_ptr] = f[i], v_ptr++; } R_len[n+1] = v_ptr - lpf->v_ptr; lpf->v_ptr = v_ptr; /* store new row of S */ S_ptr[n+1] = v_ptr; for (i = 1; i <= m0; i++) { if (v[i] != 0.0) v_ind[v_ptr] = i, v_val[v_ptr] = v[i], v_ptr++; } S_len[n+1] = v_ptr - lpf->v_ptr; lpf->v_ptr = v_ptr; /* x := g - S * f1 (new column of C) */ s_prod(lpf, x, -1.0, f); /* y := w - R' * v1 (new row of C) */ rt_prod(lpf, y, -1.0, v); /* z := - v1 * f1 (new diagonal element of C) */ z = 0.0; for (i = 1; i <= m0; i++) z -= v[i] * f[i]; /* update factorization of new matrix C */ switch (scf_update_exp(lpf->scf, x, y, z)) { case 0: break; case SCF_ESING: lpf->valid = 0; ret = LPF_ESING; goto done; case SCF_ELIMIT: xassert(lpf != lpf); default: xassert(lpf != lpf); } /* expand matrix P */ P_row[m0+n+1] = P_col[m0+n+1] = m0+n+1; /* expand matrix Q */ Q_row[m0+n+1] = Q_col[m0+n+1] = m0+n+1; /* permute j-th and last (just added) column of matrix Q */ i = Q_col[j], ii = Q_col[m0+n+1]; Q_row[i] = m0+n+1, Q_col[m0+n+1] = i; Q_row[ii] = j, Q_col[j] = ii; /* increase the number of additional rows and columns */ lpf->n++; xassert(lpf->n <= lpf->n_max); /* the factorization has been successfully updated */ ret = 0; done: /* return to the calling program */ return ret; } /*********************************************************************** * NAME * * lpf_delete_it - delete LP basis factorization * * SYNOPSIS * * #include "glplpf.h" * void lpf_delete_it(LPF *lpf) * * DESCRIPTION * * The routine lpf_delete_it deletes LP basis factorization specified * by the parameter lpf and frees all memory allocated to this program * object. */ void lpf_delete_it(LPF *lpf) #if 0 /* 06/VI-2013 */ { luf_delete_it(lpf->luf); #else { lufint_delete(lpf->lufint); #endif #if GLPLPF_DEBUG if (lpf->B != NULL) xfree(lpf->B); #else xassert(lpf->B == NULL); #endif if (lpf->R_ptr != NULL) xfree(lpf->R_ptr); if (lpf->R_len != NULL) xfree(lpf->R_len); if (lpf->S_ptr != NULL) xfree(lpf->S_ptr); if (lpf->S_len != NULL) xfree(lpf->S_len); if (lpf->scf != NULL) scf_delete_it(lpf->scf); if (lpf->P_row != NULL) xfree(lpf->P_row); if (lpf->P_col != NULL) xfree(lpf->P_col); if (lpf->Q_row != NULL) xfree(lpf->Q_row); if (lpf->Q_col != NULL) xfree(lpf->Q_col); if (lpf->v_ind != NULL) xfree(lpf->v_ind); if (lpf->v_val != NULL) xfree(lpf->v_val); if (lpf->work1 != NULL) xfree(lpf->work1); if (lpf->work2 != NULL) xfree(lpf->work2); xfree(lpf); return; } /* eof */ Rglpk/src/GLPK/glpios02.c0000644000176000001440000006453312245352174014530 0ustar ripleyusers/* glpios02.c (preprocess current subproblem) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpios.h" /*********************************************************************** * prepare_row_info - prepare row info to determine implied bounds * * Given a row (linear form) * * n * sum a[j] * x[j] (1) * j=1 * * and bounds of columns (variables) * * l[j] <= x[j] <= u[j] (2) * * this routine computes f_min, j_min, f_max, j_max needed to determine * implied bounds. * * ALGORITHM * * Let J+ = {j : a[j] > 0} and J- = {j : a[j] < 0}. * * Parameters f_min and j_min are computed as follows: * * 1) if there is no x[k] such that k in J+ and l[k] = -inf or k in J- * and u[k] = +inf, then * * f_min := sum a[j] * l[j] + sum a[j] * u[j] * j in J+ j in J- * (3) * j_min := 0 * * 2) if there is exactly one x[k] such that k in J+ and l[k] = -inf * or k in J- and u[k] = +inf, then * * f_min := sum a[j] * l[j] + sum a[j] * u[j] * j in J+\{k} j in J-\{k} * (4) * j_min := k * * 3) if there are two or more x[k] such that k in J+ and l[k] = -inf * or k in J- and u[k] = +inf, then * * f_min := -inf * (5) * j_min := 0 * * Parameters f_max and j_max are computed in a similar way as follows: * * 1) if there is no x[k] such that k in J+ and u[k] = +inf or k in J- * and l[k] = -inf, then * * f_max := sum a[j] * u[j] + sum a[j] * l[j] * j in J+ j in J- * (6) * j_max := 0 * * 2) if there is exactly one x[k] such that k in J+ and u[k] = +inf * or k in J- and l[k] = -inf, then * * f_max := sum a[j] * u[j] + sum a[j] * l[j] * j in J+\{k} j in J-\{k} * (7) * j_max := k * * 3) if there are two or more x[k] such that k in J+ and u[k] = +inf * or k in J- and l[k] = -inf, then * * f_max := +inf * (8) * j_max := 0 */ struct f_info { int j_min, j_max; double f_min, f_max; }; static void prepare_row_info(int n, const double a[], const double l[], const double u[], struct f_info *f) { int j, j_min, j_max; double f_min, f_max; xassert(n >= 0); /* determine f_min and j_min */ f_min = 0.0, j_min = 0; for (j = 1; j <= n; j++) { if (a[j] > 0.0) { if (l[j] == -DBL_MAX) { if (j_min == 0) j_min = j; else { f_min = -DBL_MAX, j_min = 0; break; } } else f_min += a[j] * l[j]; } else if (a[j] < 0.0) { if (u[j] == +DBL_MAX) { if (j_min == 0) j_min = j; else { f_min = -DBL_MAX, j_min = 0; break; } } else f_min += a[j] * u[j]; } else xassert(a != a); } f->f_min = f_min, f->j_min = j_min; /* determine f_max and j_max */ f_max = 0.0, j_max = 0; for (j = 1; j <= n; j++) { if (a[j] > 0.0) { if (u[j] == +DBL_MAX) { if (j_max == 0) j_max = j; else { f_max = +DBL_MAX, j_max = 0; break; } } else f_max += a[j] * u[j]; } else if (a[j] < 0.0) { if (l[j] == -DBL_MAX) { if (j_max == 0) j_max = j; else { f_max = +DBL_MAX, j_max = 0; break; } } else f_max += a[j] * l[j]; } else xassert(a != a); } f->f_max = f_max, f->j_max = j_max; return; } /*********************************************************************** * row_implied_bounds - determine row implied bounds * * Given a row (linear form) * * n * sum a[j] * x[j] * j=1 * * and bounds of columns (variables) * * l[j] <= x[j] <= u[j] * * this routine determines implied bounds of the row. * * ALGORITHM * * Let J+ = {j : a[j] > 0} and J- = {j : a[j] < 0}. * * The implied lower bound of the row is computed as follows: * * L' := sum a[j] * l[j] + sum a[j] * u[j] (9) * j in J+ j in J- * * and as it follows from (3), (4), and (5): * * L' := if j_min = 0 then f_min else -inf (10) * * The implied upper bound of the row is computed as follows: * * U' := sum a[j] * u[j] + sum a[j] * l[j] (11) * j in J+ j in J- * * and as it follows from (6), (7), and (8): * * U' := if j_max = 0 then f_max else +inf (12) * * The implied bounds are stored in locations LL and UU. */ static void row_implied_bounds(const struct f_info *f, double *LL, double *UU) { *LL = (f->j_min == 0 ? f->f_min : -DBL_MAX); *UU = (f->j_max == 0 ? f->f_max : +DBL_MAX); return; } /*********************************************************************** * col_implied_bounds - determine column implied bounds * * Given a row (constraint) * * n * L <= sum a[j] * x[j] <= U (13) * j=1 * * and bounds of columns (variables) * * l[j] <= x[j] <= u[j] * * this routine determines implied bounds of variable x[k]. * * It is assumed that if L != -inf, the lower bound of the row can be * active, and if U != +inf, the upper bound of the row can be active. * * ALGORITHM * * From (13) it follows that * * L <= sum a[j] * x[j] + a[k] * x[k] <= U * j!=k * or * * L - sum a[j] * x[j] <= a[k] * x[k] <= U - sum a[j] * x[j] * j!=k j!=k * * Thus, if the row lower bound L can be active, implied lower bound of * term a[k] * x[k] can be determined as follows: * * ilb(a[k] * x[k]) = min(L - sum a[j] * x[j]) = * j!=k * (14) * = L - max sum a[j] * x[j] * j!=k * * where, as it follows from (6), (7), and (8) * * / f_max - a[k] * u[k], j_max = 0, a[k] > 0 * | * | f_max - a[k] * l[k], j_max = 0, a[k] < 0 * max sum a[j] * x[j] = { * j!=k | f_max, j_max = k * | * \ +inf, j_max != 0 * * and if the upper bound U can be active, implied upper bound of term * a[k] * x[k] can be determined as follows: * * iub(a[k] * x[k]) = max(U - sum a[j] * x[j]) = * j!=k * (15) * = U - min sum a[j] * x[j] * j!=k * * where, as it follows from (3), (4), and (5) * * / f_min - a[k] * l[k], j_min = 0, a[k] > 0 * | * | f_min - a[k] * u[k], j_min = 0, a[k] < 0 * min sum a[j] * x[j] = { * j!=k | f_min, j_min = k * | * \ -inf, j_min != 0 * * Since * * ilb(a[k] * x[k]) <= a[k] * x[k] <= iub(a[k] * x[k]) * * implied lower and upper bounds of x[k] are determined as follows: * * l'[k] := if a[k] > 0 then ilb / a[k] else ulb / a[k] (16) * * u'[k] := if a[k] > 0 then ulb / a[k] else ilb / a[k] (17) * * The implied bounds are stored in locations ll and uu. */ static void col_implied_bounds(const struct f_info *f, int n, const double a[], double L, double U, const double l[], const double u[], int k, double *ll, double *uu) { double ilb, iub; xassert(n >= 0); xassert(1 <= k && k <= n); /* determine implied lower bound of term a[k] * x[k] (14) */ if (L == -DBL_MAX || f->f_max == +DBL_MAX) ilb = -DBL_MAX; else if (f->j_max == 0) { if (a[k] > 0.0) { xassert(u[k] != +DBL_MAX); ilb = L - (f->f_max - a[k] * u[k]); } else if (a[k] < 0.0) { xassert(l[k] != -DBL_MAX); ilb = L - (f->f_max - a[k] * l[k]); } else xassert(a != a); } else if (f->j_max == k) ilb = L - f->f_max; else ilb = -DBL_MAX; /* determine implied upper bound of term a[k] * x[k] (15) */ if (U == +DBL_MAX || f->f_min == -DBL_MAX) iub = +DBL_MAX; else if (f->j_min == 0) { if (a[k] > 0.0) { xassert(l[k] != -DBL_MAX); iub = U - (f->f_min - a[k] * l[k]); } else if (a[k] < 0.0) { xassert(u[k] != +DBL_MAX); iub = U - (f->f_min - a[k] * u[k]); } else xassert(a != a); } else if (f->j_min == k) iub = U - f->f_min; else iub = +DBL_MAX; /* determine implied bounds of x[k] (16) and (17) */ #if 1 /* do not use a[k] if it has small magnitude to prevent wrong implied bounds; for example, 1e-15 * x1 >= x2 + x3, where x1 >= -10, x2, x3 >= 0, would lead to wrong conclusion that x1 >= 0 */ if (fabs(a[k]) < 1e-6) *ll = -DBL_MAX, *uu = +DBL_MAX; else #endif if (a[k] > 0.0) { *ll = (ilb == -DBL_MAX ? -DBL_MAX : ilb / a[k]); *uu = (iub == +DBL_MAX ? +DBL_MAX : iub / a[k]); } else if (a[k] < 0.0) { *ll = (iub == +DBL_MAX ? -DBL_MAX : iub / a[k]); *uu = (ilb == -DBL_MAX ? +DBL_MAX : ilb / a[k]); } else xassert(a != a); return; } /*********************************************************************** * check_row_bounds - check and relax original row bounds * * Given a row (constraint) * * n * L <= sum a[j] * x[j] <= U * j=1 * * and bounds of columns (variables) * * l[j] <= x[j] <= u[j] * * this routine checks the original row bounds L and U for feasibility * and redundancy. If the original lower bound L or/and upper bound U * cannot be active due to bounds of variables, the routine remove them * replacing by -inf or/and +inf, respectively. * * If no primal infeasibility is detected, the routine returns zero, * otherwise non-zero. */ static int check_row_bounds(const struct f_info *f, double *L_, double *U_) { int ret = 0; double L = *L_, U = *U_, LL, UU; /* determine implied bounds of the row */ row_implied_bounds(f, &LL, &UU); /* check if the original lower bound is infeasible */ if (L != -DBL_MAX) { double eps = 1e-3 * (1.0 + fabs(L)); if (UU < L - eps) { ret = 1; goto done; } } /* check if the original upper bound is infeasible */ if (U != +DBL_MAX) { double eps = 1e-3 * (1.0 + fabs(U)); if (LL > U + eps) { ret = 1; goto done; } } /* check if the original lower bound is redundant */ if (L != -DBL_MAX) { double eps = 1e-12 * (1.0 + fabs(L)); if (LL > L - eps) { /* it cannot be active, so remove it */ *L_ = -DBL_MAX; } } /* check if the original upper bound is redundant */ if (U != +DBL_MAX) { double eps = 1e-12 * (1.0 + fabs(U)); if (UU < U + eps) { /* it cannot be active, so remove it */ *U_ = +DBL_MAX; } } done: return ret; } /*********************************************************************** * check_col_bounds - check and tighten original column bounds * * Given a row (constraint) * * n * L <= sum a[j] * x[j] <= U * j=1 * * and bounds of columns (variables) * * l[j] <= x[j] <= u[j] * * for column (variable) x[j] this routine checks the original column * bounds l[j] and u[j] for feasibility and redundancy. If the original * lower bound l[j] or/and upper bound u[j] cannot be active due to * bounds of the constraint and other variables, the routine tighten * them replacing by corresponding implied bounds, if possible. * * NOTE: It is assumed that if L != -inf, the row lower bound can be * active, and if U != +inf, the row upper bound can be active. * * The flag means that variable x[j] is required to be integer. * * New actual bounds for x[j] are stored in locations lj and uj. * * If no primal infeasibility is detected, the routine returns zero, * otherwise non-zero. */ static int check_col_bounds(const struct f_info *f, int n, const double a[], double L, double U, const double l[], const double u[], int flag, int j, double *_lj, double *_uj) { int ret = 0; double lj, uj, ll, uu; xassert(n >= 0); xassert(1 <= j && j <= n); lj = l[j], uj = u[j]; /* determine implied bounds of the column */ col_implied_bounds(f, n, a, L, U, l, u, j, &ll, &uu); /* if x[j] is integral, round its implied bounds */ if (flag) { if (ll != -DBL_MAX) ll = (ll - floor(ll) < 1e-3 ? floor(ll) : ceil(ll)); if (uu != +DBL_MAX) uu = (ceil(uu) - uu < 1e-3 ? ceil(uu) : floor(uu)); } /* check if the original lower bound is infeasible */ if (lj != -DBL_MAX) { double eps = 1e-3 * (1.0 + fabs(lj)); if (uu < lj - eps) { ret = 1; goto done; } } /* check if the original upper bound is infeasible */ if (uj != +DBL_MAX) { double eps = 1e-3 * (1.0 + fabs(uj)); if (ll > uj + eps) { ret = 1; goto done; } } /* check if the original lower bound is redundant */ if (ll != -DBL_MAX) { double eps = 1e-3 * (1.0 + fabs(ll)); if (lj < ll - eps) { /* it cannot be active, so tighten it */ lj = ll; } } /* check if the original upper bound is redundant */ if (uu != +DBL_MAX) { double eps = 1e-3 * (1.0 + fabs(uu)); if (uj > uu + eps) { /* it cannot be active, so tighten it */ uj = uu; } } /* due to round-off errors it may happen that lj > uj (although lj < uj + eps, since no primal infeasibility is detected), so adjuct the new actual bounds to provide lj <= uj */ if (!(lj == -DBL_MAX || uj == +DBL_MAX)) { double t1 = fabs(lj), t2 = fabs(uj); double eps = 1e-10 * (1.0 + (t1 <= t2 ? t1 : t2)); if (lj > uj - eps) { if (lj == l[j]) uj = lj; else if (uj == u[j]) lj = uj; else if (t1 <= t2) uj = lj; else lj = uj; } } *_lj = lj, *_uj = uj; done: return ret; } /*********************************************************************** * check_efficiency - check if change in column bounds is efficient * * Given the original bounds of a column l and u and its new actual * bounds l' and u' (possibly tighten by the routine check_col_bounds) * this routine checks if the change in the column bounds is efficient * enough. If so, the routine returns non-zero, otherwise zero. * * The flag means that the variable is required to be integer. */ static int check_efficiency(int flag, double l, double u, double ll, double uu) { int eff = 0; /* check efficiency for lower bound */ if (l < ll) { if (flag || l == -DBL_MAX) eff++; else { double r; if (u == +DBL_MAX) r = 1.0 + fabs(l); else r = 1.0 + (u - l); if (ll - l >= 0.25 * r) eff++; } } /* check efficiency for upper bound */ if (u > uu) { if (flag || u == +DBL_MAX) eff++; else { double r; if (l == -DBL_MAX) r = 1.0 + fabs(u); else r = 1.0 + (u - l); if (u - uu >= 0.25 * r) eff++; } } return eff; } /*********************************************************************** * basic_preprocessing - perform basic preprocessing * * This routine performs basic preprocessing of the specified MIP that * includes relaxing some row bounds and tightening some column bounds. * * On entry the arrays L and U contains original row bounds, and the * arrays l and u contains original column bounds: * * L[0] is the lower bound of the objective row; * L[i], i = 1,...,m, is the lower bound of i-th row; * U[0] is the upper bound of the objective row; * U[i], i = 1,...,m, is the upper bound of i-th row; * l[0] is not used; * l[j], j = 1,...,n, is the lower bound of j-th column; * u[0] is not used; * u[j], j = 1,...,n, is the upper bound of j-th column. * * On exit the arrays L, U, l, and u contain new actual bounds of rows * and column in the same locations. * * The parameters nrs and num specify an initial list of rows to be * processed: * * nrs is the number of rows in the initial list, 0 <= nrs <= m+1; * num[0] is not used; * num[1,...,nrs] are row numbers (0 means the objective row). * * The parameter max_pass specifies the maximal number of times that * each row can be processed, max_pass > 0. * * If no primal infeasibility is detected, the routine returns zero, * otherwise non-zero. */ static int basic_preprocessing(glp_prob *mip, double L[], double U[], double l[], double u[], int nrs, const int num[], int max_pass) { int m = mip->m; int n = mip->n; struct f_info f; int i, j, k, len, size, ret = 0; int *ind, *list, *mark, *pass; double *val, *lb, *ub; xassert(0 <= nrs && nrs <= m+1); xassert(max_pass > 0); /* allocate working arrays */ ind = xcalloc(1+n, sizeof(int)); list = xcalloc(1+m+1, sizeof(int)); mark = xcalloc(1+m+1, sizeof(int)); memset(&mark[0], 0, (m+1) * sizeof(int)); pass = xcalloc(1+m+1, sizeof(int)); memset(&pass[0], 0, (m+1) * sizeof(int)); val = xcalloc(1+n, sizeof(double)); lb = xcalloc(1+n, sizeof(double)); ub = xcalloc(1+n, sizeof(double)); /* initialize the list of rows to be processed */ size = 0; for (k = 1; k <= nrs; k++) { i = num[k]; xassert(0 <= i && i <= m); /* duplicate row numbers are not allowed */ xassert(!mark[i]); list[++size] = i, mark[i] = 1; } xassert(size == nrs); /* process rows in the list until it becomes empty */ while (size > 0) { /* get a next row from the list */ i = list[size--], mark[i] = 0; /* increase the row processing count */ pass[i]++; /* if the row is free, skip it */ if (L[i] == -DBL_MAX && U[i] == +DBL_MAX) continue; /* obtain coefficients of the row */ len = 0; if (i == 0) { for (j = 1; j <= n; j++) { GLPCOL *col = mip->col[j]; if (col->coef != 0.0) len++, ind[len] = j, val[len] = col->coef; } } else { GLPROW *row = mip->row[i]; GLPAIJ *aij; for (aij = row->ptr; aij != NULL; aij = aij->r_next) len++, ind[len] = aij->col->j, val[len] = aij->val; } /* determine lower and upper bounds of columns corresponding to non-zero row coefficients */ for (k = 1; k <= len; k++) j = ind[k], lb[k] = l[j], ub[k] = u[j]; /* prepare the row info to determine implied bounds */ prepare_row_info(len, val, lb, ub, &f); /* check and relax bounds of the row */ if (check_row_bounds(&f, &L[i], &U[i])) { /* the feasible region is empty */ ret = 1; goto done; } /* if the row became free, drop it */ if (L[i] == -DBL_MAX && U[i] == +DBL_MAX) continue; /* process columns having non-zero coefficients in the row */ for (k = 1; k <= len; k++) { GLPCOL *col; int flag, eff; double ll, uu; /* take a next column in the row */ j = ind[k], col = mip->col[j]; flag = col->kind != GLP_CV; /* check and tighten bounds of the column */ if (check_col_bounds(&f, len, val, L[i], U[i], lb, ub, flag, k, &ll, &uu)) { /* the feasible region is empty */ ret = 1; goto done; } /* check if change in the column bounds is efficient */ eff = check_efficiency(flag, l[j], u[j], ll, uu); /* set new actual bounds of the column */ l[j] = ll, u[j] = uu; /* if the change is efficient, add all rows affected by the corresponding column, to the list */ if (eff > 0) { GLPAIJ *aij; for (aij = col->ptr; aij != NULL; aij = aij->c_next) { int ii = aij->row->i; /* if the row was processed maximal number of times, skip it */ if (pass[ii] >= max_pass) continue; /* if the row is free, skip it */ if (L[ii] == -DBL_MAX && U[ii] == +DBL_MAX) continue; /* put the row into the list */ if (mark[ii] == 0) { xassert(size <= m); list[++size] = ii, mark[ii] = 1; } } } } } done: /* free working arrays */ xfree(ind); xfree(list); xfree(mark); xfree(pass); xfree(val); xfree(lb); xfree(ub); return ret; } /*********************************************************************** * NAME * * ios_preprocess_node - preprocess current subproblem * * SYNOPSIS * * #include "glpios.h" * int ios_preprocess_node(glp_tree *tree, int max_pass); * * DESCRIPTION * * The routine ios_preprocess_node performs basic preprocessing of the * current subproblem. * * RETURNS * * If no primal infeasibility is detected, the routine returns zero, * otherwise non-zero. */ int ios_preprocess_node(glp_tree *tree, int max_pass) { glp_prob *mip = tree->mip; int m = mip->m; int n = mip->n; int i, j, nrs, *num, ret = 0; double *L, *U, *l, *u; /* the current subproblem must exist */ xassert(tree->curr != NULL); /* determine original row bounds */ L = xcalloc(1+m, sizeof(double)); U = xcalloc(1+m, sizeof(double)); switch (mip->mip_stat) { case GLP_UNDEF: L[0] = -DBL_MAX, U[0] = +DBL_MAX; break; case GLP_FEAS: switch (mip->dir) { case GLP_MIN: L[0] = -DBL_MAX, U[0] = mip->mip_obj - mip->c0; break; case GLP_MAX: L[0] = mip->mip_obj - mip->c0, U[0] = +DBL_MAX; break; default: xassert(mip != mip); } break; default: xassert(mip != mip); } for (i = 1; i <= m; i++) { L[i] = glp_get_row_lb(mip, i); U[i] = glp_get_row_ub(mip, i); } /* determine original column bounds */ l = xcalloc(1+n, sizeof(double)); u = xcalloc(1+n, sizeof(double)); for (j = 1; j <= n; j++) { l[j] = glp_get_col_lb(mip, j); u[j] = glp_get_col_ub(mip, j); } /* build the initial list of rows to be analyzed */ nrs = m + 1; num = xcalloc(1+nrs, sizeof(int)); for (i = 1; i <= nrs; i++) num[i] = i - 1; /* perform basic preprocessing */ if (basic_preprocessing(mip , L, U, l, u, nrs, num, max_pass)) { ret = 1; goto done; } /* set new actual (relaxed) row bounds */ for (i = 1; i <= m; i++) { /* consider only non-active rows to keep dual feasibility */ if (glp_get_row_stat(mip, i) == GLP_BS) { if (L[i] == -DBL_MAX && U[i] == +DBL_MAX) glp_set_row_bnds(mip, i, GLP_FR, 0.0, 0.0); else if (U[i] == +DBL_MAX) glp_set_row_bnds(mip, i, GLP_LO, L[i], 0.0); else if (L[i] == -DBL_MAX) glp_set_row_bnds(mip, i, GLP_UP, 0.0, U[i]); } } /* set new actual (tightened) column bounds */ for (j = 1; j <= n; j++) { int type; if (l[j] == -DBL_MAX && u[j] == +DBL_MAX) type = GLP_FR; else if (u[j] == +DBL_MAX) type = GLP_LO; else if (l[j] == -DBL_MAX) type = GLP_UP; else if (l[j] != u[j]) type = GLP_DB; else type = GLP_FX; glp_set_col_bnds(mip, j, type, l[j], u[j]); } done: /* free working arrays and return */ xfree(L); xfree(U); xfree(l); xfree(u); xfree(num); return ret; } /* eof */ Rglpk/src/GLPK/glpssx.h0000644000176000001440000004032312245352174014405 0ustar ripleyusers/* glpssx.h (simplex method, bignum arithmetic) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPSSX_H #define GLPSSX_H #include "glpbfx.h" #include "env.h" typedef struct SSX SSX; struct SSX { /* simplex solver workspace */ /*---------------------------------------------------------------------- // LP PROBLEM DATA // // It is assumed that LP problem has the following statement: // // minimize (or maximize) // // z = c[1]*x[1] + ... + c[m+n]*x[m+n] + c[0] (1) // // subject to equality constraints // // x[1] - a[1,1]*x[m+1] - ... - a[1,n]*x[m+n] = 0 // // . . . . . . . (2) // // x[m] - a[m,1]*x[m+1] + ... - a[m,n]*x[m+n] = 0 // // and bounds of variables // // l[1] <= x[1] <= u[1] // // . . . . . . . (3) // // l[m+n] <= x[m+n] <= u[m+n] // // where: // x[1], ..., x[m] - auxiliary variables; // x[m+1], ..., x[m+n] - structural variables; // z - objective function; // c[1], ..., c[m+n] - coefficients of the objective function; // c[0] - constant term of the objective function; // a[1,1], ..., a[m,n] - constraint coefficients; // l[1], ..., l[m+n] - lower bounds of variables; // u[1], ..., u[m+n] - upper bounds of variables. // // Bounds of variables can be finite as well as inifinite. Besides, // lower and upper bounds can be equal to each other. So the following // five types of variables are possible: // // Bounds of variable Type of variable // ------------------------------------------------- // -inf < x[k] < +inf Free (unbounded) variable // l[k] <= x[k] < +inf Variable with lower bound // -inf < x[k] <= u[k] Variable with upper bound // l[k] <= x[k] <= u[k] Double-bounded variable // l[k] = x[k] = u[k] Fixed variable // // Using vector-matrix notations the LP problem (1)-(3) can be written // as follows: // // minimize (or maximize) // // z = c * x + c[0] (4) // // subject to equality constraints // // xR - A * xS = 0 (5) // // and bounds of variables // // l <= x <= u (6) // // where: // xR - vector of auxiliary variables; // xS - vector of structural variables; // x = (xR, xS) - vector of all variables; // z - objective function; // c - vector of objective coefficients; // c[0] - constant term of the objective function; // A - matrix of constraint coefficients (has m rows // and n columns); // l - vector of lower bounds of variables; // u - vector of upper bounds of variables. // // The simplex method makes no difference between auxiliary and // structural variables, so it is convenient to think the system of // equality constraints (5) written in a homogeneous form: // // (I | -A) * x = 0, (7) // // where (I | -A) is an augmented (m+n)xm constraint matrix, I is mxm // unity matrix whose columns correspond to auxiliary variables, and A // is the original mxn constraint matrix whose columns correspond to // structural variables. Note that only the matrix A is stored. ----------------------------------------------------------------------*/ int m; /* number of rows (auxiliary variables), m > 0 */ int n; /* number of columns (structural variables), n > 0 */ int *type; /* int type[1+m+n]; */ /* type[0] is not used; type[k], 1 <= k <= m+n, is the type of variable x[k]: */ #define SSX_FR 0 /* free (unbounded) variable */ #define SSX_LO 1 /* variable with lower bound */ #define SSX_UP 2 /* variable with upper bound */ #define SSX_DB 3 /* double-bounded variable */ #define SSX_FX 4 /* fixed variable */ mpq_t *lb; /* mpq_t lb[1+m+n]; alias: l */ /* lb[0] is not used; lb[k], 1 <= k <= m+n, is an lower bound of variable x[k]; if x[k] has no lower bound, lb[k] is zero */ mpq_t *ub; /* mpq_t ub[1+m+n]; alias: u */ /* ub[0] is not used; ub[k], 1 <= k <= m+n, is an upper bound of variable x[k]; if x[k] has no upper bound, ub[k] is zero; if x[k] is of fixed type, ub[k] is equal to lb[k] */ int dir; /* optimization direction (sense of the objective function): */ #define SSX_MIN 0 /* minimization */ #define SSX_MAX 1 /* maximization */ mpq_t *coef; /* mpq_t coef[1+m+n]; alias: c */ /* coef[0] is a constant term of the objective function; coef[k], 1 <= k <= m+n, is a coefficient of the objective function at variable x[k]; note that auxiliary variables also may have non-zero objective coefficients */ int *A_ptr; /* int A_ptr[1+n+1]; */ int *A_ind; /* int A_ind[A_ptr[n+1]]; */ mpq_t *A_val; /* mpq_t A_val[A_ptr[n+1]]; */ /* constraint matrix A (see (5)) in storage-by-columns format */ /*---------------------------------------------------------------------- // LP BASIS AND CURRENT BASIC SOLUTION // // The LP basis is defined by the following partition of the augmented // constraint matrix (7): // // (B | N) = (I | -A) * Q, (8) // // where B is a mxm non-singular basis matrix whose columns correspond // to basic variables xB, N is a mxn matrix whose columns correspond to // non-basic variables xN, and Q is a permutation (m+n)x(m+n) matrix. // // From (7) and (8) it follows that // // (I | -A) * x = (I | -A) * Q * Q' * x = (B | N) * (xB, xN), // // therefore // // (xB, xN) = Q' * x, (9) // // where x is the vector of all variables in the original order, xB is // a vector of basic variables, xN is a vector of non-basic variables, // Q' = inv(Q) is a matrix transposed to Q. // // Current values of non-basic variables xN[j], j = 1, ..., n, are not // stored; they are defined implicitly by their statuses as follows: // // 0, if xN[j] is free variable // lN[j], if xN[j] is on its lower bound (10) // uN[j], if xN[j] is on its upper bound // lN[j] = uN[j], if xN[j] is fixed variable // // where lN[j] and uN[j] are lower and upper bounds of xN[j]. // // Current values of basic variables xB[i], i = 1, ..., m, are computed // as follows: // // beta = - inv(B) * N * xN, (11) // // where current values of xN are defined by (10). // // Current values of simplex multipliers pi[i], i = 1, ..., m (which // are values of Lagrange multipliers for equality constraints (7) also // called shadow prices) are computed as follows: // // pi = inv(B') * cB, (12) // // where B' is a matrix transposed to B, cB is a vector of objective // coefficients at basic variables xB. // // Current values of reduced costs d[j], j = 1, ..., n, (which are // values of Langrange multipliers for active inequality constraints // corresponding to non-basic variables) are computed as follows: // // d = cN - N' * pi, (13) // // where N' is a matrix transposed to N, cN is a vector of objective // coefficients at non-basic variables xN. ----------------------------------------------------------------------*/ int *stat; /* int stat[1+m+n]; */ /* stat[0] is not used; stat[k], 1 <= k <= m+n, is the status of variable x[k]: */ #define SSX_BS 0 /* basic variable */ #define SSX_NL 1 /* non-basic variable on lower bound */ #define SSX_NU 2 /* non-basic variable on upper bound */ #define SSX_NF 3 /* non-basic free variable */ #define SSX_NS 4 /* non-basic fixed variable */ int *Q_row; /* int Q_row[1+m+n]; */ /* matrix Q in row-like format; Q_row[0] is not used; Q_row[i] = j means that q[i,j] = 1 */ int *Q_col; /* int Q_col[1+m+n]; */ /* matrix Q in column-like format; Q_col[0] is not used; Q_col[j] = i means that q[i,j] = 1 */ /* if k-th column of the matrix (I | A) is k'-th column of the matrix (B | N), then Q_row[k] = k' and Q_col[k'] = k; if x[k] is xB[i], then Q_row[k] = i and Q_col[i] = k; if x[k] is xN[j], then Q_row[k] = m+j and Q_col[m+j] = k */ BFX *binv; /* invertable form of the basis matrix B */ mpq_t *bbar; /* mpq_t bbar[1+m]; alias: beta */ /* bbar[0] is a value of the objective function; bbar[i], 1 <= i <= m, is a value of basic variable xB[i] */ mpq_t *pi; /* mpq_t pi[1+m]; */ /* pi[0] is not used; pi[i], 1 <= i <= m, is a simplex multiplier corresponding to i-th row (equality constraint) */ mpq_t *cbar; /* mpq_t cbar[1+n]; alias: d */ /* cbar[0] is not used; cbar[j], 1 <= j <= n, is a reduced cost of non-basic variable xN[j] */ /*---------------------------------------------------------------------- // SIMPLEX TABLE // // Due to (8) and (9) the system of equality constraints (7) for the // current basis can be written as follows: // // xB = A~ * xN, (14) // // where // // A~ = - inv(B) * N (15) // // is a mxn matrix called the simplex table. // // The revised simplex method uses only two components of A~, namely, // pivot column corresponding to non-basic variable xN[q] chosen to // enter the basis, and pivot row corresponding to basic variable xB[p] // chosen to leave the basis. // // Pivot column alfa_q is q-th column of A~, so // // alfa_q = A~ * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q], (16) // // where N[q] is q-th column of the matrix N. // // Pivot row alfa_p is p-th row of A~ or, equivalently, p-th column of // A~', a matrix transposed to A~, so // // alfa_p = A~' * e[p] = - N' * inv(B') * e[p] = - N' * rho_p, (17) // // where (*)' means transposition, and // // rho_p = inv(B') * e[p], (18) // // is p-th column of inv(B') or, that is the same, p-th row of inv(B). ----------------------------------------------------------------------*/ int p; /* number of basic variable xB[p], 1 <= p <= m, chosen to leave the basis */ mpq_t *rho; /* mpq_t rho[1+m]; */ /* p-th row of the inverse inv(B); see (18) */ mpq_t *ap; /* mpq_t ap[1+n]; */ /* p-th row of the simplex table; see (17) */ int q; /* number of non-basic variable xN[q], 1 <= q <= n, chosen to enter the basis */ mpq_t *aq; /* mpq_t aq[1+m]; */ /* q-th column of the simplex table; see (16) */ /*--------------------------------------------------------------------*/ int q_dir; /* direction in which non-basic variable xN[q] should change on moving to the adjacent vertex of the polyhedron: +1 means that xN[q] increases -1 means that xN[q] decreases */ int p_stat; /* non-basic status which should be assigned to basic variable xB[p] when it has left the basis and become xN[q] */ mpq_t delta; /* actual change of xN[q] in the adjacent basis (it has the same sign as q_dir) */ /*--------------------------------------------------------------------*/ int it_lim; /* simplex iterations limit; if this value is positive, it is decreased by one each time when one simplex iteration has been performed, and reaching zero value signals the solver to stop the search; negative value means no iterations limit */ int it_cnt; /* simplex iterations count; this count is increased by one each time when one simplex iteration has been performed */ double tm_lim; /* searching time limit, in seconds; if this value is positive, it is decreased each time when one simplex iteration has been performed by the amount of time spent for the iteration, and reaching zero value signals the solver to stop the search; negative value means no time limit */ double out_frq; /* output frequency, in seconds; this parameter specifies how frequently the solver sends information about the progress of the search to the standard output */ #if 0 /* 10/VI-2013 */ glp_long tm_beg; #else double tm_beg; #endif /* starting time of the search, in seconds; the total time of the search is the difference between xtime() and tm_beg */ #if 0 /* 10/VI-2013 */ glp_long tm_lag; #else double tm_lag; #endif /* the most recent time, in seconds, at which the progress of the the search was displayed */ }; #define ssx_create _glp_ssx_create #define ssx_factorize _glp_ssx_factorize #define ssx_get_xNj _glp_ssx_get_xNj #define ssx_eval_bbar _glp_ssx_eval_bbar #define ssx_eval_pi _glp_ssx_eval_pi #define ssx_eval_dj _glp_ssx_eval_dj #define ssx_eval_cbar _glp_ssx_eval_cbar #define ssx_eval_rho _glp_ssx_eval_rho #define ssx_eval_row _glp_ssx_eval_row #define ssx_eval_col _glp_ssx_eval_col #define ssx_chuzc _glp_ssx_chuzc #define ssx_chuzr _glp_ssx_chuzr #define ssx_update_bbar _glp_ssx_update_bbar #define ssx_update_pi _glp_ssx_update_pi #define ssx_update_cbar _glp_ssx_update_cbar #define ssx_change_basis _glp_ssx_change_basis #define ssx_delete _glp_ssx_delete #define ssx_phase_I _glp_ssx_phase_I #define ssx_phase_II _glp_ssx_phase_II #define ssx_driver _glp_ssx_driver SSX *ssx_create(int m, int n, int nnz); /* create simplex solver workspace */ int ssx_factorize(SSX *ssx); /* factorize the current basis matrix */ void ssx_get_xNj(SSX *ssx, int j, mpq_t x); /* determine value of non-basic variable */ void ssx_eval_bbar(SSX *ssx); /* compute values of basic variables */ void ssx_eval_pi(SSX *ssx); /* compute values of simplex multipliers */ void ssx_eval_dj(SSX *ssx, int j, mpq_t dj); /* compute reduced cost of non-basic variable */ void ssx_eval_cbar(SSX *ssx); /* compute reduced costs of all non-basic variables */ void ssx_eval_rho(SSX *ssx); /* compute p-th row of the inverse */ void ssx_eval_row(SSX *ssx); /* compute pivot row of the simplex table */ void ssx_eval_col(SSX *ssx); /* compute pivot column of the simplex table */ void ssx_chuzc(SSX *ssx); /* choose pivot column */ void ssx_chuzr(SSX *ssx); /* choose pivot row */ void ssx_update_bbar(SSX *ssx); /* update values of basic variables */ void ssx_update_pi(SSX *ssx); /* update simplex multipliers */ void ssx_update_cbar(SSX *ssx); /* update reduced costs of non-basic variables */ void ssx_change_basis(SSX *ssx); /* change current basis to adjacent one */ void ssx_delete(SSX *ssx); /* delete simplex solver workspace */ int ssx_phase_I(SSX *ssx); /* find primal feasible solution */ int ssx_phase_II(SSX *ssx); /* find optimal solution */ int ssx_driver(SSX *ssx); /* base driver to exact simplex method */ #endif /* eof */ Rglpk/src/GLPK/cfg.h0000644000176000001440000001127612245352174013631 0ustar ripleyusers/* cfg.h (conflict graph) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef CFG_H #define CFG_H #include "dmp.h" /*********************************************************************** * The structure CFG describes the conflict graph. * * Conflict graph is an undirected graph G = (V, E), where V is a set * of vertices, E <= V x V is a set of edges. Each vertex v in V of the * conflict graph corresponds to a binary variable z[v], which is * either an original binary variable x[j] or its complement 1 - x[j]. * Edge (v,w) in E means that z[v] and z[w] cannot take the value 1 at * the same time, i.e. it defines an inequality z[v] + z[w] <= 1, which * is assumed to be valid for original MIP. * * Since the conflict graph may be dense, it is stored as an union of * its cliques rather than explicitly. */ typedef struct CFG CFG; typedef struct CFGVLE CFGVLE; typedef struct CFGCLE CFGCLE; struct CFG { /* conflict graph descriptor */ int n; /* number of *all* variables (columns) in corresponding MIP */ int *pos; /* int pos[1+n]; */ /* pos[0] is not used; * pos[j] = v, 1 <= j <= n, means that vertex v corresponds to * original binary variable x[j], and pos[j] = 0 means that the * conflict graph has no such vertex */ int *neg; /* int neg[1+n]; */ /* neg[0] is not used; * neg[j] = v, 1 <= j <= n, means that vertex v corresponds to * complement of original binary variable x[j], and neg[j] = 0 * means that the conflict graph has no such vertex */ DMP *pool; /* memory pool to allocate elements of the conflict graph */ int nv_max; /* maximal number of vertices in the conflict graph */ int nv; /* current number of vertices in the conflict graph */ int *ref; /* int ref[1+nv_max]; */ /* ref[v] = j, 1 <= v <= nv, means that vertex v corresponds * either to original binary variable x[j] or to its complement, * i.e. either pos[j] = v or neg[j] = v */ CFGVLE **vptr; /* CFGVLE *vptr[1+nv_max]; */ /* vptr[v], 1 <= v <= nv, is an initial pointer to the list of * vertices adjacent to vertex v */ CFGCLE **cptr; /* CFGCLE *cptr[1+nv_max]; */ /* cptr[v], 1 <= v <= nv, is an initial pointer to the list of * cliques that contain vertex v */ }; struct CFGVLE { /* vertex list element */ int v; /* vertex number, 1 <= v <= nv */ CFGVLE *next; /* pointer to next vertex list element */ }; struct CFGCLE { /* clique list element */ CFGVLE *vptr; /* initial pointer to the list of clique vertices */ CFGCLE *next; /* pointer to next clique list element */ }; #define cfg_create_graph _glp_cfg_create_graph CFG *cfg_create_graph(int n, int nv_max); /* create conflict graph */ #define cfg_add_clique _glp_cfg_add_clique void cfg_add_clique(CFG *G, int size, const int ind[]); /* add clique to conflict graph */ #define cfg_get_adjacent _glp_cfg_get_adjacent int cfg_get_adjacent(CFG *G, int v, int ind[]); /* get vertices adjacent to specified vertex */ #define cfg_expand_clique _glp_cfg_expand_clique int cfg_expand_clique(CFG *G, int c_len, int c_ind[]); /* expand specified clique to maximal clique */ #define cfg_check_clique _glp_cfg_check_clique void cfg_check_clique(CFG *G, int c_len, const int c_ind[]); /* check clique in conflict graph */ #define cfg_delete_graph _glp_cfg_delete_graph void cfg_delete_graph(CFG *G); /* delete conflict graph */ #define cfg_build_graph _glp_cfg_build_graph CFG *cfg_build_graph(void /* glp_prob */ *P); /* build conflict graph */ #define cfg_find_clique _glp_cfg_find_clique int cfg_find_clique(void /* glp_prob */ *P, CFG *G, int ind[], double *sum); /* find maximum weight clique in conflict graph */ #endif /* eof */ Rglpk/src/GLPK/glpios11.c0000644000176000001440000002473212245352174014525 0ustar ripleyusers/* glpios11.c (process cuts stored in the local cut pool) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpios.h" /*********************************************************************** * NAME * * ios_process_cuts - process cuts stored in the local cut pool * * SYNOPSIS * * #include "glpios.h" * void ios_process_cuts(glp_tree *T); * * DESCRIPTION * * The routine ios_process_cuts analyzes each cut currently stored in * the local cut pool, which must be non-empty, and either adds the cut * to the current subproblem or just discards it. All cuts are assumed * to be locally valid. On exit the local cut pool remains unchanged. * * REFERENCES * * 1. E.Balas, S.Ceria, G.Cornuejols, "Mixed 0-1 Programming by * Lift-and-Project in a Branch-and-Cut Framework", Management Sc., * 42 (1996) 1229-1246. * * 2. G.Andreello, A.Caprara, and M.Fischetti, "Embedding Cuts in * a Branch&Cut Framework: a Computational Study with {0,1/2}-Cuts", * Preliminary Draft, October 28, 2003, pp.6-8. */ struct info { /* estimated cut efficiency */ IOSCUT *cut; /* pointer to cut in the cut pool */ char flag; /* if this flag is set, the cut is included into the current subproblem */ double eff; /* cut efficacy (normalized residual) */ double deg; /* lower bound to objective degradation */ }; static int fcmp(const void *arg1, const void *arg2) { const struct info *info1 = arg1, *info2 = arg2; if (info1->deg == 0.0 && info2->deg == 0.0) { if (info1->eff > info2->eff) return -1; if (info1->eff < info2->eff) return +1; } else { if (info1->deg > info2->deg) return -1; if (info1->deg < info2->deg) return +1; } return 0; } static double parallel(IOSCUT *a, IOSCUT *b, double work[]); void ios_process_cuts(glp_tree *T) { IOSPOOL *pool; IOSCUT *cut; IOSAIJ *aij; struct info *info; int k, kk, max_cuts, len, ret, *ind; double *val, *work; /* the current subproblem must exist */ xassert(T->curr != NULL); /* the pool must exist and be non-empty */ pool = T->local; xassert(pool != NULL); xassert(pool->size > 0); /* allocate working arrays */ info = xcalloc(1+pool->size, sizeof(struct info)); ind = xcalloc(1+T->n, sizeof(int)); val = xcalloc(1+T->n, sizeof(double)); work = xcalloc(1+T->n, sizeof(double)); for (k = 1; k <= T->n; k++) work[k] = 0.0; /* build the list of cuts stored in the cut pool */ for (k = 0, cut = pool->head; cut != NULL; cut = cut->next) k++, info[k].cut = cut, info[k].flag = 0; xassert(k == pool->size); /* estimate efficiency of all cuts in the cut pool */ for (k = 1; k <= pool->size; k++) { double temp, dy, dz; cut = info[k].cut; /* build the vector of cut coefficients and compute its Euclidean norm */ len = 0; temp = 0.0; for (aij = cut->ptr; aij != NULL; aij = aij->next) { xassert(1 <= aij->j && aij->j <= T->n); len++, ind[len] = aij->j, val[len] = aij->val; temp += aij->val * aij->val; } if (temp < DBL_EPSILON * DBL_EPSILON) temp = DBL_EPSILON; /* transform the cut to express it only through non-basic (auxiliary and structural) variables */ len = glp_transform_row(T->mip, len, ind, val); /* determine change in the cut value and in the objective value for the adjacent basis by simulating one step of the dual simplex */ ret = _glp_analyze_row(T->mip, len, ind, val, cut->type, cut->rhs, 1e-9, NULL, NULL, NULL, NULL, &dy, &dz); /* determine normalized residual and lower bound to objective degradation */ if (ret == 0) { info[k].eff = fabs(dy) / sqrt(temp); /* if some reduced costs violates (slightly) their zero bounds (i.e. have wrong signs) due to round-off errors, dz also may have wrong sign being close to zero */ if (T->mip->dir == GLP_MIN) { if (dz < 0.0) dz = 0.0; info[k].deg = + dz; } else /* GLP_MAX */ { if (dz > 0.0) dz = 0.0; info[k].deg = - dz; } } else if (ret == 1) { /* the constraint is not violated at the current point */ info[k].eff = info[k].deg = 0.0; } else if (ret == 2) { /* no dual feasible adjacent basis exists */ info[k].eff = 1.0; info[k].deg = DBL_MAX; } else xassert(ret != ret); /* if the degradation is too small, just ignore it */ if (info[k].deg < 0.01) info[k].deg = 0.0; } /* sort the list of cuts by decreasing objective degradation and then by decreasing efficacy */ qsort(&info[1], pool->size, sizeof(struct info), fcmp); /* only first (most efficient) max_cuts in the list are qualified as candidates to be added to the current subproblem */ max_cuts = (T->curr->level == 0 ? 90 : 10); if (max_cuts > pool->size) max_cuts = pool->size; /* add cuts to the current subproblem */ #if 0 xprintf("*** adding cuts ***\n"); #endif for (k = 1; k <= max_cuts; k++) { int i, len; /* if this cut seems to be inefficient, skip it */ if (info[k].deg < 0.01 && info[k].eff < 0.01) continue; /* if the angle between this cut and every other cut included in the current subproblem is small, skip this cut */ for (kk = 1; kk < k; kk++) { if (info[kk].flag) { if (parallel(info[k].cut, info[kk].cut, work) > 0.90) break; } } if (kk < k) continue; /* add this cut to the current subproblem */ #if 0 xprintf("eff = %g; deg = %g\n", info[k].eff, info[k].deg); #endif cut = info[k].cut, info[k].flag = 1; i = glp_add_rows(T->mip, 1); if (cut->name != NULL) glp_set_row_name(T->mip, i, cut->name); xassert(T->mip->row[i]->origin == GLP_RF_CUT); T->mip->row[i]->klass = cut->klass; len = 0; for (aij = cut->ptr; aij != NULL; aij = aij->next) len++, ind[len] = aij->j, val[len] = aij->val; glp_set_mat_row(T->mip, i, len, ind, val); xassert(cut->type == GLP_LO || cut->type == GLP_UP); glp_set_row_bnds(T->mip, i, cut->type, cut->rhs, cut->rhs); } /* free working arrays */ xfree(info); xfree(ind); xfree(val); xfree(work); return; } #if 0 /*********************************************************************** * Given a cut a * x >= b (<= b) the routine efficacy computes the cut * efficacy as follows: * * eff = d * (a * x~ - b) / ||a||, * * where d is -1 (in case of '>= b') or +1 (in case of '<= b'), x~ is * the vector of values of structural variables in optimal solution to * LP relaxation of the current subproblem, ||a|| is the Euclidean norm * of the vector of cut coefficients. * * If the cut is violated at point x~, the efficacy eff is positive, * and its value is the Euclidean distance between x~ and the cut plane * a * x = b in the space of structural variables. * * Following geometrical intuition, it is quite natural to consider * this distance as a first-order measure of the expected efficacy of * the cut: the larger the distance the better the cut [1]. */ static double efficacy(glp_tree *T, IOSCUT *cut) { glp_prob *mip = T->mip; IOSAIJ *aij; double s = 0.0, t = 0.0, temp; for (aij = cut->ptr; aij != NULL; aij = aij->next) { xassert(1 <= aij->j && aij->j <= mip->n); s += aij->val * mip->col[aij->j]->prim; t += aij->val * aij->val; } temp = sqrt(t); if (temp < DBL_EPSILON) temp = DBL_EPSILON; if (cut->type == GLP_LO) temp = (s >= cut->rhs ? 0.0 : (cut->rhs - s) / temp); else if (cut->type == GLP_UP) temp = (s <= cut->rhs ? 0.0 : (s - cut->rhs) / temp); else xassert(cut != cut); return temp; } #endif /*********************************************************************** * Given two cuts a1 * x >= b1 (<= b1) and a2 * x >= b2 (<= b2) the * routine parallel computes the cosine of angle between the cut planes * a1 * x = b1 and a2 * x = b2 (which is the acute angle between two * normals to these planes) in the space of structural variables as * follows: * * cos phi = (a1' * a2) / (||a1|| * ||a2||), * * where (a1' * a2) is a dot product of vectors of cut coefficients, * ||a1|| and ||a2|| are Euclidean norms of vectors a1 and a2. * * Note that requirement cos phi = 0 forces the cuts to be orthogonal, * i.e. with disjoint support, while requirement cos phi <= 0.999 means * only avoiding duplicate (parallel) cuts [1]. */ static double parallel(IOSCUT *a, IOSCUT *b, double work[]) { IOSAIJ *aij; double s = 0.0, sa = 0.0, sb = 0.0, temp; for (aij = a->ptr; aij != NULL; aij = aij->next) { work[aij->j] = aij->val; sa += aij->val * aij->val; } for (aij = b->ptr; aij != NULL; aij = aij->next) { s += work[aij->j] * aij->val; sb += aij->val * aij->val; } for (aij = a->ptr; aij != NULL; aij = aij->next) work[aij->j] = 0.0; temp = sqrt(sa) * sqrt(sb); if (temp < DBL_EPSILON * DBL_EPSILON) temp = DBL_EPSILON; return s / temp; } /* eof */ Rglpk/src/GLPK/glpmps.c0000644000176000001440000013374112245352174014371 0ustar ripleyusers/* glpmps.c (MPS format routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #if 1 /* 11/VI-2013 */ #include "env2.h" #endif #include "glpapi.h" #include "glplib.h" /*********************************************************************** * NAME * * glp_init_mpscp - initialize MPS format control parameters * * SYNOPSIS * * void glp_init_mpscp(glp_mpscp *parm); * * DESCRIPTION * * The routine glp_init_mpscp initializes control parameters, which are * used by the MPS input/output routines glp_read_mps and glp_write_mps, * with default values. * * Default values of the control parameters are stored in the glp_mpscp * structure, which the parameter parm points to. */ void glp_init_mpscp(glp_mpscp *parm) { parm->blank = '\0'; parm->obj_name = NULL; parm->tol_mps = 1e-12; return; } static void check_parm(const char *func, const glp_mpscp *parm) { /* check control parameters */ if (!(0x00 <= parm->blank && parm->blank <= 0xFF) || !(parm->blank == '\0' || isprint(parm->blank))) xerror("%s: blank = 0x%02X; invalid parameter\n", func, parm->blank); if (!(parm->obj_name == NULL || strlen(parm->obj_name) <= 255)) xerror("%s: obj_name = \"%.12s...\"; parameter too long\n", func, parm->obj_name); if (!(0.0 <= parm->tol_mps && parm->tol_mps < 1.0)) xerror("%s: tol_mps = %g; invalid parameter\n", func, parm->tol_mps); return; } /*********************************************************************** * NAME * * glp_read_mps - read problem data in MPS format * * SYNOPSIS * * int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm, * const char *fname); * * DESCRIPTION * * The routine glp_read_mps reads problem data in MPS format from a * text file. * * The parameter fmt specifies the version of MPS format: * * GLP_MPS_DECK - fixed (ancient) MPS format; * GLP_MPS_FILE - free (modern) MPS format. * * The parameter parm is a pointer to the structure glp_mpscp, which * specifies control parameters used by the routine. If parm is NULL, * the routine uses default settings. * * The character string fname specifies a name of the text file to be * read. * * Note that before reading data the current content of the problem * object is completely erased with the routine glp_erase_prob. * * RETURNS * * If the operation was successful, the routine glp_read_mps returns * zero. Otherwise, it prints an error message and returns non-zero. */ struct csa { /* common storage area */ glp_prob *P; /* pointer to problem object */ int deck; /* MPS format (0 - free, 1 - fixed) */ const glp_mpscp *parm; /* pointer to control parameters */ const char *fname; /* name of input MPS file */ XFILE *fp; /* stream assigned to input MPS file */ jmp_buf jump; /* label for go to in case of error */ int recno; /* current record (card) number */ int recpos; /* current record (card) position */ int c; /* current character */ int fldno; /* current field number */ char field[255+1]; /* current field content */ int w80; /* warning 'record must not be longer than 80 chars' issued */ int wef; /* warning 'extra fields detected beyond field 6' issued */ int obj_row; /* objective row number */ void *work1, *work2, *work3; /* working arrays */ }; static void error(struct csa *csa, const char *fmt, ...) { /* print error message and terminate processing */ va_list arg; xprintf("%s:%d: ", csa->fname, csa->recno); va_start(arg, fmt); xvprintf(fmt, arg); va_end(arg); longjmp(csa->jump, 1); /* no return */ } static void warning(struct csa *csa, const char *fmt, ...) { /* print warning message and continue processing */ va_list arg; xprintf("%s:%d: warning: ", csa->fname, csa->recno); va_start(arg, fmt); xvprintf(fmt, arg); va_end(arg); return; } static void read_char(struct csa *csa) { /* read next character */ int c; if (csa->c == '\n') csa->recno++, csa->recpos = 0; csa->recpos++; read: c = xfgetc(csa->fp); if (c < 0) { if (xferror(csa->fp)) error(csa, "read error - %s\n", xerrmsg()); else if (csa->c == '\n') error(csa, "unexpected end of file\n"); else { warning(csa, "missing final end of line\n"); c = '\n'; } } else if (c == '\n') ; else if (csa->c == '\r') { c = '\r'; goto badc; } else if (csa->deck && c == '\r') { csa->c = '\r'; goto read; } else if (c == ' ') ; else if (isspace(c)) { if (csa->deck) badc: error(csa, "in fixed MPS format white-space character 0x%02" "X is not allowed\n", c); c = ' '; } else if (iscntrl(c)) error(csa, "invalid control character 0x%02X\n", c); if (csa->deck && csa->recpos == 81 && c != '\n' && csa->w80 < 1) { warning(csa, "in fixed MPS format record must not be longer th" "an 80 characters\n"); csa->w80++; } csa->c = c; return; } static int indicator(struct csa *csa, int name) { /* skip comment records and read possible indicator record */ int ret; /* reset current field number */ csa->fldno = 0; loop: /* read the very first character of the next record */ xassert(csa->c == '\n'); read_char(csa); if (csa->c == ' ' || csa->c == '\n') { /* data record */ ret = 0; } else if (csa->c == '*') { /* comment record */ while (csa->c != '\n') read_char(csa); goto loop; } else { /* indicator record */ int len = 0; while (csa->c != ' ' && csa->c != '\n' && len < 12) { csa->field[len++] = (char)csa->c; read_char(csa); } csa->field[len] = '\0'; if (!(strcmp(csa->field, "NAME") == 0 || strcmp(csa->field, "ROWS") == 0 || strcmp(csa->field, "COLUMNS") == 0 || strcmp(csa->field, "RHS") == 0 || strcmp(csa->field, "RANGES") == 0 || strcmp(csa->field, "BOUNDS") == 0 || strcmp(csa->field, "ENDATA") == 0)) error(csa, "invalid indicator record\n"); if (!name) { while (csa->c != '\n') read_char(csa); } ret = 1; } return ret; } static void read_field(struct csa *csa) { /* read next field of the current data record */ csa->fldno++; if (csa->deck) { /* fixed MPS format */ int beg, end, pos; /* determine predefined field positions */ if (csa->fldno == 1) beg = 2, end = 3; else if (csa->fldno == 2) beg = 5, end = 12; else if (csa->fldno == 3) beg = 15, end = 22; else if (csa->fldno == 4) beg = 25, end = 36; else if (csa->fldno == 5) beg = 40, end = 47; else if (csa->fldno == 6) beg = 50, end = 61; else xassert(csa != csa); /* skip blanks preceding the current field */ if (csa->c != '\n') { pos = csa->recpos; while (csa->recpos < beg) { if (csa->c == ' ') ; else if (csa->c == '\n') break; else error(csa, "in fixed MPS format positions %d-%d must " "be blank\n", pos, beg-1); read_char(csa); } } /* skip possible comment beginning in the field 3 or 5 */ if ((csa->fldno == 3 || csa->fldno == 5) && csa->c == '$') { while (csa->c != '\n') read_char(csa); } /* read the current field */ for (pos = beg; pos <= end; pos++) { if (csa->c == '\n') break; csa->field[pos-beg] = (char)csa->c; read_char(csa); } csa->field[pos-beg] = '\0'; strtrim(csa->field); /* skip blanks following the last field */ if (csa->fldno == 6 && csa->c != '\n') { while (csa->recpos <= 72) { if (csa->c == ' ') ; else if (csa->c == '\n') break; else error(csa, "in fixed MPS format positions 62-72 must " "be blank\n"); read_char(csa); } while (csa->c != '\n') read_char(csa); } } else { /* free MPS format */ int len; /* skip blanks preceding the current field */ while (csa->c == ' ') read_char(csa); /* skip possible comment */ if (csa->c == '$') { while (csa->c != '\n') read_char(csa); } /* read the current field */ len = 0; while (!(csa->c == ' ' || csa->c == '\n')) { if (len == 255) error(csa, "length of field %d exceeds 255 characters\n", csa->fldno++); csa->field[len++] = (char)csa->c; read_char(csa); } csa->field[len] = '\0'; /* skip anything following the last field (any extra fields are considered to be comments) */ if (csa->fldno == 6) { while (csa->c == ' ') read_char(csa); if (csa->c != '$' && csa->c != '\n' && csa->wef < 1) { warning(csa, "some extra field(s) detected beyond field " "6; field(s) ignored\n"); csa->wef++; } while (csa->c != '\n') read_char(csa); } } return; } static void patch_name(struct csa *csa, char *name) { /* process embedded blanks in symbolic name */ int blank = csa->parm->blank; if (blank == '\0') { /* remove emedded blanks */ strspx(name); } else { /* replace embedded blanks by specified character */ for (; *name != '\0'; name++) if (*name == ' ') *name = (char)blank; } return; } static double read_number(struct csa *csa) { /* read next field and convert it to floating-point number */ double x; char *s; /* read next field */ read_field(csa); xassert(csa->fldno == 4 || csa->fldno == 6); if (csa->field[0] == '\0') error(csa, "missing numeric value in field %d\n", csa->fldno); /* skip initial spaces of the field */ for (s = csa->field; *s == ' '; s++); /* perform conversion */ if (str2num(s, &x) != 0) error(csa, "cannot convert `%s' to floating-point number\n", s); return x; } static void skip_field(struct csa *csa) { /* read and skip next field (assumed to be blank) */ read_field(csa); if (csa->field[0] != '\0') error(csa, "field %d must be blank\n", csa->fldno); return; } static void read_name(struct csa *csa) { /* read NAME indicator record */ if (!(indicator(csa, 1) && strcmp(csa->field, "NAME") == 0)) error(csa, "missing NAME indicator record\n"); /* this indicator record looks like a data record; simulate that fields 1 and 2 were read */ csa->fldno = 2; /* field 3: model name */ read_field(csa), patch_name(csa, csa->field); if (csa->field[0] == '\0') warning(csa, "missing model name in field 3\n"); else glp_set_prob_name(csa->P, csa->field); /* skip anything following field 3 */ while (csa->c != '\n') read_char(csa); return; } static void read_rows(struct csa *csa) { /* read ROWS section */ int i, type; loop: if (indicator(csa, 0)) goto done; /* field 1: row type */ read_field(csa), strspx(csa->field); if (strcmp(csa->field, "N") == 0) type = GLP_FR; else if (strcmp(csa->field, "G") == 0) type = GLP_LO; else if (strcmp(csa->field, "L") == 0) type = GLP_UP; else if (strcmp(csa->field, "E") == 0) type = GLP_FX; else if (csa->field[0] == '\0') error(csa, "missing row type in field 1\n"); else error(csa, "invalid row type in field 1\n"); /* field 2: row name */ read_field(csa), patch_name(csa, csa->field); if (csa->field[0] == '\0') error(csa, "missing row name in field 2\n"); if (glp_find_row(csa->P, csa->field) != 0) error(csa, "row `%s' multiply specified\n", csa->field); i = glp_add_rows(csa->P, 1); glp_set_row_name(csa->P, i, csa->field); glp_set_row_bnds(csa->P, i, type, 0.0, 0.0); /* fields 3, 4, 5, and 6 must be blank */ skip_field(csa); skip_field(csa); skip_field(csa); skip_field(csa); goto loop; done: return; } static void read_columns(struct csa *csa) { /* read COLUMNS section */ int i, j, f, len, kind = GLP_CV, *ind; double aij, *val; char name[255+1], *flag; /* allocate working arrays */ csa->work1 = ind = xcalloc(1+csa->P->m, sizeof(int)); csa->work2 = val = xcalloc(1+csa->P->m, sizeof(double)); csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char)); memset(&flag[1], 0, csa->P->m); /* no current column exists */ j = 0, len = 0; loop: if (indicator(csa, 0)) goto done; /* field 1 must be blank */ if (csa->deck) { read_field(csa); if (csa->field[0] != '\0') error(csa, "field 1 must be blank\n"); } else csa->fldno++; /* field 2: column or kind name */ read_field(csa), patch_name(csa, csa->field); strcpy(name, csa->field); /* field 3: row name or keyword 'MARKER' */ read_field(csa), patch_name(csa, csa->field); if (strcmp(csa->field, "'MARKER'") == 0) { /* process kind data record */ /* field 4 must be blank */ if (csa->deck) { read_field(csa); if (csa->field[0] != '\0') error(csa, "field 4 must be blank\n"); } else csa->fldno++; /* field 5: keyword 'INTORG' or 'INTEND' */ read_field(csa), patch_name(csa, csa->field); if (strcmp(csa->field, "'INTORG'") == 0) kind = GLP_IV; else if (strcmp(csa->field, "'INTEND'") == 0) kind = GLP_CV; else if (csa->field[0] == '\0') error(csa, "missing keyword in field 5\n"); else error(csa, "invalid keyword in field 5\n"); /* field 6 must be blank */ skip_field(csa); goto loop; } /* process column name specified in field 2 */ if (name[0] == '\0') { /* the same column as in previous data record */ if (j == 0) error(csa, "missing column name in field 2\n"); } else if (j != 0 && strcmp(name, csa->P->col[j]->name) == 0) { /* the same column as in previous data record */ xassert(j != 0); } else { /* store the current column */ if (j != 0) { glp_set_mat_col(csa->P, j, len, ind, val); while (len > 0) flag[ind[len--]] = 0; } /* create new column */ if (glp_find_col(csa->P, name) != 0) error(csa, "column `%s' multiply specified\n", name); j = glp_add_cols(csa->P, 1); glp_set_col_name(csa->P, j, name); glp_set_col_kind(csa->P, j, kind); if (kind == GLP_CV) glp_set_col_bnds(csa->P, j, GLP_LO, 0.0, 0.0); else if (kind == GLP_IV) glp_set_col_bnds(csa->P, j, GLP_DB, 0.0, 1.0); else xassert(kind != kind); } /* process fields 3-4 and 5-6 */ for (f = 3; f <= 5; f += 2) { /* field 3 or 5: row name */ if (f == 3) { if (csa->field[0] == '\0') error(csa, "missing row name in field 3\n"); } else { read_field(csa), patch_name(csa, csa->field); if (csa->field[0] == '\0') { /* if field 5 is blank, field 6 also must be blank */ skip_field(csa); continue; } } i = glp_find_row(csa->P, csa->field); if (i == 0) error(csa, "row `%s' not found\n", csa->field); if (flag[i]) error(csa, "duplicate coefficient in row `%s'\n", csa->field); /* field 4 or 6: coefficient value */ aij = read_number(csa); if (fabs(aij) < csa->parm->tol_mps) aij = 0.0; len++, ind[len] = i, val[len] = aij, flag[i] = 1; } goto loop; done: /* store the last column */ if (j != 0) glp_set_mat_col(csa->P, j, len, ind, val); /* free working arrays */ xfree(ind); xfree(val); xfree(flag); csa->work1 = csa->work2 = csa->work3 = NULL; return; } static void read_rhs(struct csa *csa) { /* read RHS section */ int i, f, v, type; double rhs; char name[255+1], *flag; /* allocate working array */ csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char)); memset(&flag[1], 0, csa->P->m); /* no current RHS vector exists */ v = 0; loop: if (indicator(csa, 0)) goto done; /* field 1 must be blank */ if (csa->deck) { read_field(csa); if (csa->field[0] != '\0') error(csa, "field 1 must be blank\n"); } else csa->fldno++; /* field 2: RHS vector name */ read_field(csa), patch_name(csa, csa->field); if (csa->field[0] == '\0') { /* the same RHS vector as in previous data record */ if (v == 0) { warning(csa, "missing RHS vector name in field 2\n"); goto blnk; } } else if (v != 0 && strcmp(csa->field, name) == 0) { /* the same RHS vector as in previous data record */ xassert(v != 0); } else blnk: { /* new RHS vector */ if (v != 0) error(csa, "multiple RHS vectors not supported\n"); v++; strcpy(name, csa->field); } /* process fields 3-4 and 5-6 */ for (f = 3; f <= 5; f += 2) { /* field 3 or 5: row name */ read_field(csa), patch_name(csa, csa->field); if (csa->field[0] == '\0') { if (f == 3) error(csa, "missing row name in field 3\n"); else { /* if field 5 is blank, field 6 also must be blank */ skip_field(csa); continue; } } i = glp_find_row(csa->P, csa->field); if (i == 0) error(csa, "row `%s' not found\n", csa->field); if (flag[i]) error(csa, "duplicate right-hand side for row `%s'\n", csa->field); /* field 4 or 6: right-hand side value */ rhs = read_number(csa); if (fabs(rhs) < csa->parm->tol_mps) rhs = 0.0; type = csa->P->row[i]->type; if (type == GLP_FR) { if (i == csa->obj_row) glp_set_obj_coef(csa->P, 0, rhs); else if (rhs != 0.0) warning(csa, "non-zero right-hand side for free row `%s'" " ignored\n", csa->P->row[i]->name); } else glp_set_row_bnds(csa->P, i, type, rhs, rhs); flag[i] = 1; } goto loop; done: /* free working array */ xfree(flag); csa->work3 = NULL; return; } static void read_ranges(struct csa *csa) { /* read RANGES section */ int i, f, v, type; double rhs, rng; char name[255+1], *flag; /* allocate working array */ csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char)); memset(&flag[1], 0, csa->P->m); /* no current RANGES vector exists */ v = 0; loop: if (indicator(csa, 0)) goto done; /* field 1 must be blank */ if (csa->deck) { read_field(csa); if (csa->field[0] != '\0') error(csa, "field 1 must be blank\n"); } else csa->fldno++; /* field 2: RANGES vector name */ read_field(csa), patch_name(csa, csa->field); if (csa->field[0] == '\0') { /* the same RANGES vector as in previous data record */ if (v == 0) { warning(csa, "missing RANGES vector name in field 2\n"); goto blnk; } } else if (v != 0 && strcmp(csa->field, name) == 0) { /* the same RANGES vector as in previous data record */ xassert(v != 0); } else blnk: { /* new RANGES vector */ if (v != 0) error(csa, "multiple RANGES vectors not supported\n"); v++; strcpy(name, csa->field); } /* process fields 3-4 and 5-6 */ for (f = 3; f <= 5; f += 2) { /* field 3 or 5: row name */ read_field(csa), patch_name(csa, csa->field); if (csa->field[0] == '\0') { if (f == 3) error(csa, "missing row name in field 3\n"); else { /* if field 5 is blank, field 6 also must be blank */ skip_field(csa); continue; } } i = glp_find_row(csa->P, csa->field); if (i == 0) error(csa, "row `%s' not found\n", csa->field); if (flag[i]) error(csa, "duplicate range for row `%s'\n", csa->field); /* field 4 or 6: range value */ rng = read_number(csa); if (fabs(rng) < csa->parm->tol_mps) rng = 0.0; type = csa->P->row[i]->type; if (type == GLP_FR) warning(csa, "range for free row `%s' ignored\n", csa->P->row[i]->name); else if (type == GLP_LO) { rhs = csa->P->row[i]->lb; glp_set_row_bnds(csa->P, i, rhs == 0.0 ? GLP_FX : GLP_DB, rhs, rhs + fabs(rng)); } else if (type == GLP_UP) { rhs = csa->P->row[i]->ub; glp_set_row_bnds(csa->P, i, rhs == 0.0 ? GLP_FX : GLP_DB, rhs - fabs(rng), rhs); } else if (type == GLP_FX) { rhs = csa->P->row[i]->lb; if (rng > 0.0) glp_set_row_bnds(csa->P, i, GLP_DB, rhs, rhs + rng); else if (rng < 0.0) glp_set_row_bnds(csa->P, i, GLP_DB, rhs + rng, rhs); } else xassert(type != type); flag[i] = 1; } goto loop; done: /* free working array */ xfree(flag); csa->work3 = NULL; return; } static void read_bounds(struct csa *csa) { /* read BOUNDS section */ GLPCOL *col; int j, v, mask, data; double bnd, lb, ub; char type[2+1], name[255+1], *flag; /* allocate working array */ csa->work3 = flag = xcalloc(1+csa->P->n, sizeof(char)); memset(&flag[1], 0, csa->P->n); /* no current BOUNDS vector exists */ v = 0; loop: if (indicator(csa, 0)) goto done; /* field 1: bound type */ read_field(csa); if (strcmp(csa->field, "LO") == 0) mask = 0x01, data = 1; else if (strcmp(csa->field, "UP") == 0) mask = 0x10, data = 1; else if (strcmp(csa->field, "FX") == 0) mask = 0x11, data = 1; else if (strcmp(csa->field, "FR") == 0) mask = 0x11, data = 0; else if (strcmp(csa->field, "MI") == 0) mask = 0x01, data = 0; else if (strcmp(csa->field, "PL") == 0) mask = 0x10, data = 0; else if (strcmp(csa->field, "LI") == 0) mask = 0x01, data = 1; else if (strcmp(csa->field, "UI") == 0) mask = 0x10, data = 1; else if (strcmp(csa->field, "BV") == 0) mask = 0x11, data = 0; else if (csa->field[0] == '\0') error(csa, "missing bound type in field 1\n"); else error(csa, "invalid bound type in field 1\n"); strcpy(type, csa->field); /* field 2: BOUNDS vector name */ read_field(csa), patch_name(csa, csa->field); if (csa->field[0] == '\0') { /* the same BOUNDS vector as in previous data record */ if (v == 0) { warning(csa, "missing BOUNDS vector name in field 2\n"); goto blnk; } } else if (v != 0 && strcmp(csa->field, name) == 0) { /* the same BOUNDS vector as in previous data record */ xassert(v != 0); } else blnk: { /* new BOUNDS vector */ if (v != 0) error(csa, "multiple BOUNDS vectors not supported\n"); v++; strcpy(name, csa->field); } /* field 3: column name */ read_field(csa), patch_name(csa, csa->field); if (csa->field[0] == '\0') error(csa, "missing column name in field 3\n"); j = glp_find_col(csa->P, csa->field); if (j == 0) error(csa, "column `%s' not found\n", csa->field); if ((flag[j] & mask) == 0x01) error(csa, "duplicate lower bound for column `%s'\n", csa->field); if ((flag[j] & mask) == 0x10) error(csa, "duplicate upper bound for column `%s'\n", csa->field); xassert((flag[j] & mask) == 0x00); /* field 4: bound value */ if (data) { bnd = read_number(csa); if (fabs(bnd) < csa->parm->tol_mps) bnd = 0.0; } else read_field(csa), bnd = 0.0; /* get current column bounds */ col = csa->P->col[j]; if (col->type == GLP_FR) lb = -DBL_MAX, ub = +DBL_MAX; else if (col->type == GLP_LO) lb = col->lb, ub = +DBL_MAX; else if (col->type == GLP_UP) lb = -DBL_MAX, ub = col->ub; else if (col->type == GLP_DB) lb = col->lb, ub = col->ub; else if (col->type == GLP_FX) lb = ub = col->lb; else xassert(col != col); /* change column bounds */ if (strcmp(type, "LO") == 0) lb = bnd; else if (strcmp(type, "UP") == 0) ub = bnd; else if (strcmp(type, "FX") == 0) lb = ub = bnd; else if (strcmp(type, "FR") == 0) lb = -DBL_MAX, ub = +DBL_MAX; else if (strcmp(type, "MI") == 0) lb = -DBL_MAX; else if (strcmp(type, "PL") == 0) ub = +DBL_MAX; else if (strcmp(type, "LI") == 0) { glp_set_col_kind(csa->P, j, GLP_IV); lb = ceil(bnd); #if 1 /* 16/VII-2013 */ /* if column upper bound has not been explicitly specified, take it as +inf */ if (!(flag[j] & 0x10)) ub = +DBL_MAX; #endif } else if (strcmp(type, "UI") == 0) { glp_set_col_kind(csa->P, j, GLP_IV); ub = floor(bnd); } else if (strcmp(type, "BV") == 0) { glp_set_col_kind(csa->P, j, GLP_IV); lb = 0.0, ub = 1.0; } else xassert(type != type); /* set new column bounds */ if (lb == -DBL_MAX && ub == +DBL_MAX) glp_set_col_bnds(csa->P, j, GLP_FR, lb, ub); else if (ub == +DBL_MAX) glp_set_col_bnds(csa->P, j, GLP_LO, lb, ub); else if (lb == -DBL_MAX) glp_set_col_bnds(csa->P, j, GLP_UP, lb, ub); else if (lb != ub) glp_set_col_bnds(csa->P, j, GLP_DB, lb, ub); else glp_set_col_bnds(csa->P, j, GLP_FX, lb, ub); flag[j] |= (char)mask; /* fields 5 and 6 must be blank */ skip_field(csa); skip_field(csa); goto loop; done: /* free working array */ xfree(flag); csa->work3 = NULL; return; } int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm, const char *fname) { /* read problem data in MPS format */ glp_mpscp _parm; struct csa _csa, *csa = &_csa; int ret; xprintf("Reading problem data from `%s'...\n", fname); if (!(fmt == GLP_MPS_DECK || fmt == GLP_MPS_FILE)) xerror("glp_read_mps: fmt = %d; invalid parameter\n", fmt); if (parm == NULL) glp_init_mpscp(&_parm), parm = &_parm; /* check control parameters */ check_parm("glp_read_mps", parm); /* initialize common storage area */ csa->P = P; csa->deck = (fmt == GLP_MPS_DECK); csa->parm = parm; csa->fname = fname; csa->fp = NULL; if (setjmp(csa->jump)) { ret = 1; goto done; } csa->recno = csa->recpos = 0; csa->c = '\n'; csa->fldno = 0; csa->field[0] = '\0'; csa->w80 = csa->wef = 0; csa->obj_row = 0; csa->work1 = csa->work2 = csa->work3 = NULL; /* erase problem object */ glp_erase_prob(P); glp_create_index(P); /* open input MPS file */ csa->fp = xfopen(fname, "r"); if (csa->fp == NULL) { xprintf("Unable to open `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } /* read NAME indicator record */ read_name(csa); if (P->name != NULL) xprintf("Problem: %s\n", P->name); /* read ROWS section */ if (!(indicator(csa, 0) && strcmp(csa->field, "ROWS") == 0)) error(csa, "missing ROWS indicator record\n"); read_rows(csa); /* determine objective row */ if (parm->obj_name == NULL || parm->obj_name[0] == '\0') { /* use the first row of N type */ int i; for (i = 1; i <= P->m; i++) { if (P->row[i]->type == GLP_FR) { csa->obj_row = i; break; } } if (csa->obj_row == 0) warning(csa, "unable to determine objective row\n"); } else { /* use a row with specified name */ int i; for (i = 1; i <= P->m; i++) { xassert(P->row[i]->name != NULL); if (strcmp(parm->obj_name, P->row[i]->name) == 0) { csa->obj_row = i; break; } } if (csa->obj_row == 0) error(csa, "objective row `%s' not found\n", parm->obj_name); } if (csa->obj_row != 0) { glp_set_obj_name(P, P->row[csa->obj_row]->name); xprintf("Objective: %s\n", P->obj); } /* read COLUMNS section */ if (strcmp(csa->field, "COLUMNS") != 0) error(csa, "missing COLUMNS indicator record\n"); read_columns(csa); /* set objective coefficients */ if (csa->obj_row != 0) { GLPAIJ *aij; for (aij = P->row[csa->obj_row]->ptr; aij != NULL; aij = aij->r_next) glp_set_obj_coef(P, aij->col->j, aij->val); } /* read optional RHS section */ if (strcmp(csa->field, "RHS") == 0) read_rhs(csa); /* read optional RANGES section */ if (strcmp(csa->field, "RANGES") == 0) read_ranges(csa); /* read optional BOUNDS section */ if (strcmp(csa->field, "BOUNDS") == 0) read_bounds(csa); /* read ENDATA indicator record */ if (strcmp(csa->field, "ENDATA") != 0) error(csa, "invalid use of %s indicator record\n", csa->field); /* print some statistics */ xprintf("%d row%s, %d column%s, %d non-zero%s\n", P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s", P->nnz, P->nnz == 1 ? "" : "s"); if (glp_get_num_int(P) > 0) { int ni = glp_get_num_int(P); int nb = glp_get_num_bin(P); if (ni == 1) { if (nb == 0) xprintf("One variable is integer\n"); else xprintf("One variable is binary\n"); } else { xprintf("%d integer variables, ", ni); if (nb == 0) xprintf("none"); else if (nb == 1) xprintf("one"); else if (nb == ni) xprintf("all"); else xprintf("%d", nb); xprintf(" of which %s binary\n", nb == 1 ? "is" : "are"); } } xprintf("%d records were read\n", csa->recno); /* problem data has been successfully read */ glp_delete_index(P); glp_sort_matrix(P); ret = 0; done: if (csa->fp != NULL) xfclose(csa->fp); if (csa->work1 != NULL) xfree(csa->work1); if (csa->work2 != NULL) xfree(csa->work2); if (csa->work3 != NULL) xfree(csa->work3); if (ret != 0) glp_erase_prob(P); return ret; } /*********************************************************************** * NAME * * glp_write_mps - write problem data in MPS format * * SYNOPSIS * * int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm, * const char *fname); * * DESCRIPTION * * The routine glp_write_mps writes problem data in MPS format to a * text file. * * The parameter fmt specifies the version of MPS format: * * GLP_MPS_DECK - fixed (ancient) MPS format; * GLP_MPS_FILE - free (modern) MPS format. * * The parameter parm is a pointer to the structure glp_mpscp, which * specifies control parameters used by the routine. If parm is NULL, * the routine uses default settings. * * The character string fname specifies a name of the text file to be * written. * * RETURNS * * If the operation was successful, the routine glp_read_mps returns * zero. Otherwise, it prints an error message and returns non-zero. */ #define csa csa1 struct csa { /* common storage area */ glp_prob *P; /* pointer to problem object */ int deck; /* MPS format (0 - free, 1 - fixed) */ const glp_mpscp *parm; /* pointer to control parameters */ char field[255+1]; /* field buffer */ }; static char *mps_name(struct csa *csa) { /* make problem name */ char *f; if (csa->P->name == NULL) csa->field[0] = '\0'; else if (csa->deck) { strncpy(csa->field, csa->P->name, 8); csa->field[8] = '\0'; } else strcpy(csa->field, csa->P->name); for (f = csa->field; *f != '\0'; f++) if (*f == ' ') *f = '_'; return csa->field; } static char *row_name(struct csa *csa, int i) { /* make i-th row name */ char *f; xassert(0 <= i && i <= csa->P->m); if (i == 0 || csa->P->row[i]->name == NULL || csa->deck && strlen(csa->P->row[i]->name) > 8) sprintf(csa->field, "R%07d", i); else { strcpy(csa->field, csa->P->row[i]->name); for (f = csa->field; *f != '\0'; f++) if (*f == ' ') *f = '_'; } return csa->field; } static char *col_name(struct csa *csa, int j) { /* make j-th column name */ char *f; xassert(1 <= j && j <= csa->P->n); if (csa->P->col[j]->name == NULL || csa->deck && strlen(csa->P->col[j]->name) > 8) sprintf(csa->field, "C%07d", j); else { strcpy(csa->field, csa->P->col[j]->name); for (f = csa->field; *f != '\0'; f++) if (*f == ' ') *f = '_'; } return csa->field; } static char *mps_numb(struct csa *csa, double val) { /* format floating-point number */ int dig; char *exp; for (dig = 12; dig >= 6; dig--) { if (val != 0.0 && fabs(val) < 0.002) sprintf(csa->field, "%.*E", dig-1, val); else sprintf(csa->field, "%.*G", dig, val); exp = strchr(csa->field, 'E'); if (exp != NULL) sprintf(exp+1, "%d", atoi(exp+1)); if (strlen(csa->field) <= 12) break; } xassert(strlen(csa->field) <= 12); return csa->field; } int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm, const char *fname) { /* write problem data in MPS format */ glp_mpscp _parm; struct csa _csa, *csa = &_csa; XFILE *fp; int out_obj, one_col = 0, empty = 0; int i, j, recno, marker, count, gap, ret; xprintf("Writing problem data to `%s'...\n", fname); if (!(fmt == GLP_MPS_DECK || fmt == GLP_MPS_FILE)) xerror("glp_write_mps: fmt = %d; invalid parameter\n", fmt); if (parm == NULL) glp_init_mpscp(&_parm), parm = &_parm; /* check control parameters */ check_parm("glp_write_mps", parm); /* initialize common storage area */ csa->P = P; csa->deck = (fmt == GLP_MPS_DECK); csa->parm = parm; /* create output MPS file */ fp = xfopen(fname, "w"), recno = 0; if (fp == NULL) { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } /* write comment records */ xfprintf(fp, "* %-*s%s\n", P->name == NULL ? 1 : 12, "Problem:", P->name == NULL ? "" : P->name), recno++; xfprintf(fp, "* %-12s%s\n", "Class:", glp_get_num_int(P) == 0 ? "LP" : "MIP"), recno++; xfprintf(fp, "* %-12s%d\n", "Rows:", P->m), recno++; if (glp_get_num_int(P) == 0) xfprintf(fp, "* %-12s%d\n", "Columns:", P->n), recno++; else xfprintf(fp, "* %-12s%d (%d integer, %d binary)\n", "Columns:", P->n, glp_get_num_int(P), glp_get_num_bin(P)), recno++; xfprintf(fp, "* %-12s%d\n", "Non-zeros:", P->nnz), recno++; xfprintf(fp, "* %-12s%s\n", "Format:", csa->deck ? "Fixed MPS" : "Free MPS"), recno++; xfprintf(fp, "*\n", recno++); /* write NAME indicator record */ xfprintf(fp, "NAME%*s%s\n", P->name == NULL ? 0 : csa->deck ? 10 : 1, "", mps_name(csa)), recno++; #if 1 /* determine whether to write the objective row */ out_obj = 1; for (i = 1; i <= P->m; i++) { if (P->row[i]->type == GLP_FR) { out_obj = 0; break; } } #endif /* write ROWS section */ xfprintf(fp, "ROWS\n"), recno++; for (i = (out_obj ? 0 : 1); i <= P->m; i++) { int type; type = (i == 0 ? GLP_FR : P->row[i]->type); if (type == GLP_FR) type = 'N'; else if (type == GLP_LO) type = 'G'; else if (type == GLP_UP) type = 'L'; else if (type == GLP_DB || type == GLP_FX) type = 'E'; else xassert(type != type); xfprintf(fp, " %c%*s%s\n", type, csa->deck ? 2 : 1, "", row_name(csa, i)), recno++; } /* write COLUMNS section */ xfprintf(fp, "COLUMNS\n"), recno++; marker = 0; for (j = 1; j <= P->n; j++) { GLPAIJ cj, *aij; int kind; kind = P->col[j]->kind; if (kind == GLP_CV) { if (marker % 2 == 1) { /* close current integer block */ marker++; xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTEND'\n", csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "", csa->deck ? 17 : 1, ""), recno++; } } else if (kind == GLP_IV) { if (marker % 2 == 0) { /* open new integer block */ marker++; xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTORG'\n", csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "", csa->deck ? 17 : 1, ""), recno++; } } else xassert(kind != kind); if (out_obj && P->col[j]->coef != 0.0) { /* make fake objective coefficient */ aij = &cj; aij->row = NULL; aij->val = P->col[j]->coef; aij->c_next = P->col[j]->ptr; } else aij = P->col[j]->ptr; #if 1 /* FIXME */ if (aij == NULL) { /* empty column */ empty++; xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "", csa->deck ? 8 : 1, col_name(csa, j)); /* we need a row */ xassert(P->m > 0); xfprintf(fp, "%*s%-*s", csa->deck ? 2 : 1, "", csa->deck ? 8 : 1, row_name(csa, 1)); xfprintf(fp, "%*s0%*s$ empty column\n", csa->deck ? 13 : 1, "", csa->deck ? 3 : 1, ""), recno++; } #endif count = 0; for (aij = aij; aij != NULL; aij = aij->c_next) { if (one_col || count % 2 == 0) xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "", csa->deck ? 8 : 1, col_name(csa, j)); gap = (one_col || count % 2 == 0 ? 2 : 3); xfprintf(fp, "%*s%-*s", csa->deck ? gap : 1, "", csa->deck ? 8 : 1, row_name(csa, aij->row == NULL ? 0 : aij->row->i)); xfprintf(fp, "%*s%*s", csa->deck ? 2 : 1, "", csa->deck ? 12 : 1, mps_numb(csa, aij->val)), count++; if (one_col || count % 2 == 0) xfprintf(fp, "\n"), recno++; } if (!(one_col || count % 2 == 0)) xfprintf(fp, "\n"), recno++; } if (marker % 2 == 1) { /* close last integer block */ marker++; xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTEND'\n", csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "", csa->deck ? 17 : 1, ""), recno++; } #if 1 if (empty > 0) xprintf("Warning: problem has %d empty column(s)\n", empty); #endif /* write RHS section */ xfprintf(fp, "RHS\n"), recno++; count = 0; for (i = (out_obj ? 0 : 1); i <= P->m; i++) { int type; double rhs; if (i == 0) rhs = P->c0; else { type = P->row[i]->type; if (type == GLP_FR) rhs = 0.0; else if (type == GLP_LO) rhs = P->row[i]->lb; else if (type == GLP_UP) rhs = P->row[i]->ub; else if (type == GLP_DB || type == GLP_FX) rhs = P->row[i]->lb; else xassert(type != type); } if (rhs != 0.0) { if (one_col || count % 2 == 0) xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "", csa->deck ? 8 : 1, "RHS1"); gap = (one_col || count % 2 == 0 ? 2 : 3); xfprintf(fp, "%*s%-*s", csa->deck ? gap : 1, "", csa->deck ? 8 : 1, row_name(csa, i)); xfprintf(fp, "%*s%*s", csa->deck ? 2 : 1, "", csa->deck ? 12 : 1, mps_numb(csa, rhs)), count++; if (one_col || count % 2 == 0) xfprintf(fp, "\n"), recno++; } } if (!(one_col || count % 2 == 0)) xfprintf(fp, "\n"), recno++; /* write RANGES section */ for (i = P->m; i >= 1; i--) if (P->row[i]->type == GLP_DB) break; if (i == 0) goto bnds; xfprintf(fp, "RANGES\n"), recno++; count = 0; for (i = 1; i <= P->m; i++) { if (P->row[i]->type == GLP_DB) { if (one_col || count % 2 == 0) xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "", csa->deck ? 8 : 1, "RNG1"); gap = (one_col || count % 2 == 0 ? 2 : 3); xfprintf(fp, "%*s%-*s", csa->deck ? gap : 1, "", csa->deck ? 8 : 1, row_name(csa, i)); xfprintf(fp, "%*s%*s", csa->deck ? 2 : 1, "", csa->deck ? 12 : 1, mps_numb(csa, P->row[i]->ub - P->row[i]->lb)), count++; if (one_col || count % 2 == 0) xfprintf(fp, "\n"), recno++; } } if (!(one_col || count % 2 == 0)) xfprintf(fp, "\n"), recno++; bnds: /* write BOUNDS section */ for (j = P->n; j >= 1; j--) if (!(P->col[j]->kind == GLP_CV && P->col[j]->type == GLP_LO && P->col[j]->lb == 0.0)) break; if (j == 0) goto endt; xfprintf(fp, "BOUNDS\n"), recno++; for (j = 1; j <= P->n; j++) { int type, data[2]; double bnd[2]; char *spec[2]; spec[0] = spec[1] = NULL; type = P->col[j]->type; if (type == GLP_FR) spec[0] = "FR", data[0] = 0; else if (type == GLP_LO) { if (P->col[j]->lb != 0.0) spec[0] = "LO", data[0] = 1, bnd[0] = P->col[j]->lb; if (P->col[j]->kind == GLP_IV) spec[1] = "PL", data[1] = 0; } else if (type == GLP_UP) { spec[0] = "MI", data[0] = 0; spec[1] = "UP", data[1] = 1, bnd[1] = P->col[j]->ub; } else if (type == GLP_DB) { if (P->col[j]->lb != 0.0) spec[0] = "LO", data[0] = 1, bnd[0] = P->col[j]->lb; spec[1] = "UP", data[1] = 1, bnd[1] = P->col[j]->ub; } else if (type == GLP_FX) spec[0] = "FX", data[0] = 1, bnd[0] = P->col[j]->lb; else xassert(type != type); for (i = 0; i <= 1; i++) { if (spec[i] != NULL) { xfprintf(fp, " %s %-*s%*s%-*s", spec[i], csa->deck ? 8 : 1, "BND1", csa->deck ? 2 : 1, "", csa->deck ? 8 : 1, col_name(csa, j)); if (data[i]) xfprintf(fp, "%*s%*s", csa->deck ? 2 : 1, "", csa->deck ? 12 : 1, mps_numb(csa, bnd[i])); xfprintf(fp, "\n"), recno++; } } } endt: /* write ENDATA indicator record */ xfprintf(fp, "ENDATA\n"), recno++; xfflush(fp); if (xferror(fp)) { xprintf("Write error on `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } /* problem data has been successfully written */ xprintf("%d records were written\n", recno); ret = 0; done: if (fp != NULL) xfclose(fp); return ret; } /* eof */ Rglpk/src/GLPK/glpspm.c0000644000176000001440000006053012245352174014364 0ustar ripleyusers/* glpspm.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glphbm.h" #include "glprgr.h" #include "glpspm.h" #include "env.h" /*********************************************************************** * NAME * * spm_create_mat - create general sparse matrix * * SYNOPSIS * * #include "glpspm.h" * SPM *spm_create_mat(int m, int n); * * DESCRIPTION * * The routine spm_create_mat creates a general sparse matrix having * m rows and n columns. Being created the matrix is zero (empty), i.e. * has no elements. * * RETURNS * * The routine returns a pointer to the matrix created. */ SPM *spm_create_mat(int m, int n) { SPM *A; xassert(0 <= m && m < INT_MAX); xassert(0 <= n && n < INT_MAX); A = xmalloc(sizeof(SPM)); A->m = m; A->n = n; if (m == 0 || n == 0) { A->pool = NULL; A->row = NULL; A->col = NULL; } else { int i, j; A->pool = dmp_create_pool(); A->row = xcalloc(1+m, sizeof(SPME *)); for (i = 1; i <= m; i++) A->row[i] = NULL; A->col = xcalloc(1+n, sizeof(SPME *)); for (j = 1; j <= n; j++) A->col[j] = NULL; } return A; } /*********************************************************************** * NAME * * spm_new_elem - add new element to sparse matrix * * SYNOPSIS * * #include "glpspm.h" * SPME *spm_new_elem(SPM *A, int i, int j, double val); * * DESCRIPTION * * The routine spm_new_elem adds a new element to the specified sparse * matrix. Parameters i, j, and val specify the row number, the column * number, and a numerical value of the element, respectively. * * RETURNS * * The routine returns a pointer to the new element added. */ SPME *spm_new_elem(SPM *A, int i, int j, double val) { SPME *e; xassert(1 <= i && i <= A->m); xassert(1 <= j && j <= A->n); e = dmp_get_atom(A->pool, sizeof(SPME)); e->i = i; e->j = j; e->val = val; e->r_prev = NULL; e->r_next = A->row[i]; if (e->r_next != NULL) e->r_next->r_prev = e; e->c_prev = NULL; e->c_next = A->col[j]; if (e->c_next != NULL) e->c_next->c_prev = e; A->row[i] = A->col[j] = e; return e; } /*********************************************************************** * NAME * * spm_delete_mat - delete general sparse matrix * * SYNOPSIS * * #include "glpspm.h" * void spm_delete_mat(SPM *A); * * DESCRIPTION * * The routine deletes the specified general sparse matrix freeing all * the memory allocated to this object. */ void spm_delete_mat(SPM *A) { /* delete sparse matrix */ if (A->pool != NULL) dmp_delete_pool(A->pool); if (A->row != NULL) xfree(A->row); if (A->col != NULL) xfree(A->col); xfree(A); return; } /*********************************************************************** * NAME * * spm_test_mat_e - create test sparse matrix of E(n,c) class * * SYNOPSIS * * #include "glpspm.h" * SPM *spm_test_mat_e(int n, int c); * * DESCRIPTION * * The routine spm_test_mat_e creates a test sparse matrix of E(n,c) * class as described in the book: Ole 0sterby, Zahari Zlatev. Direct * Methods for Sparse Matrices. Springer-Verlag, 1983. * * Matrix of E(n,c) class is a symmetric positive definite matrix of * the order n. It has the number 4 on its main diagonal and the number * -1 on its four co-diagonals, two of which are neighbour to the main * diagonal and two others are shifted from the main diagonal on the * distance c. * * It is necessary that n >= 3 and 2 <= c <= n-1. * * RETURNS * * The routine returns a pointer to the matrix created. */ SPM *spm_test_mat_e(int n, int c) { SPM *A; int i; xassert(n >= 3 && 2 <= c && c <= n-1); A = spm_create_mat(n, n); for (i = 1; i <= n; i++) spm_new_elem(A, i, i, 4.0); for (i = 1; i <= n-1; i++) { spm_new_elem(A, i, i+1, -1.0); spm_new_elem(A, i+1, i, -1.0); } for (i = 1; i <= n-c; i++) { spm_new_elem(A, i, i+c, -1.0); spm_new_elem(A, i+c, i, -1.0); } return A; } /*********************************************************************** * NAME * * spm_test_mat_d - create test sparse matrix of D(n,c) class * * SYNOPSIS * * #include "glpspm.h" * SPM *spm_test_mat_d(int n, int c); * * DESCRIPTION * * The routine spm_test_mat_d creates a test sparse matrix of D(n,c) * class as described in the book: Ole 0sterby, Zahari Zlatev. Direct * Methods for Sparse Matrices. Springer-Verlag, 1983. * * Matrix of D(n,c) class is a non-singular matrix of the order n. It * has unity main diagonal, three co-diagonals above the main diagonal * on the distance c, which are cyclically continued below the main * diagonal, and a triangle block of the size 10x10 in the upper right * corner. * * It is necessary that n >= 14 and 1 <= c <= n-13. * * RETURNS * * The routine returns a pointer to the matrix created. */ SPM *spm_test_mat_d(int n, int c) { SPM *A; int i, j; xassert(n >= 14 && 1 <= c && c <= n-13); A = spm_create_mat(n, n); for (i = 1; i <= n; i++) spm_new_elem(A, i, i, 1.0); for (i = 1; i <= n-c; i++) spm_new_elem(A, i, i+c, (double)(i+1)); for (i = n-c+1; i <= n; i++) spm_new_elem(A, i, i-n+c, (double)(i+1)); for (i = 1; i <= n-c-1; i++) spm_new_elem(A, i, i+c+1, (double)(-i)); for (i = n-c; i <= n; i++) spm_new_elem(A, i, i-n+c+1, (double)(-i)); for (i = 1; i <= n-c-2; i++) spm_new_elem(A, i, i+c+2, 16.0); for (i = n-c-1; i <= n; i++) spm_new_elem(A, i, i-n+c+2, 16.0); for (j = 1; j <= 10; j++) for (i = 1; i <= 11-j; i++) spm_new_elem(A, i, n-11+i+j, 100.0 * (double)j); return A; } /*********************************************************************** * NAME * * spm_show_mat - write sparse matrix pattern in BMP file format * * SYNOPSIS * * #include "glpspm.h" * int spm_show_mat(const SPM *A, const char *fname); * * DESCRIPTION * * The routine spm_show_mat writes pattern of the specified sparse * matrix in uncompressed BMP file format (Windows bitmap) to a binary * file whose name is specified by the character string fname. * * Each pixel corresponds to one matrix element. The pixel colors have * the following meaning: * * Black structurally zero element * White positive element * Cyan negative element * Green zero element * Red duplicate element * * RETURNS * * If no error occured, the routine returns zero. Otherwise, it prints * an appropriate error message and returns non-zero. */ int spm_show_mat(const SPM *A, const char *fname) { int m = A->m; int n = A->n; int i, j, k, ret; char *map; xprintf("spm_show_mat: writing matrix pattern to `%s'...\n", fname); xassert(1 <= m && m <= 32767); xassert(1 <= n && n <= 32767); map = xmalloc(m * n); memset(map, 0x08, m * n); for (i = 1; i <= m; i++) { SPME *e; for (e = A->row[i]; e != NULL; e = e->r_next) { j = e->j; xassert(1 <= j && j <= n); k = n * (i - 1) + (j - 1); if (map[k] != 0x08) map[k] = 0x0C; else if (e->val > 0.0) map[k] = 0x0F; else if (e->val < 0.0) map[k] = 0x0B; else map[k] = 0x0A; } } ret = rgr_write_bmp16(fname, m, n, map); xfree(map); return ret; } /*********************************************************************** * NAME * * spm_read_hbm - read sparse matrix in Harwell-Boeing format * * SYNOPSIS * * #include "glpspm.h" * SPM *spm_read_hbm(const char *fname); * * DESCRIPTION * * The routine spm_read_hbm reads a sparse matrix in the Harwell-Boeing * format from a text file whose name is the character string fname. * * Detailed description of the Harwell-Boeing format recognised by this * routine can be found in the following report: * * I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the Harwell-Boeing * Sparse Matrix Collection (Release I), TR/PA/92/86, October 1992. * * NOTE * * The routine spm_read_hbm reads the matrix "as is", due to which zero * and/or duplicate elements can appear in the matrix. * * RETURNS * * If no error occured, the routine returns a pointer to the matrix * created. Otherwise, the routine prints an appropriate error message * and returns NULL. */ SPM *spm_read_hbm(const char *fname) { SPM *A = NULL; HBM *hbm; int nrow, ncol, nnzero, i, j, beg, end, ptr, *colptr, *rowind; double val, *values; char *mxtype; hbm = hbm_read_mat(fname); if (hbm == NULL) { xprintf("spm_read_hbm: unable to read matrix\n"); goto fini; } mxtype = hbm->mxtype; nrow = hbm->nrow; ncol = hbm->ncol; nnzero = hbm->nnzero; colptr = hbm->colptr; rowind = hbm->rowind; values = hbm->values; if (!(strcmp(mxtype, "RSA") == 0 || strcmp(mxtype, "PSA") == 0 || strcmp(mxtype, "RUA") == 0 || strcmp(mxtype, "PUA") == 0 || strcmp(mxtype, "RRA") == 0 || strcmp(mxtype, "PRA") == 0)) { xprintf("spm_read_hbm: matrix type `%s' not supported\n", mxtype); goto fini; } A = spm_create_mat(nrow, ncol); if (mxtype[1] == 'S' || mxtype[1] == 'U') xassert(nrow == ncol); for (j = 1; j <= ncol; j++) { beg = colptr[j]; end = colptr[j+1]; xassert(1 <= beg && beg <= end && end <= nnzero + 1); for (ptr = beg; ptr < end; ptr++) { i = rowind[ptr]; xassert(1 <= i && i <= nrow); if (mxtype[0] == 'R') val = values[ptr]; else val = 1.0; spm_new_elem(A, i, j, val); if (mxtype[1] == 'S' && i != j) spm_new_elem(A, j, i, val); } } fini: if (hbm != NULL) hbm_free_mat(hbm); return A; } /*********************************************************************** * NAME * * spm_count_nnz - determine number of non-zeros in sparse matrix * * SYNOPSIS * * #include "glpspm.h" * int spm_count_nnz(const SPM *A); * * RETURNS * * The routine spm_count_nnz returns the number of structural non-zero * elements in the specified sparse matrix. */ int spm_count_nnz(const SPM *A) { SPME *e; int i, nnz = 0; for (i = 1; i <= A->m; i++) for (e = A->row[i]; e != NULL; e = e->r_next) nnz++; return nnz; } /*********************************************************************** * NAME * * spm_drop_zeros - remove zero elements from sparse matrix * * SYNOPSIS * * #include "glpspm.h" * int spm_drop_zeros(SPM *A, double eps); * * DESCRIPTION * * The routine spm_drop_zeros removes all elements from the specified * sparse matrix, whose absolute value is less than eps. * * If the parameter eps is 0, only zero elements are removed from the * matrix. * * RETURNS * * The routine returns the number of elements removed. */ int spm_drop_zeros(SPM *A, double eps) { SPME *e, *next; int i, count = 0; for (i = 1; i <= A->m; i++) { for (e = A->row[i]; e != NULL; e = next) { next = e->r_next; if (e->val == 0.0 || fabs(e->val) < eps) { /* remove element from the row list */ if (e->r_prev == NULL) A->row[e->i] = e->r_next; else e->r_prev->r_next = e->r_next; if (e->r_next == NULL) ; else e->r_next->r_prev = e->r_prev; /* remove element from the column list */ if (e->c_prev == NULL) A->col[e->j] = e->c_next; else e->c_prev->c_next = e->c_next; if (e->c_next == NULL) ; else e->c_next->c_prev = e->c_prev; /* return element to the memory pool */ dmp_free_atom(A->pool, e, sizeof(SPME)); count++; } } } return count; } /*********************************************************************** * NAME * * spm_read_mat - read sparse matrix from text file * * SYNOPSIS * * #include "glpspm.h" * SPM *spm_read_mat(const char *fname); * * DESCRIPTION * * The routine reads a sparse matrix from a text file whose name is * specified by the parameter fname. * * For the file format see description of the routine spm_write_mat. * * RETURNS * * On success the routine returns a pointer to the matrix created, * otherwise NULL. */ #if 1 SPM *spm_read_mat(const char *fname) { xassert(fname != fname); return NULL; } #else SPM *spm_read_mat(const char *fname) { SPM *A = NULL; PDS *pds; jmp_buf jump; int i, j, k, m, n, nnz, fail = 0; double val; xprintf("spm_read_mat: reading matrix from `%s'...\n", fname); pds = pds_open_file(fname); if (pds == NULL) { xprintf("spm_read_mat: unable to open `%s' - %s\n", fname, strerror(errno)); fail = 1; goto done; } if (setjmp(jump)) { fail = 1; goto done; } pds_set_jump(pds, jump); /* number of rows, number of columns, number of non-zeros */ m = pds_scan_int(pds); if (m < 0) pds_error(pds, "invalid number of rows\n"); n = pds_scan_int(pds); if (n < 0) pds_error(pds, "invalid number of columns\n"); nnz = pds_scan_int(pds); if (nnz < 0) pds_error(pds, "invalid number of non-zeros\n"); /* create matrix */ xprintf("spm_read_mat: %d rows, %d columns, %d non-zeros\n", m, n, nnz); A = spm_create_mat(m, n); /* read matrix elements */ for (k = 1; k <= nnz; k++) { /* row index, column index, element value */ i = pds_scan_int(pds); if (!(1 <= i && i <= m)) pds_error(pds, "row index out of range\n"); j = pds_scan_int(pds); if (!(1 <= j && j <= n)) pds_error(pds, "column index out of range\n"); val = pds_scan_num(pds); /* add new element to the matrix */ spm_new_elem(A, i, j, val); } xprintf("spm_read_mat: %d lines were read\n", pds->count); done: if (pds != NULL) pds_close_file(pds); if (fail && A != NULL) spm_delete_mat(A), A = NULL; return A; } #endif /*********************************************************************** * NAME * * spm_write_mat - write sparse matrix to text file * * SYNOPSIS * * #include "glpspm.h" * int spm_write_mat(const SPM *A, const char *fname); * * DESCRIPTION * * The routine spm_write_mat writes the specified sparse matrix to a * text file whose name is specified by the parameter fname. This file * can be read back with the routine spm_read_mat. * * RETURNS * * On success the routine returns zero, otherwise non-zero. * * FILE FORMAT * * The file created by the routine spm_write_mat is a plain text file, * which contains the following information: * * m n nnz * row[1] col[1] val[1] * row[2] col[2] val[2] * . . . * row[nnz] col[nnz] val[nnz] * * where: * m is the number of rows; * n is the number of columns; * nnz is the number of non-zeros; * row[k], k = 1,...,nnz, are row indices; * col[k], k = 1,...,nnz, are column indices; * val[k], k = 1,...,nnz, are element values. */ #if 1 int spm_write_mat(const SPM *A, const char *fname) { xassert(A != A); xassert(fname != fname); return 0; } #else int spm_write_mat(const SPM *A, const char *fname) { FILE *fp; int i, nnz, ret = 0; xprintf("spm_write_mat: writing matrix to `%s'...\n", fname); fp = fopen(fname, "w"); if (fp == NULL) { xprintf("spm_write_mat: unable to create `%s' - %s\n", fname, strerror(errno)); ret = 1; goto done; } /* number of rows, number of columns, number of non-zeros */ nnz = spm_count_nnz(A); fprintf(fp, "%d %d %d\n", A->m, A->n, nnz); /* walk through rows of the matrix */ for (i = 1; i <= A->m; i++) { SPME *e; /* walk through elements of i-th row */ for (e = A->row[i]; e != NULL; e = e->r_next) { /* row index, column index, element value */ fprintf(fp, "%d %d %.*g\n", e->i, e->j, DBL_DIG, e->val); } } fflush(fp); if (ferror(fp)) { xprintf("spm_write_mat: writing error on `%s' - %s\n", fname, strerror(errno)); ret = 1; goto done; } xprintf("spm_write_mat: %d lines were written\n", 1 + nnz); done: if (fp != NULL) fclose(fp); return ret; } #endif /*********************************************************************** * NAME * * spm_transpose - transpose sparse matrix * * SYNOPSIS * * #include "glpspm.h" * SPM *spm_transpose(const SPM *A); * * RETURNS * * The routine computes and returns sparse matrix B, which is a matrix * transposed to sparse matrix A. */ SPM *spm_transpose(const SPM *A) { SPM *B; int i; B = spm_create_mat(A->n, A->m); for (i = 1; i <= A->m; i++) { SPME *e; for (e = A->row[i]; e != NULL; e = e->r_next) spm_new_elem(B, e->j, i, e->val); } return B; } SPM *spm_add_sym(const SPM *A, const SPM *B) { /* add two sparse matrices (symbolic phase) */ SPM *C; int i, j, *flag; xassert(A->m == B->m); xassert(A->n == B->n); /* create resultant matrix */ C = spm_create_mat(A->m, A->n); /* allocate and clear the flag array */ flag = xcalloc(1+C->n, sizeof(int)); for (j = 1; j <= C->n; j++) flag[j] = 0; /* compute pattern of C = A + B */ for (i = 1; i <= C->m; i++) { SPME *e; /* at the beginning i-th row of C is empty */ /* (i-th row of C) := (i-th row of C) union (i-th row of A) */ for (e = A->row[i]; e != NULL; e = e->r_next) { /* (note that i-th row of A may have duplicate elements) */ j = e->j; if (!flag[j]) { spm_new_elem(C, i, j, 0.0); flag[j] = 1; } } /* (i-th row of C) := (i-th row of C) union (i-th row of B) */ for (e = B->row[i]; e != NULL; e = e->r_next) { /* (note that i-th row of B may have duplicate elements) */ j = e->j; if (!flag[j]) { spm_new_elem(C, i, j, 0.0); flag[j] = 1; } } /* reset the flag array */ for (e = C->row[i]; e != NULL; e = e->r_next) flag[e->j] = 0; } /* check and deallocate the flag array */ for (j = 1; j <= C->n; j++) xassert(!flag[j]); xfree(flag); return C; } void spm_add_num(SPM *C, double alfa, const SPM *A, double beta, const SPM *B) { /* add two sparse matrices (numeric phase) */ int i, j; double *work; /* allocate and clear the working array */ work = xcalloc(1+C->n, sizeof(double)); for (j = 1; j <= C->n; j++) work[j] = 0.0; /* compute matrix C = alfa * A + beta * B */ for (i = 1; i <= C->n; i++) { SPME *e; /* work := alfa * (i-th row of A) + beta * (i-th row of B) */ /* (note that A and/or B may have duplicate elements) */ for (e = A->row[i]; e != NULL; e = e->r_next) work[e->j] += alfa * e->val; for (e = B->row[i]; e != NULL; e = e->r_next) work[e->j] += beta * e->val; /* (i-th row of C) := work, work := 0 */ for (e = C->row[i]; e != NULL; e = e->r_next) { j = e->j; e->val = work[j]; work[j] = 0.0; } } /* check and deallocate the working array */ for (j = 1; j <= C->n; j++) xassert(work[j] == 0.0); xfree(work); return; } SPM *spm_add_mat(double alfa, const SPM *A, double beta, const SPM *B) { /* add two sparse matrices (driver routine) */ SPM *C; C = spm_add_sym(A, B); spm_add_num(C, alfa, A, beta, B); return C; } SPM *spm_mul_sym(const SPM *A, const SPM *B) { /* multiply two sparse matrices (symbolic phase) */ int i, j, k, *flag; SPM *C; xassert(A->n == B->m); /* create resultant matrix */ C = spm_create_mat(A->m, B->n); /* allocate and clear the flag array */ flag = xcalloc(1+C->n, sizeof(int)); for (j = 1; j <= C->n; j++) flag[j] = 0; /* compute pattern of C = A * B */ for (i = 1; i <= C->m; i++) { SPME *e, *ee; /* compute pattern of i-th row of C */ for (e = A->row[i]; e != NULL; e = e->r_next) { k = e->j; for (ee = B->row[k]; ee != NULL; ee = ee->r_next) { j = ee->j; /* if a[i,k] != 0 and b[k,j] != 0 then c[i,j] != 0 */ if (!flag[j]) { /* c[i,j] does not exist, so create it */ spm_new_elem(C, i, j, 0.0); flag[j] = 1; } } } /* reset the flag array */ for (e = C->row[i]; e != NULL; e = e->r_next) flag[e->j] = 0; } /* check and deallocate the flag array */ for (j = 1; j <= C->n; j++) xassert(!flag[j]); xfree(flag); return C; } void spm_mul_num(SPM *C, const SPM *A, const SPM *B) { /* multiply two sparse matrices (numeric phase) */ int i, j; double *work; /* allocate and clear the working array */ work = xcalloc(1+A->n, sizeof(double)); for (j = 1; j <= A->n; j++) work[j] = 0.0; /* compute matrix C = A * B */ for (i = 1; i <= C->m; i++) { SPME *e, *ee; double temp; /* work := (i-th row of A) */ /* (note that A may have duplicate elements) */ for (e = A->row[i]; e != NULL; e = e->r_next) work[e->j] += e->val; /* compute i-th row of C */ for (e = C->row[i]; e != NULL; e = e->r_next) { j = e->j; /* c[i,j] := work * (j-th column of B) */ temp = 0.0; for (ee = B->col[j]; ee != NULL; ee = ee->c_next) temp += work[ee->i] * ee->val; e->val = temp; } /* reset the working array */ for (e = A->row[i]; e != NULL; e = e->r_next) work[e->j] = 0.0; } /* check and deallocate the working array */ for (j = 1; j <= A->n; j++) xassert(work[j] == 0.0); xfree(work); return; } SPM *spm_mul_mat(const SPM *A, const SPM *B) { /* multiply two sparse matrices (driver routine) */ SPM *C; C = spm_mul_sym(A, B); spm_mul_num(C, A, B); return C; } PER *spm_create_per(int n) { /* create permutation matrix */ PER *P; int k; xassert(n >= 0); P = xmalloc(sizeof(PER)); P->n = n; P->row = xcalloc(1+n, sizeof(int)); P->col = xcalloc(1+n, sizeof(int)); /* initially it is identity matrix */ for (k = 1; k <= n; k++) P->row[k] = P->col[k] = k; return P; } void spm_check_per(PER *P) { /* check permutation matrix for correctness */ int i, j; xassert(P->n >= 0); for (i = 1; i <= P->n; i++) { j = P->row[i]; xassert(1 <= j && j <= P->n); xassert(P->col[j] == i); } return; } void spm_delete_per(PER *P) { /* delete permutation matrix */ xfree(P->row); xfree(P->col); xfree(P); return; } /* eof */ Rglpk/src/GLPK/dmp.h0000644000176000001440000000365612245352174013655 0ustar ripleyusers/* dmp.h (dynamic memory pool) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef DMP_H #define DMP_H #include "stdc.h" typedef struct DMP DMP; #define dmp_debug _glp_dmp_debug extern int dmp_debug; /* debug mode flag */ #define dmp_create_pool _glp_dmp_create_pool DMP *dmp_create_pool(void); /* create dynamic memory pool */ #define dmp_talloc(pool, type) \ ((type *)dmp_get_atom(pool, sizeof(type))) #define dmp_get_atom _glp_dmp_get_atom void *dmp_get_atom(DMP *pool, int size); /* get free atom from dynamic memory pool */ #define dmp_tfree(pool, atom) \ dmp_free_atom(pool, atom, sizeof(*(atom))) #define dmp_free_atom _glp_dmp_free_atom void dmp_free_atom(DMP *pool, void *atom, int size); /* return atom to dynamic memory pool */ #define dmp_in_use _glp_dmp_in_use size_t dmp_in_use(DMP *pool); /* determine how many atoms are still in use */ #define dmp_delete_pool _glp_dmp_delete_pool void dmp_delete_pool(DMP *pool); /* delete dynamic memory pool */ #endif /* eof */ Rglpk/src/GLPK/glplux.c0000644000176000001440000011403512245352174014375 0ustar ripleyusers/* glplux.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glplux.h" #include "env.h" #define xfault xerror #define dmp_create_poolx(size) dmp_create_pool() /*---------------------------------------------------------------------- // lux_create - create LU-factorization. // // SYNOPSIS // // #include "glplux.h" // LUX *lux_create(int n); // // DESCRIPTION // // The routine lux_create creates LU-factorization data structure for // a matrix of the order n. Initially the factorization corresponds to // the unity matrix (F = V = P = Q = I, so A = I). // // RETURNS // // The routine returns a pointer to the created LU-factorization data // structure, which represents the unity matrix of the order n. */ LUX *lux_create(int n) { LUX *lux; int k; if (n < 1) xfault("lux_create: n = %d; invalid parameter\n", n); lux = xmalloc(sizeof(LUX)); lux->n = n; lux->pool = dmp_create_poolx(sizeof(LUXELM)); lux->F_row = xcalloc(1+n, sizeof(LUXELM *)); lux->F_col = xcalloc(1+n, sizeof(LUXELM *)); lux->V_piv = xcalloc(1+n, sizeof(mpq_t)); lux->V_row = xcalloc(1+n, sizeof(LUXELM *)); lux->V_col = xcalloc(1+n, sizeof(LUXELM *)); lux->P_row = xcalloc(1+n, sizeof(int)); lux->P_col = xcalloc(1+n, sizeof(int)); lux->Q_row = xcalloc(1+n, sizeof(int)); lux->Q_col = xcalloc(1+n, sizeof(int)); for (k = 1; k <= n; k++) { lux->F_row[k] = lux->F_col[k] = NULL; mpq_init(lux->V_piv[k]); mpq_set_si(lux->V_piv[k], 1, 1); lux->V_row[k] = lux->V_col[k] = NULL; lux->P_row[k] = lux->P_col[k] = k; lux->Q_row[k] = lux->Q_col[k] = k; } lux->rank = n; return lux; } /*---------------------------------------------------------------------- // initialize - initialize LU-factorization data structures. // // This routine initializes data structures for subsequent computing // the LU-factorization of a given matrix A, which is specified by the // formal routine col. On exit V = A and F = P = Q = I, where I is the // unity matrix. */ static void initialize(LUX *lux, int (*col)(void *info, int j, int ind[], mpq_t val[]), void *info, LUXWKA *wka) { int n = lux->n; DMP *pool = lux->pool; LUXELM **F_row = lux->F_row; LUXELM **F_col = lux->F_col; mpq_t *V_piv = lux->V_piv; LUXELM **V_row = lux->V_row; LUXELM **V_col = lux->V_col; int *P_row = lux->P_row; int *P_col = lux->P_col; int *Q_row = lux->Q_row; int *Q_col = lux->Q_col; int *R_len = wka->R_len; int *R_head = wka->R_head; int *R_prev = wka->R_prev; int *R_next = wka->R_next; int *C_len = wka->C_len; int *C_head = wka->C_head; int *C_prev = wka->C_prev; int *C_next = wka->C_next; LUXELM *fij, *vij; int i, j, k, len, *ind; mpq_t *val; /* F := I */ for (i = 1; i <= n; i++) { while (F_row[i] != NULL) { fij = F_row[i], F_row[i] = fij->r_next; mpq_clear(fij->val); dmp_free_atom(pool, fij, sizeof(LUXELM)); } } for (j = 1; j <= n; j++) F_col[j] = NULL; /* V := 0 */ for (k = 1; k <= n; k++) mpq_set_si(V_piv[k], 0, 1); for (i = 1; i <= n; i++) { while (V_row[i] != NULL) { vij = V_row[i], V_row[i] = vij->r_next; mpq_clear(vij->val); dmp_free_atom(pool, vij, sizeof(LUXELM)); } } for (j = 1; j <= n; j++) V_col[j] = NULL; /* V := A */ ind = xcalloc(1+n, sizeof(int)); val = xcalloc(1+n, sizeof(mpq_t)); for (k = 1; k <= n; k++) mpq_init(val[k]); for (j = 1; j <= n; j++) { /* obtain j-th column of matrix A */ len = col(info, j, ind, val); if (!(0 <= len && len <= n)) xfault("lux_decomp: j = %d: len = %d; invalid column length" "\n", j, len); /* copy elements of j-th column to matrix V */ for (k = 1; k <= len; k++) { /* get row index of a[i,j] */ i = ind[k]; if (!(1 <= i && i <= n)) xfault("lux_decomp: j = %d: i = %d; row index out of ran" "ge\n", j, i); /* check for duplicate indices */ if (V_row[i] != NULL && V_row[i]->j == j) xfault("lux_decomp: j = %d: i = %d; duplicate row indice" "s not allowed\n", j, i); /* check for zero value */ if (mpq_sgn(val[k]) == 0) xfault("lux_decomp: j = %d: i = %d; zero elements not al" "lowed\n", j, i); /* add new element v[i,j] = a[i,j] to V */ vij = dmp_get_atom(pool, sizeof(LUXELM)); vij->i = i, vij->j = j; mpq_init(vij->val); mpq_set(vij->val, val[k]); vij->r_prev = NULL; vij->r_next = V_row[i]; vij->c_prev = NULL; vij->c_next = V_col[j]; if (vij->r_next != NULL) vij->r_next->r_prev = vij; if (vij->c_next != NULL) vij->c_next->c_prev = vij; V_row[i] = V_col[j] = vij; } } xfree(ind); for (k = 1; k <= n; k++) mpq_clear(val[k]); xfree(val); /* P := Q := I */ for (k = 1; k <= n; k++) P_row[k] = P_col[k] = Q_row[k] = Q_col[k] = k; /* the rank of A and V is not determined yet */ lux->rank = -1; /* initially the entire matrix V is active */ /* determine its row lengths */ for (i = 1; i <= n; i++) { len = 0; for (vij = V_row[i]; vij != NULL; vij = vij->r_next) len++; R_len[i] = len; } /* build linked lists of active rows */ for (len = 0; len <= n; len++) R_head[len] = 0; for (i = 1; i <= n; i++) { len = R_len[i]; R_prev[i] = 0; R_next[i] = R_head[len]; if (R_next[i] != 0) R_prev[R_next[i]] = i; R_head[len] = i; } /* determine its column lengths */ for (j = 1; j <= n; j++) { len = 0; for (vij = V_col[j]; vij != NULL; vij = vij->c_next) len++; C_len[j] = len; } /* build linked lists of active columns */ for (len = 0; len <= n; len++) C_head[len] = 0; for (j = 1; j <= n; j++) { len = C_len[j]; C_prev[j] = 0; C_next[j] = C_head[len]; if (C_next[j] != 0) C_prev[C_next[j]] = j; C_head[len] = j; } return; } /*---------------------------------------------------------------------- // find_pivot - choose a pivot element. // // This routine chooses a pivot element v[p,q] in the active submatrix // of matrix U = P*V*Q. // // It is assumed that on entry the matrix U has the following partially // triangularized form: // // 1 k n // 1 x x x x x x x x x x // . x x x x x x x x x // . . x x x x x x x x // . . . x x x x x x x // k . . . . * * * * * * // . . . . * * * * * * // . . . . * * * * * * // . . . . * * * * * * // . . . . * * * * * * // n . . . . * * * * * * // // where rows and columns k, k+1, ..., n belong to the active submatrix // (elements of the active submatrix are marked by '*'). // // Since the matrix U = P*V*Q is not stored, the routine works with the // matrix V. It is assumed that the row-wise representation corresponds // to the matrix V, but the column-wise representation corresponds to // the active submatrix of the matrix V, i.e. elements of the matrix V, // which does not belong to the active submatrix, are missing from the // column linked lists. It is also assumed that each active row of the // matrix V is in the set R[len], where len is number of non-zeros in // the row, and each active column of the matrix V is in the set C[len], // where len is number of non-zeros in the column (in the latter case // only elements of the active submatrix are counted; such elements are // marked by '*' on the figure above). // // Due to exact arithmetic any non-zero element of the active submatrix // can be chosen as a pivot. However, to keep sparsity of the matrix V // the routine uses Markowitz strategy, trying to choose such element // v[p,q], which has smallest Markowitz cost (nr[p]-1) * (nc[q]-1), // where nr[p] and nc[q] are the number of non-zero elements, resp., in // p-th row and in q-th column of the active submatrix. // // In order to reduce the search, i.e. not to walk through all elements // of the active submatrix, the routine exploits a technique proposed by // I.Duff. This technique is based on using the sets R[len] and C[len] // of active rows and columns. // // On exit the routine returns a pointer to a pivot v[p,q] chosen, or // NULL, if the active submatrix is empty. */ static LUXELM *find_pivot(LUX *lux, LUXWKA *wka) { int n = lux->n; LUXELM **V_row = lux->V_row; LUXELM **V_col = lux->V_col; int *R_len = wka->R_len; int *R_head = wka->R_head; int *R_next = wka->R_next; int *C_len = wka->C_len; int *C_head = wka->C_head; int *C_next = wka->C_next; LUXELM *piv, *some, *vij; int i, j, len, min_len, ncand, piv_lim = 5; double best, cost; /* nothing is chosen so far */ piv = NULL, best = DBL_MAX, ncand = 0; /* if in the active submatrix there is a column that has the only non-zero (column singleton), choose it as a pivot */ j = C_head[1]; if (j != 0) { xassert(C_len[j] == 1); piv = V_col[j]; xassert(piv != NULL && piv->c_next == NULL); goto done; } /* if in the active submatrix there is a row that has the only non-zero (row singleton), choose it as a pivot */ i = R_head[1]; if (i != 0) { xassert(R_len[i] == 1); piv = V_row[i]; xassert(piv != NULL && piv->r_next == NULL); goto done; } /* there are no singletons in the active submatrix; walk through other non-empty rows and columns */ for (len = 2; len <= n; len++) { /* consider active columns having len non-zeros */ for (j = C_head[len]; j != 0; j = C_next[j]) { /* j-th column has len non-zeros */ /* find an element in the row of minimal length */ some = NULL, min_len = INT_MAX; for (vij = V_col[j]; vij != NULL; vij = vij->c_next) { if (min_len > R_len[vij->i]) some = vij, min_len = R_len[vij->i]; /* if Markowitz cost of this element is not greater than (len-1)**2, it can be chosen right now; this heuristic reduces the search and works well in many cases */ if (min_len <= len) { piv = some; goto done; } } /* j-th column has been scanned */ /* the minimal element found is a next pivot candidate */ xassert(some != NULL); ncand++; /* compute its Markowitz cost */ cost = (double)(min_len - 1) * (double)(len - 1); /* choose between the current candidate and this element */ if (cost < best) piv = some, best = cost; /* if piv_lim candidates have been considered, there is a doubt that a much better candidate exists; therefore it is the time to terminate the search */ if (ncand == piv_lim) goto done; } /* now consider active rows having len non-zeros */ for (i = R_head[len]; i != 0; i = R_next[i]) { /* i-th row has len non-zeros */ /* find an element in the column of minimal length */ some = NULL, min_len = INT_MAX; for (vij = V_row[i]; vij != NULL; vij = vij->r_next) { if (min_len > C_len[vij->j]) some = vij, min_len = C_len[vij->j]; /* if Markowitz cost of this element is not greater than (len-1)**2, it can be chosen right now; this heuristic reduces the search and works well in many cases */ if (min_len <= len) { piv = some; goto done; } } /* i-th row has been scanned */ /* the minimal element found is a next pivot candidate */ xassert(some != NULL); ncand++; /* compute its Markowitz cost */ cost = (double)(len - 1) * (double)(min_len - 1); /* choose between the current candidate and this element */ if (cost < best) piv = some, best = cost; /* if piv_lim candidates have been considered, there is a doubt that a much better candidate exists; therefore it is the time to terminate the search */ if (ncand == piv_lim) goto done; } } done: /* bring the pivot v[p,q] to the factorizing routine */ return piv; } /*---------------------------------------------------------------------- // eliminate - perform gaussian elimination. // // This routine performs elementary gaussian transformations in order // to eliminate subdiagonal elements in the k-th column of the matrix // U = P*V*Q using the pivot element u[k,k], where k is the number of // the current elimination step. // // The parameter piv specifies the pivot element v[p,q] = u[k,k]. // // Each time when the routine applies the elementary transformation to // a non-pivot row of the matrix V, it stores the corresponding element // to the matrix F in order to keep the main equality A = F*V. // // The routine assumes that on entry the matrices L = P*F*inv(P) and // U = P*V*Q are the following: // // 1 k 1 k n // 1 1 . . . . . . . . . 1 x x x x x x x x x x // x 1 . . . . . . . . . x x x x x x x x x // x x 1 . . . . . . . . . x x x x x x x x // x x x 1 . . . . . . . . . x x x x x x x // k x x x x 1 . . . . . k . . . . * * * * * * // x x x x _ 1 . . . . . . . . # * * * * * // x x x x _ . 1 . . . . . . . # * * * * * // x x x x _ . . 1 . . . . . . # * * * * * // x x x x _ . . . 1 . . . . . # * * * * * // n x x x x _ . . . . 1 n . . . . # * * * * * // // matrix L matrix U // // where rows and columns of the matrix U with numbers k, k+1, ..., n // form the active submatrix (eliminated elements are marked by '#' and // other elements of the active submatrix are marked by '*'). Note that // each eliminated non-zero element u[i,k] of the matrix U gives the // corresponding element l[i,k] of the matrix L (marked by '_'). // // Actually all operations are performed on the matrix V. Should note // that the row-wise representation corresponds to the matrix V, but the // column-wise representation corresponds to the active submatrix of the // matrix V, i.e. elements of the matrix V, which doesn't belong to the // active submatrix, are missing from the column linked lists. // // Let u[k,k] = v[p,q] be the pivot. In order to eliminate subdiagonal // elements u[i',k] = v[i,q], i' = k+1, k+2, ..., n, the routine applies // the following elementary gaussian transformations: // // (i-th row of V) := (i-th row of V) - f[i,p] * (p-th row of V), // // where f[i,p] = v[i,q] / v[p,q] is a gaussian multiplier. // // Additionally, in order to keep the main equality A = F*V, each time // when the routine applies the transformation to i-th row of the matrix // V, it also adds f[i,p] as a new element to the matrix F. // // IMPORTANT: On entry the working arrays flag and work should contain // zeros. This status is provided by the routine on exit. */ static void eliminate(LUX *lux, LUXWKA *wka, LUXELM *piv, int flag[], mpq_t work[]) { DMP *pool = lux->pool; LUXELM **F_row = lux->F_row; LUXELM **F_col = lux->F_col; mpq_t *V_piv = lux->V_piv; LUXELM **V_row = lux->V_row; LUXELM **V_col = lux->V_col; int *R_len = wka->R_len; int *R_head = wka->R_head; int *R_prev = wka->R_prev; int *R_next = wka->R_next; int *C_len = wka->C_len; int *C_head = wka->C_head; int *C_prev = wka->C_prev; int *C_next = wka->C_next; LUXELM *fip, *vij, *vpj, *viq, *next; mpq_t temp; int i, j, p, q; mpq_init(temp); /* determine row and column indices of the pivot v[p,q] */ xassert(piv != NULL); p = piv->i, q = piv->j; /* remove p-th (pivot) row from the active set; it will never return there */ if (R_prev[p] == 0) R_head[R_len[p]] = R_next[p]; else R_next[R_prev[p]] = R_next[p]; if (R_next[p] == 0) ; else R_prev[R_next[p]] = R_prev[p]; /* remove q-th (pivot) column from the active set; it will never return there */ if (C_prev[q] == 0) C_head[C_len[q]] = C_next[q]; else C_next[C_prev[q]] = C_next[q]; if (C_next[q] == 0) ; else C_prev[C_next[q]] = C_prev[q]; /* store the pivot value in a separate array */ mpq_set(V_piv[p], piv->val); /* remove the pivot from p-th row */ if (piv->r_prev == NULL) V_row[p] = piv->r_next; else piv->r_prev->r_next = piv->r_next; if (piv->r_next == NULL) ; else piv->r_next->r_prev = piv->r_prev; R_len[p]--; /* remove the pivot from q-th column */ if (piv->c_prev == NULL) V_col[q] = piv->c_next; else piv->c_prev->c_next = piv->c_next; if (piv->c_next == NULL) ; else piv->c_next->c_prev = piv->c_prev; C_len[q]--; /* free the space occupied by the pivot */ mpq_clear(piv->val); dmp_free_atom(pool, piv, sizeof(LUXELM)); /* walk through p-th (pivot) row, which already does not contain the pivot v[p,q], and do the following... */ for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next) { /* get column index of v[p,j] */ j = vpj->j; /* store v[p,j] in the working array */ flag[j] = 1; mpq_set(work[j], vpj->val); /* remove j-th column from the active set; it will return there later with a new length */ if (C_prev[j] == 0) C_head[C_len[j]] = C_next[j]; else C_next[C_prev[j]] = C_next[j]; if (C_next[j] == 0) ; else C_prev[C_next[j]] = C_prev[j]; /* v[p,j] leaves the active submatrix, so remove it from j-th column; however, v[p,j] is kept in p-th row */ if (vpj->c_prev == NULL) V_col[j] = vpj->c_next; else vpj->c_prev->c_next = vpj->c_next; if (vpj->c_next == NULL) ; else vpj->c_next->c_prev = vpj->c_prev; C_len[j]--; } /* now walk through q-th (pivot) column, which already does not contain the pivot v[p,q], and perform gaussian elimination */ while (V_col[q] != NULL) { /* element v[i,q] has to be eliminated */ viq = V_col[q]; /* get row index of v[i,q] */ i = viq->i; /* remove i-th row from the active set; later it will return there with a new length */ if (R_prev[i] == 0) R_head[R_len[i]] = R_next[i]; else R_next[R_prev[i]] = R_next[i]; if (R_next[i] == 0) ; else R_prev[R_next[i]] = R_prev[i]; /* compute gaussian multiplier f[i,p] = v[i,q] / v[p,q] and store it in the matrix F */ fip = dmp_get_atom(pool, sizeof(LUXELM)); fip->i = i, fip->j = p; mpq_init(fip->val); mpq_div(fip->val, viq->val, V_piv[p]); fip->r_prev = NULL; fip->r_next = F_row[i]; fip->c_prev = NULL; fip->c_next = F_col[p]; if (fip->r_next != NULL) fip->r_next->r_prev = fip; if (fip->c_next != NULL) fip->c_next->c_prev = fip; F_row[i] = F_col[p] = fip; /* v[i,q] has to be eliminated, so remove it from i-th row */ if (viq->r_prev == NULL) V_row[i] = viq->r_next; else viq->r_prev->r_next = viq->r_next; if (viq->r_next == NULL) ; else viq->r_next->r_prev = viq->r_prev; R_len[i]--; /* and also from q-th column */ V_col[q] = viq->c_next; C_len[q]--; /* free the space occupied by v[i,q] */ mpq_clear(viq->val); dmp_free_atom(pool, viq, sizeof(LUXELM)); /* perform gaussian transformation: (i-th row) := (i-th row) - f[i,p] * (p-th row) note that now p-th row, which is in the working array, does not contain the pivot v[p,q], and i-th row does not contain the element v[i,q] to be eliminated */ /* walk through i-th row and transform existing non-zero elements */ for (vij = V_row[i]; vij != NULL; vij = next) { next = vij->r_next; /* get column index of v[i,j] */ j = vij->j; /* v[i,j] := v[i,j] - f[i,p] * v[p,j] */ if (flag[j]) { /* v[p,j] != 0 */ flag[j] = 0; mpq_mul(temp, fip->val, work[j]); mpq_sub(vij->val, vij->val, temp); if (mpq_sgn(vij->val) == 0) { /* new v[i,j] is zero, so remove it from the active submatrix */ /* remove v[i,j] from i-th row */ if (vij->r_prev == NULL) V_row[i] = vij->r_next; else vij->r_prev->r_next = vij->r_next; if (vij->r_next == NULL) ; else vij->r_next->r_prev = vij->r_prev; R_len[i]--; /* remove v[i,j] from j-th column */ if (vij->c_prev == NULL) V_col[j] = vij->c_next; else vij->c_prev->c_next = vij->c_next; if (vij->c_next == NULL) ; else vij->c_next->c_prev = vij->c_prev; C_len[j]--; /* free the space occupied by v[i,j] */ mpq_clear(vij->val); dmp_free_atom(pool, vij, sizeof(LUXELM)); } } } /* now flag is the pattern of the set v[p,*] \ v[i,*] */ /* walk through p-th (pivot) row and create new elements in i-th row, which appear due to fill-in */ for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next) { j = vpj->j; if (flag[j]) { /* create new non-zero v[i,j] = 0 - f[i,p] * v[p,j] and add it to i-th row and j-th column */ vij = dmp_get_atom(pool, sizeof(LUXELM)); vij->i = i, vij->j = j; mpq_init(vij->val); mpq_mul(vij->val, fip->val, work[j]); mpq_neg(vij->val, vij->val); vij->r_prev = NULL; vij->r_next = V_row[i]; vij->c_prev = NULL; vij->c_next = V_col[j]; if (vij->r_next != NULL) vij->r_next->r_prev = vij; if (vij->c_next != NULL) vij->c_next->c_prev = vij; V_row[i] = V_col[j] = vij; R_len[i]++, C_len[j]++; } else { /* there is no fill-in, because v[i,j] already exists in i-th row; restore the flag, which was reset before */ flag[j] = 1; } } /* now i-th row has been completely transformed and can return to the active set with a new length */ R_prev[i] = 0; R_next[i] = R_head[R_len[i]]; if (R_next[i] != 0) R_prev[R_next[i]] = i; R_head[R_len[i]] = i; } /* at this point q-th (pivot) column must be empty */ xassert(C_len[q] == 0); /* walk through p-th (pivot) row again and do the following... */ for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next) { /* get column index of v[p,j] */ j = vpj->j; /* erase v[p,j] from the working array */ flag[j] = 0; mpq_set_si(work[j], 0, 1); /* now j-th column has been completely transformed, so it can return to the active list with a new length */ C_prev[j] = 0; C_next[j] = C_head[C_len[j]]; if (C_next[j] != 0) C_prev[C_next[j]] = j; C_head[C_len[j]] = j; } mpq_clear(temp); /* return to the factorizing routine */ return; } /*---------------------------------------------------------------------- // lux_decomp - compute LU-factorization. // // SYNOPSIS // // #include "glplux.h" // int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[], // mpq_t val[]), void *info); // // DESCRIPTION // // The routine lux_decomp computes LU-factorization of a given square // matrix A. // // The parameter lux specifies LU-factorization data structure built by // means of the routine lux_create. // // The formal routine col specifies the original matrix A. In order to // obtain j-th column of the matrix A the routine lux_decomp calls the // routine col with the parameter j (1 <= j <= n, where n is the order // of A). In response the routine col should store row indices and // numerical values of non-zero elements of j-th column of A to the // locations ind[1], ..., ind[len] and val[1], ..., val[len], resp., // where len is the number of non-zeros in j-th column, which should be // returned on exit. Neiter zero nor duplicate elements are allowed. // // The parameter info is a transit pointer passed to the formal routine // col; it can be used for various purposes. // // RETURNS // // The routine lux_decomp returns the singularity flag. Zero flag means // that the original matrix A is non-singular while non-zero flag means // that A is (exactly!) singular. // // Note that LU-factorization is valid in both cases, however, in case // of singularity some rows of the matrix V (including pivot elements) // will be empty. // // REPAIRING SINGULAR MATRIX // // If the routine lux_decomp returns non-zero flag, it provides all // necessary information that can be used for "repairing" the matrix A, // where "repairing" means replacing linearly dependent columns of the // matrix A by appropriate columns of the unity matrix. This feature is // needed when the routine lux_decomp is used for reinverting the basis // matrix within the simplex method procedure. // // On exit linearly dependent columns of the matrix U have the numbers // rank+1, rank+2, ..., n, where rank is the exact rank of the matrix A // stored by the routine to the member lux->rank. The correspondence // between columns of A and U is the same as between columns of V and U. // Thus, linearly dependent columns of the matrix A have the numbers // Q_col[rank+1], Q_col[rank+2], ..., Q_col[n], where Q_col is an array // representing the permutation matrix Q in column-like format. It is // understood that each j-th linearly dependent column of the matrix U // should be replaced by the unity vector, where all elements are zero // except the unity diagonal element u[j,j]. On the other hand j-th row // of the matrix U corresponds to the row of the matrix V (and therefore // of the matrix A) with the number P_row[j], where P_row is an array // representing the permutation matrix P in row-like format. Thus, each // j-th linearly dependent column of the matrix U should be replaced by // a column of the unity matrix with the number P_row[j]. // // The code that repairs the matrix A may look like follows: // // for (j = rank+1; j <= n; j++) // { replace column Q_col[j] of the matrix A by column P_row[j] of // the unity matrix; // } // // where rank, P_row, and Q_col are members of the structure LUX. */ int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[], mpq_t val[]), void *info) { int n = lux->n; LUXELM **V_row = lux->V_row; LUXELM **V_col = lux->V_col; int *P_row = lux->P_row; int *P_col = lux->P_col; int *Q_row = lux->Q_row; int *Q_col = lux->Q_col; LUXELM *piv, *vij; LUXWKA *wka; int i, j, k, p, q, t, *flag; mpq_t *work; /* allocate working area */ wka = xmalloc(sizeof(LUXWKA)); wka->R_len = xcalloc(1+n, sizeof(int)); wka->R_head = xcalloc(1+n, sizeof(int)); wka->R_prev = xcalloc(1+n, sizeof(int)); wka->R_next = xcalloc(1+n, sizeof(int)); wka->C_len = xcalloc(1+n, sizeof(int)); wka->C_head = xcalloc(1+n, sizeof(int)); wka->C_prev = xcalloc(1+n, sizeof(int)); wka->C_next = xcalloc(1+n, sizeof(int)); /* initialize LU-factorization data structures */ initialize(lux, col, info, wka); /* allocate working arrays */ flag = xcalloc(1+n, sizeof(int)); work = xcalloc(1+n, sizeof(mpq_t)); for (k = 1; k <= n; k++) { flag[k] = 0; mpq_init(work[k]); } /* main elimination loop */ for (k = 1; k <= n; k++) { /* choose a pivot element v[p,q] */ piv = find_pivot(lux, wka); if (piv == NULL) { /* no pivot can be chosen, because the active submatrix is empty */ break; } /* determine row and column indices of the pivot element */ p = piv->i, q = piv->j; /* let v[p,q] correspond to u[i',j']; permute k-th and i'-th rows and k-th and j'-th columns of the matrix U = P*V*Q to move the element u[i',j'] to the position u[k,k] */ i = P_col[p], j = Q_row[q]; xassert(k <= i && i <= n && k <= j && j <= n); /* permute k-th and i-th rows of the matrix U */ t = P_row[k]; P_row[i] = t, P_col[t] = i; P_row[k] = p, P_col[p] = k; /* permute k-th and j-th columns of the matrix U */ t = Q_col[k]; Q_col[j] = t, Q_row[t] = j; Q_col[k] = q, Q_row[q] = k; /* eliminate subdiagonal elements of k-th column of the matrix U = P*V*Q using the pivot element u[k,k] = v[p,q] */ eliminate(lux, wka, piv, flag, work); } /* determine the rank of A (and V) */ lux->rank = k - 1; /* free working arrays */ xfree(flag); for (k = 1; k <= n; k++) mpq_clear(work[k]); xfree(work); /* build column lists of the matrix V using its row lists */ for (j = 1; j <= n; j++) xassert(V_col[j] == NULL); for (i = 1; i <= n; i++) { for (vij = V_row[i]; vij != NULL; vij = vij->r_next) { j = vij->j; vij->c_prev = NULL; vij->c_next = V_col[j]; if (vij->c_next != NULL) vij->c_next->c_prev = vij; V_col[j] = vij; } } /* free working area */ xfree(wka->R_len); xfree(wka->R_head); xfree(wka->R_prev); xfree(wka->R_next); xfree(wka->C_len); xfree(wka->C_head); xfree(wka->C_prev); xfree(wka->C_next); xfree(wka); /* return to the calling program */ return (lux->rank < n); } /*---------------------------------------------------------------------- // lux_f_solve - solve system F*x = b or F'*x = b. // // SYNOPSIS // // #include "glplux.h" // void lux_f_solve(LUX *lux, int tr, mpq_t x[]); // // DESCRIPTION // // The routine lux_f_solve solves either the system F*x = b (if the // flag tr is zero) or the system F'*x = b (if the flag tr is non-zero), // where the matrix F is a component of LU-factorization specified by // the parameter lux, F' is a matrix transposed to F. // // On entry the array x should contain elements of the right-hand side // vector b in locations x[1], ..., x[n], where n is the order of the // matrix F. On exit this array will contain elements of the solution // vector x in the same locations. */ void lux_f_solve(LUX *lux, int tr, mpq_t x[]) { int n = lux->n; LUXELM **F_row = lux->F_row; LUXELM **F_col = lux->F_col; int *P_row = lux->P_row; LUXELM *fik, *fkj; int i, j, k; mpq_t temp; mpq_init(temp); if (!tr) { /* solve the system F*x = b */ for (j = 1; j <= n; j++) { k = P_row[j]; if (mpq_sgn(x[k]) != 0) { for (fik = F_col[k]; fik != NULL; fik = fik->c_next) { mpq_mul(temp, fik->val, x[k]); mpq_sub(x[fik->i], x[fik->i], temp); } } } } else { /* solve the system F'*x = b */ for (i = n; i >= 1; i--) { k = P_row[i]; if (mpq_sgn(x[k]) != 0) { for (fkj = F_row[k]; fkj != NULL; fkj = fkj->r_next) { mpq_mul(temp, fkj->val, x[k]); mpq_sub(x[fkj->j], x[fkj->j], temp); } } } } mpq_clear(temp); return; } /*---------------------------------------------------------------------- // lux_v_solve - solve system V*x = b or V'*x = b. // // SYNOPSIS // // #include "glplux.h" // void lux_v_solve(LUX *lux, int tr, double x[]); // // DESCRIPTION // // The routine lux_v_solve solves either the system V*x = b (if the // flag tr is zero) or the system V'*x = b (if the flag tr is non-zero), // where the matrix V is a component of LU-factorization specified by // the parameter lux, V' is a matrix transposed to V. // // On entry the array x should contain elements of the right-hand side // vector b in locations x[1], ..., x[n], where n is the order of the // matrix V. On exit this array will contain elements of the solution // vector x in the same locations. */ void lux_v_solve(LUX *lux, int tr, mpq_t x[]) { int n = lux->n; mpq_t *V_piv = lux->V_piv; LUXELM **V_row = lux->V_row; LUXELM **V_col = lux->V_col; int *P_row = lux->P_row; int *Q_col = lux->Q_col; LUXELM *vij; int i, j, k; mpq_t *b, temp; b = xcalloc(1+n, sizeof(mpq_t)); for (k = 1; k <= n; k++) mpq_init(b[k]), mpq_set(b[k], x[k]), mpq_set_si(x[k], 0, 1); mpq_init(temp); if (!tr) { /* solve the system V*x = b */ for (k = n; k >= 1; k--) { i = P_row[k], j = Q_col[k]; if (mpq_sgn(b[i]) != 0) { mpq_set(x[j], b[i]); mpq_div(x[j], x[j], V_piv[i]); for (vij = V_col[j]; vij != NULL; vij = vij->c_next) { mpq_mul(temp, vij->val, x[j]); mpq_sub(b[vij->i], b[vij->i], temp); } } } } else { /* solve the system V'*x = b */ for (k = 1; k <= n; k++) { i = P_row[k], j = Q_col[k]; if (mpq_sgn(b[j]) != 0) { mpq_set(x[i], b[j]); mpq_div(x[i], x[i], V_piv[i]); for (vij = V_row[i]; vij != NULL; vij = vij->r_next) { mpq_mul(temp, vij->val, x[i]); mpq_sub(b[vij->j], b[vij->j], temp); } } } } for (k = 1; k <= n; k++) mpq_clear(b[k]); mpq_clear(temp); xfree(b); return; } /*---------------------------------------------------------------------- // lux_solve - solve system A*x = b or A'*x = b. // // SYNOPSIS // // #include "glplux.h" // void lux_solve(LUX *lux, int tr, mpq_t x[]); // // DESCRIPTION // // The routine lux_solve solves either the system A*x = b (if the flag // tr is zero) or the system A'*x = b (if the flag tr is non-zero), // where the parameter lux specifies LU-factorization of the matrix A, // A' is a matrix transposed to A. // // On entry the array x should contain elements of the right-hand side // vector b in locations x[1], ..., x[n], where n is the order of the // matrix A. On exit this array will contain elements of the solution // vector x in the same locations. */ void lux_solve(LUX *lux, int tr, mpq_t x[]) { if (lux->rank < lux->n) xfault("lux_solve: LU-factorization has incomplete rank\n"); if (!tr) { /* A = F*V, therefore inv(A) = inv(V)*inv(F) */ lux_f_solve(lux, 0, x); lux_v_solve(lux, 0, x); } else { /* A' = V'*F', therefore inv(A') = inv(F')*inv(V') */ lux_v_solve(lux, 1, x); lux_f_solve(lux, 1, x); } return; } /*---------------------------------------------------------------------- // lux_delete - delete LU-factorization. // // SYNOPSIS // // #include "glplux.h" // void lux_delete(LUX *lux); // // DESCRIPTION // // The routine lux_delete deletes LU-factorization data structure, // which the parameter lux points to, freeing all the memory allocated // to this object. */ void lux_delete(LUX *lux) { int n = lux->n; LUXELM *fij, *vij; int i; for (i = 1; i <= n; i++) { for (fij = lux->F_row[i]; fij != NULL; fij = fij->r_next) mpq_clear(fij->val); mpq_clear(lux->V_piv[i]); for (vij = lux->V_row[i]; vij != NULL; vij = vij->r_next) mpq_clear(vij->val); } dmp_delete_pool(lux->pool); xfree(lux->F_row); xfree(lux->F_col); xfree(lux->V_piv); xfree(lux->V_row); xfree(lux->V_col); xfree(lux->P_row); xfree(lux->P_col); xfree(lux->Q_row); xfree(lux->Q_col); xfree(lux); return; } /* eof */ Rglpk/src/GLPK/glpapi02.c0000644000176000001440000003230512245352174014477 0ustar ripleyusers/* glpapi02.c (problem retrieving routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpapi.h" /*********************************************************************** * NAME * * glp_get_prob_name - retrieve problem name * * SYNOPSIS * * const char *glp_get_prob_name(glp_prob *lp); * * RETURNS * * The routine glp_get_prob_name returns a pointer to an internal * buffer, which contains symbolic name of the problem. However, if the * problem has no assigned name, the routine returns NULL. */ const char *glp_get_prob_name(glp_prob *lp) { char *name; name = lp->name; return name; } /*********************************************************************** * NAME * * glp_get_obj_name - retrieve objective function name * * SYNOPSIS * * const char *glp_get_obj_name(glp_prob *lp); * * RETURNS * * The routine glp_get_obj_name returns a pointer to an internal * buffer, which contains a symbolic name of the objective function. * However, if the objective function has no assigned name, the routine * returns NULL. */ const char *glp_get_obj_name(glp_prob *lp) { char *name; name = lp->obj; return name; } /*********************************************************************** * NAME * * glp_get_obj_dir - retrieve optimization direction flag * * SYNOPSIS * * int glp_get_obj_dir(glp_prob *lp); * * RETURNS * * The routine glp_get_obj_dir returns the optimization direction flag * (i.e. "sense" of the objective function): * * GLP_MIN - minimization; * GLP_MAX - maximization. */ int glp_get_obj_dir(glp_prob *lp) { int dir = lp->dir; return dir; } /*********************************************************************** * NAME * * glp_get_num_rows - retrieve number of rows * * SYNOPSIS * * int glp_get_num_rows(glp_prob *lp); * * RETURNS * * The routine glp_get_num_rows returns the current number of rows in * the specified problem object. */ int glp_get_num_rows(glp_prob *lp) { int m = lp->m; return m; } /*********************************************************************** * NAME * * glp_get_num_cols - retrieve number of columns * * SYNOPSIS * * int glp_get_num_cols(glp_prob *lp); * * RETURNS * * The routine glp_get_num_cols returns the current number of columns * in the specified problem object. */ int glp_get_num_cols(glp_prob *lp) { int n = lp->n; return n; } /*********************************************************************** * NAME * * glp_get_row_name - retrieve row name * * SYNOPSIS * * const char *glp_get_row_name(glp_prob *lp, int i); * * RETURNS * * The routine glp_get_row_name returns a pointer to an internal * buffer, which contains symbolic name of i-th row. However, if i-th * row has no assigned name, the routine returns NULL. */ const char *glp_get_row_name(glp_prob *lp, int i) { char *name; if (!(1 <= i && i <= lp->m)) xerror("glp_get_row_name: i = %d; row number out of range\n", i); name = lp->row[i]->name; return name; } /*********************************************************************** * NAME * * glp_get_col_name - retrieve column name * * SYNOPSIS * * const char *glp_get_col_name(glp_prob *lp, int j); * * RETURNS * * The routine glp_get_col_name returns a pointer to an internal * buffer, which contains symbolic name of j-th column. However, if j-th * column has no assigned name, the routine returns NULL. */ const char *glp_get_col_name(glp_prob *lp, int j) { char *name; if (!(1 <= j && j <= lp->n)) xerror("glp_get_col_name: j = %d; column number out of range\n" , j); name = lp->col[j]->name; return name; } /*********************************************************************** * NAME * * glp_get_row_type - retrieve row type * * SYNOPSIS * * int glp_get_row_type(glp_prob *lp, int i); * * RETURNS * * The routine glp_get_row_type returns the type of i-th row, i.e. the * type of corresponding auxiliary variable, as follows: * * GLP_FR - free (unbounded) variable; * GLP_LO - variable with lower bound; * GLP_UP - variable with upper bound; * GLP_DB - double-bounded variable; * GLP_FX - fixed variable. */ int glp_get_row_type(glp_prob *lp, int i) { if (!(1 <= i && i <= lp->m)) xerror("glp_get_row_type: i = %d; row number out of range\n", i); return lp->row[i]->type; } /*********************************************************************** * NAME * * glp_get_row_lb - retrieve row lower bound * * SYNOPSIS * * double glp_get_row_lb(glp_prob *lp, int i); * * RETURNS * * The routine glp_get_row_lb returns the lower bound of i-th row, i.e. * the lower bound of corresponding auxiliary variable. However, if the * row has no lower bound, the routine returns -DBL_MAX. */ double glp_get_row_lb(glp_prob *lp, int i) { double lb; if (!(1 <= i && i <= lp->m)) xerror("glp_get_row_lb: i = %d; row number out of range\n", i); switch (lp->row[i]->type) { case GLP_FR: case GLP_UP: lb = -DBL_MAX; break; case GLP_LO: case GLP_DB: case GLP_FX: lb = lp->row[i]->lb; break; default: xassert(lp != lp); } return lb; } /*********************************************************************** * NAME * * glp_get_row_ub - retrieve row upper bound * * SYNOPSIS * * double glp_get_row_ub(glp_prob *lp, int i); * * RETURNS * * The routine glp_get_row_ub returns the upper bound of i-th row, i.e. * the upper bound of corresponding auxiliary variable. However, if the * row has no upper bound, the routine returns +DBL_MAX. */ double glp_get_row_ub(glp_prob *lp, int i) { double ub; if (!(1 <= i && i <= lp->m)) xerror("glp_get_row_ub: i = %d; row number out of range\n", i); switch (lp->row[i]->type) { case GLP_FR: case GLP_LO: ub = +DBL_MAX; break; case GLP_UP: case GLP_DB: case GLP_FX: ub = lp->row[i]->ub; break; default: xassert(lp != lp); } return ub; } /*********************************************************************** * NAME * * glp_get_col_type - retrieve column type * * SYNOPSIS * * int glp_get_col_type(glp_prob *lp, int j); * * RETURNS * * The routine glp_get_col_type returns the type of j-th column, i.e. * the type of corresponding structural variable, as follows: * * GLP_FR - free (unbounded) variable; * GLP_LO - variable with lower bound; * GLP_UP - variable with upper bound; * GLP_DB - double-bounded variable; * GLP_FX - fixed variable. */ int glp_get_col_type(glp_prob *lp, int j) { if (!(1 <= j && j <= lp->n)) xerror("glp_get_col_type: j = %d; column number out of range\n" , j); return lp->col[j]->type; } /*********************************************************************** * NAME * * glp_get_col_lb - retrieve column lower bound * * SYNOPSIS * * double glp_get_col_lb(glp_prob *lp, int j); * * RETURNS * * The routine glp_get_col_lb returns the lower bound of j-th column, * i.e. the lower bound of corresponding structural variable. However, * if the column has no lower bound, the routine returns -DBL_MAX. */ double glp_get_col_lb(glp_prob *lp, int j) { double lb; if (!(1 <= j && j <= lp->n)) xerror("glp_get_col_lb: j = %d; column number out of range\n", j); switch (lp->col[j]->type) { case GLP_FR: case GLP_UP: lb = -DBL_MAX; break; case GLP_LO: case GLP_DB: case GLP_FX: lb = lp->col[j]->lb; break; default: xassert(lp != lp); } return lb; } /*********************************************************************** * NAME * * glp_get_col_ub - retrieve column upper bound * * SYNOPSIS * * double glp_get_col_ub(glp_prob *lp, int j); * * RETURNS * * The routine glp_get_col_ub returns the upper bound of j-th column, * i.e. the upper bound of corresponding structural variable. However, * if the column has no upper bound, the routine returns +DBL_MAX. */ double glp_get_col_ub(glp_prob *lp, int j) { double ub; if (!(1 <= j && j <= lp->n)) xerror("glp_get_col_ub: j = %d; column number out of range\n", j); switch (lp->col[j]->type) { case GLP_FR: case GLP_LO: ub = +DBL_MAX; break; case GLP_UP: case GLP_DB: case GLP_FX: ub = lp->col[j]->ub; break; default: xassert(lp != lp); } return ub; } /*********************************************************************** * NAME * * glp_get_obj_coef - retrieve obj. coefficient or constant term * * SYNOPSIS * * double glp_get_obj_coef(glp_prob *lp, int j); * * RETURNS * * The routine glp_get_obj_coef returns the objective coefficient at * j-th structural variable (column) of the specified problem object. * * If the parameter j is zero, the routine returns the constant term * ("shift") of the objective function. */ double glp_get_obj_coef(glp_prob *lp, int j) { if (!(0 <= j && j <= lp->n)) xerror("glp_get_obj_coef: j = %d; column number out of range\n" , j); return j == 0 ? lp->c0 : lp->col[j]->coef; } /*********************************************************************** * NAME * * glp_get_num_nz - retrieve number of constraint coefficients * * SYNOPSIS * * int glp_get_num_nz(glp_prob *lp); * * RETURNS * * The routine glp_get_num_nz returns the number of (non-zero) elements * in the constraint matrix of the specified problem object. */ int glp_get_num_nz(glp_prob *lp) { int nnz = lp->nnz; return nnz; } /*********************************************************************** * NAME * * glp_get_mat_row - retrieve row of the constraint matrix * * SYNOPSIS * * int glp_get_mat_row(glp_prob *lp, int i, int ind[], double val[]); * * DESCRIPTION * * The routine glp_get_mat_row scans (non-zero) elements of i-th row * of the constraint matrix of the specified problem object and stores * their column indices and numeric values to locations ind[1], ..., * ind[len] and val[1], ..., val[len], respectively, where 0 <= len <= n * is the number of elements in i-th row, n is the number of columns. * * The parameter ind and/or val can be specified as NULL, in which case * corresponding information is not stored. * * RETURNS * * The routine glp_get_mat_row returns the length len, i.e. the number * of (non-zero) elements in i-th row. */ int glp_get_mat_row(glp_prob *lp, int i, int ind[], double val[]) { GLPAIJ *aij; int len; if (!(1 <= i && i <= lp->m)) xerror("glp_get_mat_row: i = %d; row number out of range\n", i); len = 0; for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next) { len++; if (ind != NULL) ind[len] = aij->col->j; if (val != NULL) val[len] = aij->val; } xassert(len <= lp->n); return len; } /*********************************************************************** * NAME * * glp_get_mat_col - retrieve column of the constraint matrix * * SYNOPSIS * * int glp_get_mat_col(glp_prob *lp, int j, int ind[], double val[]); * * DESCRIPTION * * The routine glp_get_mat_col scans (non-zero) elements of j-th column * of the constraint matrix of the specified problem object and stores * their row indices and numeric values to locations ind[1], ..., * ind[len] and val[1], ..., val[len], respectively, where 0 <= len <= m * is the number of elements in j-th column, m is the number of rows. * * The parameter ind or/and val can be specified as NULL, in which case * corresponding information is not stored. * * RETURNS * * The routine glp_get_mat_col returns the length len, i.e. the number * of (non-zero) elements in j-th column. */ int glp_get_mat_col(glp_prob *lp, int j, int ind[], double val[]) { GLPAIJ *aij; int len; if (!(1 <= j && j <= lp->n)) xerror("glp_get_mat_col: j = %d; column number out of range\n", j); len = 0; for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next) { len++; if (ind != NULL) ind[len] = aij->row->i; if (val != NULL) val[len] = aij->val; } xassert(len <= lp->m); return len; } /* eof */ Rglpk/src/GLPK/glpspx02.c0000644000176000001440000031021412245352174014536 0ustar ripleyusers/* glpspx02.c (dual simplex method) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpspx.h" #define GLP_DEBUG 1 #if 0 #define GLP_LONG_STEP 1 #endif struct csa { /* common storage area */ /*--------------------------------------------------------------*/ /* LP data */ int m; /* number of rows (auxiliary variables), m > 0 */ int n; /* number of columns (structural variables), n > 0 */ char *type; /* char type[1+m+n]; */ /* type[0] is not used; type[k], 1 <= k <= m+n, is the type of variable x[k]: GLP_FR - free variable GLP_LO - variable with lower bound GLP_UP - variable with upper bound GLP_DB - double-bounded variable GLP_FX - fixed variable */ double *lb; /* double lb[1+m+n]; */ /* lb[0] is not used; lb[k], 1 <= k <= m+n, is an lower bound of variable x[k]; if x[k] has no lower bound, lb[k] is zero */ double *ub; /* double ub[1+m+n]; */ /* ub[0] is not used; ub[k], 1 <= k <= m+n, is an upper bound of variable x[k]; if x[k] has no upper bound, ub[k] is zero; if x[k] is of fixed type, ub[k] is the same as lb[k] */ double *coef; /* double coef[1+m+n]; */ /* coef[0] is not used; coef[k], 1 <= k <= m+n, is an objective coefficient at variable x[k] */ /*--------------------------------------------------------------*/ /* original bounds of variables */ char *orig_type; /* char orig_type[1+m+n]; */ double *orig_lb; /* double orig_lb[1+m+n]; */ double *orig_ub; /* double orig_ub[1+m+n]; */ /*--------------------------------------------------------------*/ /* original objective function */ double *obj; /* double obj[1+n]; */ /* obj[0] is a constant term of the original objective function; obj[j], 1 <= j <= n, is an original objective coefficient at structural variable x[m+j] */ double zeta; /* factor used to scale original objective coefficients; its sign defines original optimization direction: zeta > 0 means minimization, zeta < 0 means maximization */ /*--------------------------------------------------------------*/ /* constraint matrix A; it has m rows and n columns and is stored by columns */ int *A_ptr; /* int A_ptr[1+n+1]; */ /* A_ptr[0] is not used; A_ptr[j], 1 <= j <= n, is starting position of j-th column in arrays A_ind and A_val; note that A_ptr[1] is always 1; A_ptr[n+1] indicates the position after the last element in arrays A_ind and A_val */ int *A_ind; /* int A_ind[A_ptr[n+1]]; */ /* row indices */ double *A_val; /* double A_val[A_ptr[n+1]]; */ /* non-zero element values */ #if 1 /* 06/IV-2009 */ /* constraint matrix A stored by rows */ int *AT_ptr; /* int AT_ptr[1+m+1]; */ /* AT_ptr[0] is not used; AT_ptr[i], 1 <= i <= m, is starting position of i-th row in arrays AT_ind and AT_val; note that AT_ptr[1] is always 1; AT_ptr[m+1] indicates the position after the last element in arrays AT_ind and AT_val */ int *AT_ind; /* int AT_ind[AT_ptr[m+1]]; */ /* column indices */ double *AT_val; /* double AT_val[AT_ptr[m+1]]; */ /* non-zero element values */ #endif /*--------------------------------------------------------------*/ /* basis header */ int *head; /* int head[1+m+n]; */ /* head[0] is not used; head[i], 1 <= i <= m, is the ordinal number of basic variable xB[i]; head[i] = k means that xB[i] = x[k] and i-th column of matrix B is k-th column of matrix (I|-A); head[m+j], 1 <= j <= n, is the ordinal number of non-basic variable xN[j]; head[m+j] = k means that xN[j] = x[k] and j-th column of matrix N is k-th column of matrix (I|-A) */ #if 1 /* 06/IV-2009 */ int *bind; /* int bind[1+m+n]; */ /* bind[0] is not used; bind[k], 1 <= k <= m+n, is the position of k-th column of the matrix (I|-A) in the matrix (B|N); that is, bind[k] = k' means that head[k'] = k */ #endif char *stat; /* char stat[1+n]; */ /* stat[0] is not used; stat[j], 1 <= j <= n, is the status of non-basic variable xN[j], which defines its active bound: GLP_NL - lower bound is active GLP_NU - upper bound is active GLP_NF - free variable GLP_NS - fixed variable */ /*--------------------------------------------------------------*/ /* matrix B is the basis matrix; it is composed from columns of the augmented constraint matrix (I|-A) corresponding to basic variables and stored in a factorized (invertable) form */ int valid; /* factorization is valid only if this flag is set */ BFD *bfd; /* BFD bfd[1:m,1:m]; */ /* factorized (invertable) form of the basis matrix */ #if 0 /* 06/IV-2009 */ /*--------------------------------------------------------------*/ /* matrix N is a matrix composed from columns of the augmented constraint matrix (I|-A) corresponding to non-basic variables except fixed ones; it is stored by rows and changes every time the basis changes */ int *N_ptr; /* int N_ptr[1+m+1]; */ /* N_ptr[0] is not used; N_ptr[i], 1 <= i <= m, is starting position of i-th row in arrays N_ind and N_val; note that N_ptr[1] is always 1; N_ptr[m+1] indicates the position after the last element in arrays N_ind and N_val */ int *N_len; /* int N_len[1+m]; */ /* N_len[0] is not used; N_len[i], 1 <= i <= m, is length of i-th row (0 to n) */ int *N_ind; /* int N_ind[N_ptr[m+1]]; */ /* column indices */ double *N_val; /* double N_val[N_ptr[m+1]]; */ /* non-zero element values */ #endif /*--------------------------------------------------------------*/ /* working parameters */ int phase; /* search phase: 0 - not determined yet 1 - search for dual feasible solution 2 - search for optimal solution */ #if 0 /* 10/VI-2013 */ glp_long tm_beg; #else double tm_beg; #endif /* time value at the beginning of the search */ int it_beg; /* simplex iteration count at the beginning of the search */ int it_cnt; /* simplex iteration count; it increases by one every time the basis changes */ int it_dpy; /* simplex iteration count at the most recent display output */ /*--------------------------------------------------------------*/ /* basic solution components */ double *bbar; /* double bbar[1+m]; */ /* bbar[0] is not used on phase I; on phase II it is the current value of the original objective function; bbar[i], 1 <= i <= m, is primal value of basic variable xB[i] (if xB[i] is free, its primal value is not updated) */ double *cbar; /* double cbar[1+n]; */ /* cbar[0] is not used; cbar[j], 1 <= j <= n, is reduced cost of non-basic variable xN[j] (if xN[j] is fixed, its reduced cost is not updated) */ /*--------------------------------------------------------------*/ /* the following pricing technique options may be used: GLP_PT_STD - standard ("textbook") pricing; GLP_PT_PSE - projected steepest edge; GLP_PT_DVX - Devex pricing (not implemented yet); in case of GLP_PT_STD the reference space is not used, and all steepest edge coefficients are set to 1 */ int refct; /* this count is set to an initial value when the reference space is defined and decreases by one every time the basis changes; once this count reaches zero, the reference space is redefined again */ char *refsp; /* char refsp[1+m+n]; */ /* refsp[0] is not used; refsp[k], 1 <= k <= m+n, is the flag which means that variable x[k] belongs to the current reference space */ double *gamma; /* double gamma[1+m]; */ /* gamma[0] is not used; gamma[i], 1 <= i <= n, is the steepest edge coefficient for basic variable xB[i]; if xB[i] is free, gamma[i] is not used and just set to 1 */ /*--------------------------------------------------------------*/ /* basic variable xB[p] chosen to leave the basis */ int p; /* index of the basic variable xB[p] chosen, 1 <= p <= m; if the set of eligible basic variables is empty (i.e. if the current basic solution is primal feasible within a tolerance) and thus no variable has been chosen, p is set to 0 */ double delta; /* change of xB[p] in the adjacent basis; delta > 0 means that xB[p] violates its lower bound and will increase to achieve it in the adjacent basis; delta < 0 means that xB[p] violates its upper bound and will decrease to achieve it in the adjacent basis */ /*--------------------------------------------------------------*/ /* pivot row of the simplex table corresponding to basic variable xB[p] chosen is the following vector: T' * e[p] = - N' * inv(B') * e[p] = - N' * rho, where B' is a matrix transposed to the current basis matrix, N' is a matrix, whose rows are columns of the matrix (I|-A) corresponding to non-basic non-fixed variables */ int trow_nnz; /* number of non-zero components, 0 <= nnz <= n */ int *trow_ind; /* int trow_ind[1+n]; */ /* trow_ind[0] is not used; trow_ind[t], 1 <= t <= nnz, is an index of non-zero component, i.e. trow_ind[t] = j means that trow_vec[j] != 0 */ double *trow_vec; /* int trow_vec[1+n]; */ /* trow_vec[0] is not used; trow_vec[j], 1 <= j <= n, is a numeric value of j-th component of the row */ double trow_max; /* infinity (maximum) norm of the row (max |trow_vec[j]|) */ int trow_num; /* number of significant non-zero components, which means that: |trow_vec[j]| >= eps for j in trow_ind[1,...,num], |tcol_vec[j]| < eps for j in trow_ind[num+1,...,nnz], where eps is a pivot tolerance */ /*--------------------------------------------------------------*/ #ifdef GLP_LONG_STEP /* 07/IV-2009 */ int nbps; /* number of breakpoints, 0 <= nbps <= n */ struct bkpt { int j; /* index of non-basic variable xN[j], 1 <= j <= n */ double t; /* value of dual ray parameter at breakpoint, t >= 0 */ double dz; /* dz = zeta(t = t[k]) - zeta(t = 0) */ } *bkpt; /* struct bkpt bkpt[1+n]; */ /* bkpt[0] is not used; bkpt[k], 1 <= k <= nbps, is k-th breakpoint of the dual objective */ #endif /*--------------------------------------------------------------*/ /* non-basic variable xN[q] chosen to enter the basis */ int q; /* index of the non-basic variable xN[q] chosen, 1 <= q <= n; if no variable has been chosen, q is set to 0 */ double new_dq; /* reduced cost of xN[q] in the adjacent basis (it is the change of lambdaB[p]) */ /*--------------------------------------------------------------*/ /* pivot column of the simplex table corresponding to non-basic variable xN[q] chosen is the following vector: T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q], where B is the current basis matrix, N[q] is a column of the matrix (I|-A) corresponding to xN[q] */ int tcol_nnz; /* number of non-zero components, 0 <= nnz <= m */ int *tcol_ind; /* int tcol_ind[1+m]; */ /* tcol_ind[0] is not used; tcol_ind[t], 1 <= t <= nnz, is an index of non-zero component, i.e. tcol_ind[t] = i means that tcol_vec[i] != 0 */ double *tcol_vec; /* double tcol_vec[1+m]; */ /* tcol_vec[0] is not used; tcol_vec[i], 1 <= i <= m, is a numeric value of i-th component of the column */ /*--------------------------------------------------------------*/ /* working arrays */ double *work1; /* double work1[1+m]; */ double *work2; /* double work2[1+m]; */ double *work3; /* double work3[1+m]; */ double *work4; /* double work4[1+m]; */ }; static const double kappa = 0.10; /*********************************************************************** * alloc_csa - allocate common storage area * * This routine allocates all arrays in the common storage area (CSA) * and returns a pointer to the CSA. */ static struct csa *alloc_csa(glp_prob *lp) { struct csa *csa; int m = lp->m; int n = lp->n; int nnz = lp->nnz; csa = xmalloc(sizeof(struct csa)); xassert(m > 0 && n > 0); csa->m = m; csa->n = n; csa->type = xcalloc(1+m+n, sizeof(char)); csa->lb = xcalloc(1+m+n, sizeof(double)); csa->ub = xcalloc(1+m+n, sizeof(double)); csa->coef = xcalloc(1+m+n, sizeof(double)); csa->orig_type = xcalloc(1+m+n, sizeof(char)); csa->orig_lb = xcalloc(1+m+n, sizeof(double)); csa->orig_ub = xcalloc(1+m+n, sizeof(double)); csa->obj = xcalloc(1+n, sizeof(double)); csa->A_ptr = xcalloc(1+n+1, sizeof(int)); csa->A_ind = xcalloc(1+nnz, sizeof(int)); csa->A_val = xcalloc(1+nnz, sizeof(double)); #if 1 /* 06/IV-2009 */ csa->AT_ptr = xcalloc(1+m+1, sizeof(int)); csa->AT_ind = xcalloc(1+nnz, sizeof(int)); csa->AT_val = xcalloc(1+nnz, sizeof(double)); #endif csa->head = xcalloc(1+m+n, sizeof(int)); #if 1 /* 06/IV-2009 */ csa->bind = xcalloc(1+m+n, sizeof(int)); #endif csa->stat = xcalloc(1+n, sizeof(char)); #if 0 /* 06/IV-2009 */ csa->N_ptr = xcalloc(1+m+1, sizeof(int)); csa->N_len = xcalloc(1+m, sizeof(int)); csa->N_ind = NULL; /* will be allocated later */ csa->N_val = NULL; /* will be allocated later */ #endif csa->bbar = xcalloc(1+m, sizeof(double)); csa->cbar = xcalloc(1+n, sizeof(double)); csa->refsp = xcalloc(1+m+n, sizeof(char)); csa->gamma = xcalloc(1+m, sizeof(double)); csa->trow_ind = xcalloc(1+n, sizeof(int)); csa->trow_vec = xcalloc(1+n, sizeof(double)); #ifdef GLP_LONG_STEP /* 07/IV-2009 */ csa->bkpt = xcalloc(1+n, sizeof(struct bkpt)); #endif csa->tcol_ind = xcalloc(1+m, sizeof(int)); csa->tcol_vec = xcalloc(1+m, sizeof(double)); csa->work1 = xcalloc(1+m, sizeof(double)); csa->work2 = xcalloc(1+m, sizeof(double)); csa->work3 = xcalloc(1+m, sizeof(double)); csa->work4 = xcalloc(1+m, sizeof(double)); return csa; } /*********************************************************************** * init_csa - initialize common storage area * * This routine initializes all data structures in the common storage * area (CSA). */ static void init_csa(struct csa *csa, glp_prob *lp) { int m = csa->m; int n = csa->n; char *type = csa->type; double *lb = csa->lb; double *ub = csa->ub; double *coef = csa->coef; char *orig_type = csa->orig_type; double *orig_lb = csa->orig_lb; double *orig_ub = csa->orig_ub; double *obj = csa->obj; int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; #if 1 /* 06/IV-2009 */ int *AT_ptr = csa->AT_ptr; int *AT_ind = csa->AT_ind; double *AT_val = csa->AT_val; #endif int *head = csa->head; #if 1 /* 06/IV-2009 */ int *bind = csa->bind; #endif char *stat = csa->stat; char *refsp = csa->refsp; double *gamma = csa->gamma; int i, j, k, loc; double cmax; /* auxiliary variables */ for (i = 1; i <= m; i++) { GLPROW *row = lp->row[i]; type[i] = (char)row->type; lb[i] = row->lb * row->rii; ub[i] = row->ub * row->rii; coef[i] = 0.0; } /* structural variables */ for (j = 1; j <= n; j++) { GLPCOL *col = lp->col[j]; type[m+j] = (char)col->type; lb[m+j] = col->lb / col->sjj; ub[m+j] = col->ub / col->sjj; coef[m+j] = col->coef * col->sjj; } /* original bounds of variables */ memcpy(&orig_type[1], &type[1], (m+n) * sizeof(char)); memcpy(&orig_lb[1], &lb[1], (m+n) * sizeof(double)); memcpy(&orig_ub[1], &ub[1], (m+n) * sizeof(double)); /* original objective function */ obj[0] = lp->c0; memcpy(&obj[1], &coef[m+1], n * sizeof(double)); /* factor used to scale original objective coefficients */ cmax = 0.0; for (j = 1; j <= n; j++) if (cmax < fabs(obj[j])) cmax = fabs(obj[j]); if (cmax == 0.0) cmax = 1.0; switch (lp->dir) { case GLP_MIN: csa->zeta = + 1.0 / cmax; break; case GLP_MAX: csa->zeta = - 1.0 / cmax; break; default: xassert(lp != lp); } #if 1 if (fabs(csa->zeta) < 1.0) csa->zeta *= 1000.0; #endif /* scale working objective coefficients */ for (j = 1; j <= n; j++) coef[m+j] *= csa->zeta; /* matrix A (by columns) */ loc = 1; for (j = 1; j <= n; j++) { GLPAIJ *aij; A_ptr[j] = loc; for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next) { A_ind[loc] = aij->row->i; A_val[loc] = aij->row->rii * aij->val * aij->col->sjj; loc++; } } A_ptr[n+1] = loc; xassert(loc-1 == lp->nnz); #if 1 /* 06/IV-2009 */ /* matrix A (by rows) */ loc = 1; for (i = 1; i <= m; i++) { GLPAIJ *aij; AT_ptr[i] = loc; for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next) { AT_ind[loc] = aij->col->j; AT_val[loc] = aij->row->rii * aij->val * aij->col->sjj; loc++; } } AT_ptr[m+1] = loc; xassert(loc-1 == lp->nnz); #endif /* basis header */ xassert(lp->valid); memcpy(&head[1], &lp->head[1], m * sizeof(int)); k = 0; for (i = 1; i <= m; i++) { GLPROW *row = lp->row[i]; if (row->stat != GLP_BS) { k++; xassert(k <= n); head[m+k] = i; stat[k] = (char)row->stat; } } for (j = 1; j <= n; j++) { GLPCOL *col = lp->col[j]; if (col->stat != GLP_BS) { k++; xassert(k <= n); head[m+k] = m + j; stat[k] = (char)col->stat; } } xassert(k == n); #if 1 /* 06/IV-2009 */ for (k = 1; k <= m+n; k++) bind[head[k]] = k; #endif /* factorization of matrix B */ csa->valid = 1, lp->valid = 0; csa->bfd = lp->bfd, lp->bfd = NULL; #if 0 /* 06/IV-2009 */ /* matrix N (by rows) */ alloc_N(csa); build_N(csa); #endif /* working parameters */ csa->phase = 0; csa->tm_beg = xtime(); csa->it_beg = csa->it_cnt = lp->it_cnt; csa->it_dpy = -1; /* reference space and steepest edge coefficients */ csa->refct = 0; memset(&refsp[1], 0, (m+n) * sizeof(char)); for (i = 1; i <= m; i++) gamma[i] = 1.0; return; } #if 1 /* copied from primal */ /*********************************************************************** * invert_B - compute factorization of the basis matrix * * This routine computes factorization of the current basis matrix B. * * If the operation is successful, the routine returns zero, otherwise * non-zero. */ static int inv_col(void *info, int i, int ind[], double val[]) { /* this auxiliary routine returns row indices and numeric values of non-zero elements of i-th column of the basis matrix */ struct csa *csa = info; int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int *head = csa->head; int k, len, ptr, t; #ifdef GLP_DEBUG xassert(1 <= i && i <= m); #endif k = head[i]; /* B[i] is k-th column of (I|-A) */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (k <= m) { /* B[i] is k-th column of submatrix I */ len = 1; ind[1] = k; val[1] = 1.0; } else { /* B[i] is (k-m)-th column of submatrix (-A) */ ptr = A_ptr[k-m]; len = A_ptr[k-m+1] - ptr; memcpy(&ind[1], &A_ind[ptr], len * sizeof(int)); memcpy(&val[1], &A_val[ptr], len * sizeof(double)); for (t = 1; t <= len; t++) val[t] = - val[t]; } return len; } static int invert_B(struct csa *csa) { int ret; ret = bfd_factorize(csa->bfd, csa->m, NULL, inv_col, csa); csa->valid = (ret == 0); return ret; } #endif #if 1 /* copied from primal */ /*********************************************************************** * update_B - update factorization of the basis matrix * * This routine replaces i-th column of the basis matrix B by k-th * column of the augmented constraint matrix (I|-A) and then updates * the factorization of B. * * If the factorization has been successfully updated, the routine * returns zero, otherwise non-zero. */ static int update_B(struct csa *csa, int i, int k) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif int ret; #ifdef GLP_DEBUG xassert(1 <= i && i <= m); xassert(1 <= k && k <= m+n); #endif if (k <= m) { /* new i-th column of B is k-th column of I */ int ind[1+1]; double val[1+1]; ind[1] = k; val[1] = 1.0; xassert(csa->valid); ret = bfd_update_it(csa->bfd, i, 0, 1, ind, val); } else { /* new i-th column of B is (k-m)-th column of (-A) */ int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; double *val = csa->work1; int beg, end, ptr, len; beg = A_ptr[k-m]; end = A_ptr[k-m+1]; len = 0; for (ptr = beg; ptr < end; ptr++) val[++len] = - A_val[ptr]; xassert(csa->valid); ret = bfd_update_it(csa->bfd, i, 0, len, &A_ind[beg-1], val); } csa->valid = (ret == 0); return ret; } #endif #if 1 /* copied from primal */ /*********************************************************************** * error_ftran - compute residual vector r = h - B * x * * This routine computes the residual vector r = h - B * x, where B is * the current basis matrix, h is the vector of right-hand sides, x is * the solution vector. */ static void error_ftran(struct csa *csa, double h[], double x[], double r[]) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int *head = csa->head; int i, k, beg, end, ptr; double temp; /* compute the residual vector: r = h - B * x = h - B[1] * x[1] - ... - B[m] * x[m], where B[1], ..., B[m] are columns of matrix B */ memcpy(&r[1], &h[1], m * sizeof(double)); for (i = 1; i <= m; i++) { temp = x[i]; if (temp == 0.0) continue; k = head[i]; /* B[i] is k-th column of (I|-A) */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (k <= m) { /* B[i] is k-th column of submatrix I */ r[k] -= temp; } else { /* B[i] is (k-m)-th column of submatrix (-A) */ beg = A_ptr[k-m]; end = A_ptr[k-m+1]; for (ptr = beg; ptr < end; ptr++) r[A_ind[ptr]] += A_val[ptr] * temp; } } return; } #endif #if 1 /* copied from primal */ /*********************************************************************** * refine_ftran - refine solution of B * x = h * * This routine performs one iteration to refine the solution of * the system B * x = h, where B is the current basis matrix, h is the * vector of right-hand sides, x is the solution vector. */ static void refine_ftran(struct csa *csa, double h[], double x[]) { int m = csa->m; double *r = csa->work1; double *d = csa->work1; int i; /* compute the residual vector r = h - B * x */ error_ftran(csa, h, x, r); /* compute the correction vector d = inv(B) * r */ xassert(csa->valid); bfd_ftran(csa->bfd, d); /* refine the solution vector (new x) = (old x) + d */ for (i = 1; i <= m; i++) x[i] += d[i]; return; } #endif #if 1 /* copied from primal */ /*********************************************************************** * error_btran - compute residual vector r = h - B'* x * * This routine computes the residual vector r = h - B'* x, where B' * is a matrix transposed to the current basis matrix, h is the vector * of right-hand sides, x is the solution vector. */ static void error_btran(struct csa *csa, double h[], double x[], double r[]) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int *head = csa->head; int i, k, beg, end, ptr; double temp; /* compute the residual vector r = b - B'* x */ for (i = 1; i <= m; i++) { /* r[i] := b[i] - (i-th column of B)'* x */ k = head[i]; /* B[i] is k-th column of (I|-A) */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif temp = h[i]; if (k <= m) { /* B[i] is k-th column of submatrix I */ temp -= x[k]; } else { /* B[i] is (k-m)-th column of submatrix (-A) */ beg = A_ptr[k-m]; end = A_ptr[k-m+1]; for (ptr = beg; ptr < end; ptr++) temp += A_val[ptr] * x[A_ind[ptr]]; } r[i] = temp; } return; } #endif #if 1 /* copied from primal */ /*********************************************************************** * refine_btran - refine solution of B'* x = h * * This routine performs one iteration to refine the solution of the * system B'* x = h, where B' is a matrix transposed to the current * basis matrix, h is the vector of right-hand sides, x is the solution * vector. */ static void refine_btran(struct csa *csa, double h[], double x[]) { int m = csa->m; double *r = csa->work1; double *d = csa->work1; int i; /* compute the residual vector r = h - B'* x */ error_btran(csa, h, x, r); /* compute the correction vector d = inv(B') * r */ xassert(csa->valid); bfd_btran(csa->bfd, d); /* refine the solution vector (new x) = (old x) + d */ for (i = 1; i <= m; i++) x[i] += d[i]; return; } #endif #if 1 /* copied from primal */ /*********************************************************************** * get_xN - determine current value of non-basic variable xN[j] * * This routine returns the current value of non-basic variable xN[j], * which is a value of its active bound. */ static double get_xN(struct csa *csa, int j) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif double *lb = csa->lb; double *ub = csa->ub; int *head = csa->head; char *stat = csa->stat; int k; double xN; #ifdef GLP_DEBUG xassert(1 <= j && j <= n); #endif k = head[m+j]; /* x[k] = xN[j] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif switch (stat[j]) { case GLP_NL: /* x[k] is on its lower bound */ xN = lb[k]; break; case GLP_NU: /* x[k] is on its upper bound */ xN = ub[k]; break; case GLP_NF: /* x[k] is free non-basic variable */ xN = 0.0; break; case GLP_NS: /* x[k] is fixed non-basic variable */ xN = lb[k]; break; default: xassert(stat != stat); } return xN; } #endif #if 1 /* copied from primal */ /*********************************************************************** * eval_beta - compute primal values of basic variables * * This routine computes current primal values of all basic variables: * * beta = - inv(B) * N * xN, * * where B is the current basis matrix, N is a matrix built of columns * of matrix (I|-A) corresponding to non-basic variables, and xN is the * vector of current values of non-basic variables. */ static void eval_beta(struct csa *csa, double beta[]) { int m = csa->m; int n = csa->n; int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int *head = csa->head; double *h = csa->work2; int i, j, k, beg, end, ptr; double xN; /* compute the right-hand side vector: h := - N * xN = - N[1] * xN[1] - ... - N[n] * xN[n], where N[1], ..., N[n] are columns of matrix N */ for (i = 1; i <= m; i++) h[i] = 0.0; for (j = 1; j <= n; j++) { k = head[m+j]; /* x[k] = xN[j] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif /* determine current value of xN[j] */ xN = get_xN(csa, j); if (xN == 0.0) continue; if (k <= m) { /* N[j] is k-th column of submatrix I */ h[k] -= xN; } else { /* N[j] is (k-m)-th column of submatrix (-A) */ beg = A_ptr[k-m]; end = A_ptr[k-m+1]; for (ptr = beg; ptr < end; ptr++) h[A_ind[ptr]] += xN * A_val[ptr]; } } /* solve system B * beta = h */ memcpy(&beta[1], &h[1], m * sizeof(double)); xassert(csa->valid); bfd_ftran(csa->bfd, beta); /* and refine the solution */ refine_ftran(csa, h, beta); return; } #endif #if 1 /* copied from primal */ /*********************************************************************** * eval_pi - compute vector of simplex multipliers * * This routine computes the vector of current simplex multipliers: * * pi = inv(B') * cB, * * where B' is a matrix transposed to the current basis matrix, cB is * a subvector of objective coefficients at basic variables. */ static void eval_pi(struct csa *csa, double pi[]) { int m = csa->m; double *c = csa->coef; int *head = csa->head; double *cB = csa->work2; int i; /* construct the right-hand side vector cB */ for (i = 1; i <= m; i++) cB[i] = c[head[i]]; /* solve system B'* pi = cB */ memcpy(&pi[1], &cB[1], m * sizeof(double)); xassert(csa->valid); bfd_btran(csa->bfd, pi); /* and refine the solution */ refine_btran(csa, cB, pi); return; } #endif #if 1 /* copied from primal */ /*********************************************************************** * eval_cost - compute reduced cost of non-basic variable xN[j] * * This routine computes the current reduced cost of non-basic variable * xN[j]: * * d[j] = cN[j] - N'[j] * pi, * * where cN[j] is the objective coefficient at variable xN[j], N[j] is * a column of the augmented constraint matrix (I|-A) corresponding to * xN[j], pi is the vector of simplex multipliers. */ static double eval_cost(struct csa *csa, double pi[], int j) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif double *coef = csa->coef; int *head = csa->head; int k; double dj; #ifdef GLP_DEBUG xassert(1 <= j && j <= n); #endif k = head[m+j]; /* x[k] = xN[j] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif dj = coef[k]; if (k <= m) { /* N[j] is k-th column of submatrix I */ dj -= pi[k]; } else { /* N[j] is (k-m)-th column of submatrix (-A) */ int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int beg, end, ptr; beg = A_ptr[k-m]; end = A_ptr[k-m+1]; for (ptr = beg; ptr < end; ptr++) dj += A_val[ptr] * pi[A_ind[ptr]]; } return dj; } #endif #if 1 /* copied from primal */ /*********************************************************************** * eval_bbar - compute and store primal values of basic variables * * This routine computes primal values of all basic variables and then * stores them in the solution array. */ static void eval_bbar(struct csa *csa) { eval_beta(csa, csa->bbar); return; } #endif #if 1 /* copied from primal */ /*********************************************************************** * eval_cbar - compute and store reduced costs of non-basic variables * * This routine computes reduced costs of all non-basic variables and * then stores them in the solution array. */ static void eval_cbar(struct csa *csa) { #ifdef GLP_DEBUG int m = csa->m; #endif int n = csa->n; #ifdef GLP_DEBUG int *head = csa->head; #endif double *cbar = csa->cbar; double *pi = csa->work3; int j; #ifdef GLP_DEBUG int k; #endif /* compute simplex multipliers */ eval_pi(csa, pi); /* compute and store reduced costs */ for (j = 1; j <= n; j++) { #ifdef GLP_DEBUG k = head[m+j]; /* x[k] = xN[j] */ xassert(1 <= k && k <= m+n); #endif cbar[j] = eval_cost(csa, pi, j); } return; } #endif /*********************************************************************** * reset_refsp - reset the reference space * * This routine resets (redefines) the reference space used in the * projected steepest edge pricing algorithm. */ static void reset_refsp(struct csa *csa) { int m = csa->m; int n = csa->n; int *head = csa->head; char *refsp = csa->refsp; double *gamma = csa->gamma; int i, k; xassert(csa->refct == 0); csa->refct = 1000; memset(&refsp[1], 0, (m+n) * sizeof(char)); for (i = 1; i <= m; i++) { k = head[i]; /* x[k] = xB[i] */ refsp[k] = 1; gamma[i] = 1.0; } return; } /*********************************************************************** * eval_gamma - compute steepest edge coefficients * * This routine computes the vector of steepest edge coefficients for * all basic variables (except free ones) using its direct definition: * * gamma[i] = eta[i] + sum alfa[i,j]^2, i = 1,...,m, * j in C * * where eta[i] = 1 means that xB[i] is in the current reference space, * and 0 otherwise; C is a set of non-basic non-fixed variables xN[j], * which are in the current reference space; alfa[i,j] are elements of * the current simplex table. * * NOTE: The routine is intended only for debugginig purposes. */ static void eval_gamma(struct csa *csa, double gamma[]) { int m = csa->m; int n = csa->n; char *type = csa->type; int *head = csa->head; char *refsp = csa->refsp; double *alfa = csa->work3; double *h = csa->work3; int i, j, k; /* gamma[i] := eta[i] (or 1, if xB[i] is free) */ for (i = 1; i <= m; i++) { k = head[i]; /* x[k] = xB[i] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (type[k] == GLP_FR) gamma[i] = 1.0; else gamma[i] = (refsp[k] ? 1.0 : 0.0); } /* compute columns of the current simplex table */ for (j = 1; j <= n; j++) { k = head[m+j]; /* x[k] = xN[j] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif /* skip column, if xN[j] is not in C */ if (!refsp[k]) continue; #ifdef GLP_DEBUG /* set C must not contain fixed variables */ xassert(type[k] != GLP_FX); #endif /* construct the right-hand side vector h = - N[j] */ for (i = 1; i <= m; i++) h[i] = 0.0; if (k <= m) { /* N[j] is k-th column of submatrix I */ h[k] = -1.0; } else { /* N[j] is (k-m)-th column of submatrix (-A) */ int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int beg, end, ptr; beg = A_ptr[k-m]; end = A_ptr[k-m+1]; for (ptr = beg; ptr < end; ptr++) h[A_ind[ptr]] = A_val[ptr]; } /* solve system B * alfa = h */ xassert(csa->valid); bfd_ftran(csa->bfd, alfa); /* gamma[i] := gamma[i] + alfa[i,j]^2 */ for (i = 1; i <= m; i++) { k = head[i]; /* x[k] = xB[i] */ if (type[k] != GLP_FR) gamma[i] += alfa[i] * alfa[i]; } } return; } /*********************************************************************** * chuzr - choose basic variable (row of the simplex table) * * This routine chooses basic variable xB[p] having largest weighted * bound violation: * * |r[p]| / sqrt(gamma[p]) = max |r[i]| / sqrt(gamma[i]), * i in I * * / lB[i] - beta[i], if beta[i] < lB[i] * | * r[i] = < 0, if lB[i] <= beta[i] <= uB[i] * | * \ uB[i] - beta[i], if beta[i] > uB[i] * * where beta[i] is primal value of xB[i] in the current basis, lB[i] * and uB[i] are lower and upper bounds of xB[i], I is a subset of * eligible basic variables, which significantly violates their bounds, * gamma[i] is the steepest edge coefficient. * * If |r[i]| is less than a specified tolerance, xB[i] is not included * in I and therefore ignored. * * If I is empty and no variable has been chosen, p is set to 0. */ static void chuzr(struct csa *csa, double tol_bnd) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif char *type = csa->type; double *lb = csa->lb; double *ub = csa->ub; int *head = csa->head; double *bbar = csa->bbar; double *gamma = csa->gamma; int i, k, p; double delta, best, eps, ri, temp; /* nothing is chosen so far */ p = 0, delta = 0.0, best = 0.0; /* look through the list of basic variables */ for (i = 1; i <= m; i++) { k = head[i]; /* x[k] = xB[i] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif /* determine bound violation ri[i] */ ri = 0.0; if (type[k] == GLP_LO || type[k] == GLP_DB || type[k] == GLP_FX) { /* xB[i] has lower bound */ eps = tol_bnd * (1.0 + kappa * fabs(lb[k])); if (bbar[i] < lb[k] - eps) { /* and significantly violates it */ ri = lb[k] - bbar[i]; } } if (type[k] == GLP_UP || type[k] == GLP_DB || type[k] == GLP_FX) { /* xB[i] has upper bound */ eps = tol_bnd * (1.0 + kappa * fabs(ub[k])); if (bbar[i] > ub[k] + eps) { /* and significantly violates it */ ri = ub[k] - bbar[i]; } } /* if xB[i] is not eligible, skip it */ if (ri == 0.0) continue; /* xB[i] is eligible basic variable; choose one with largest weighted bound violation */ #ifdef GLP_DEBUG xassert(gamma[i] >= 0.0); #endif temp = gamma[i]; if (temp < DBL_EPSILON) temp = DBL_EPSILON; temp = (ri * ri) / temp; if (best < temp) p = i, delta = ri, best = temp; } /* store the index of basic variable xB[p] chosen and its change in the adjacent basis */ csa->p = p; csa->delta = delta; return; } #if 1 /* copied from primal */ /*********************************************************************** * eval_rho - compute pivot row of the inverse * * This routine computes the pivot (p-th) row of the inverse inv(B), * which corresponds to basic variable xB[p] chosen: * * rho = inv(B') * e[p], * * where B' is a matrix transposed to the current basis matrix, e[p] * is unity vector. */ static void eval_rho(struct csa *csa, double rho[]) { int m = csa->m; int p = csa->p; double *e = rho; int i; #ifdef GLP_DEBUG xassert(1 <= p && p <= m); #endif /* construct the right-hand side vector e[p] */ for (i = 1; i <= m; i++) e[i] = 0.0; e[p] = 1.0; /* solve system B'* rho = e[p] */ xassert(csa->valid); bfd_btran(csa->bfd, rho); return; } #endif #if 1 /* copied from primal */ /*********************************************************************** * refine_rho - refine pivot row of the inverse * * This routine refines the pivot row of the inverse inv(B) assuming * that it was previously computed by the routine eval_rho. */ static void refine_rho(struct csa *csa, double rho[]) { int m = csa->m; int p = csa->p; double *e = csa->work3; int i; #ifdef GLP_DEBUG xassert(1 <= p && p <= m); #endif /* construct the right-hand side vector e[p] */ for (i = 1; i <= m; i++) e[i] = 0.0; e[p] = 1.0; /* refine solution of B'* rho = e[p] */ refine_btran(csa, e, rho); return; } #endif #if 1 /* 06/IV-2009 */ /*********************************************************************** * eval_trow - compute pivot row of the simplex table * * This routine computes the pivot row of the simplex table, which * corresponds to basic variable xB[p] chosen. * * The pivot row is the following vector: * * trow = T'* e[p] = - N'* inv(B') * e[p] = - N' * rho, * * where rho is the pivot row of the inverse inv(B) previously computed * by the routine eval_rho. * * Note that elements of the pivot row corresponding to fixed non-basic * variables are not computed. * * NOTES * * Computing pivot row of the simplex table is one of the most time * consuming operations, and for some instances it may take more than * 50% of the total solution time. * * In the current implementation there are two routines to compute the * pivot row. The routine eval_trow1 computes elements of the pivot row * as inner products of columns of the matrix N and the vector rho; it * is used when the vector rho is relatively dense. The routine * eval_trow2 computes the pivot row as a linear combination of rows of * the matrix N; it is used when the vector rho is relatively sparse. */ static void eval_trow1(struct csa *csa, double rho[]) { int m = csa->m; int n = csa->n; int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int *head = csa->head; char *stat = csa->stat; int *trow_ind = csa->trow_ind; double *trow_vec = csa->trow_vec; int j, k, beg, end, ptr, nnz; double temp; /* compute the pivot row as inner products of columns of the matrix N and vector rho: trow[j] = - rho * N[j] */ nnz = 0; for (j = 1; j <= n; j++) { if (stat[j] == GLP_NS) { /* xN[j] is fixed */ trow_vec[j] = 0.0; continue; } k = head[m+j]; /* x[k] = xN[j] */ if (k <= m) { /* N[j] is k-th column of submatrix I */ temp = - rho[k]; } else { /* N[j] is (k-m)-th column of submatrix (-A) */ beg = A_ptr[k-m], end = A_ptr[k-m+1]; temp = 0.0; for (ptr = beg; ptr < end; ptr++) temp += rho[A_ind[ptr]] * A_val[ptr]; } if (temp != 0.0) trow_ind[++nnz] = j; trow_vec[j] = temp; } csa->trow_nnz = nnz; return; } static void eval_trow2(struct csa *csa, double rho[]) { int m = csa->m; int n = csa->n; int *AT_ptr = csa->AT_ptr; int *AT_ind = csa->AT_ind; double *AT_val = csa->AT_val; int *bind = csa->bind; char *stat = csa->stat; int *trow_ind = csa->trow_ind; double *trow_vec = csa->trow_vec; int i, j, beg, end, ptr, nnz; double temp; /* clear the pivot row */ for (j = 1; j <= n; j++) trow_vec[j] = 0.0; /* compute the pivot row as a linear combination of rows of the matrix N: trow = - rho[1] * N'[1] - ... - rho[m] * N'[m] */ for (i = 1; i <= m; i++) { temp = rho[i]; if (temp == 0.0) continue; /* trow := trow - rho[i] * N'[i] */ j = bind[i] - m; /* x[i] = xN[j] */ if (j >= 1 && stat[j] != GLP_NS) trow_vec[j] -= temp; beg = AT_ptr[i], end = AT_ptr[i+1]; for (ptr = beg; ptr < end; ptr++) { j = bind[m + AT_ind[ptr]] - m; /* x[k] = xN[j] */ if (j >= 1 && stat[j] != GLP_NS) trow_vec[j] += temp * AT_val[ptr]; } } /* construct sparse pattern of the pivot row */ nnz = 0; for (j = 1; j <= n; j++) { if (trow_vec[j] != 0.0) trow_ind[++nnz] = j; } csa->trow_nnz = nnz; return; } static void eval_trow(struct csa *csa, double rho[]) { int m = csa->m; int i, nnz; double dens; /* determine the density of the vector rho */ nnz = 0; for (i = 1; i <= m; i++) if (rho[i] != 0.0) nnz++; dens = (double)nnz / (double)m; if (dens >= 0.20) { /* rho is relatively dense */ eval_trow1(csa, rho); } else { /* rho is relatively sparse */ eval_trow2(csa, rho); } return; } #endif /*********************************************************************** * sort_trow - sort pivot row of the simplex table * * This routine reorders the list of non-zero elements of the pivot * row to put significant elements, whose magnitude is not less than * a specified tolerance, in front of the list, and stores the number * of significant elements in trow_num. */ static void sort_trow(struct csa *csa, double tol_piv) { #ifdef GLP_DEBUG int n = csa->n; char *stat = csa->stat; #endif int nnz = csa->trow_nnz; int *trow_ind = csa->trow_ind; double *trow_vec = csa->trow_vec; int j, num, pos; double big, eps, temp; /* compute infinity (maximum) norm of the row */ big = 0.0; for (pos = 1; pos <= nnz; pos++) { #ifdef GLP_DEBUG j = trow_ind[pos]; xassert(1 <= j && j <= n); xassert(stat[j] != GLP_NS); #endif temp = fabs(trow_vec[trow_ind[pos]]); if (big < temp) big = temp; } csa->trow_max = big; /* determine absolute pivot tolerance */ eps = tol_piv * (1.0 + 0.01 * big); /* move significant row components to the front of the list */ for (num = 0; num < nnz; ) { j = trow_ind[nnz]; if (fabs(trow_vec[j]) < eps) nnz--; else { num++; trow_ind[nnz] = trow_ind[num]; trow_ind[num] = j; } } csa->trow_num = num; return; } #ifdef GLP_LONG_STEP /* 07/IV-2009 */ static int ls_func(const void *p1_, const void *p2_) { const struct bkpt *p1 = p1_, *p2 = p2_; if (p1->t < p2->t) return -1; if (p1->t > p2->t) return +1; return 0; } static int ls_func1(const void *p1_, const void *p2_) { const struct bkpt *p1 = p1_, *p2 = p2_; if (p1->dz < p2->dz) return -1; if (p1->dz > p2->dz) return +1; return 0; } static void long_step(struct csa *csa) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif char *type = csa->type; double *lb = csa->lb; double *ub = csa->ub; int *head = csa->head; char *stat = csa->stat; double *cbar = csa->cbar; double delta = csa->delta; int *trow_ind = csa->trow_ind; double *trow_vec = csa->trow_vec; int trow_num = csa->trow_num; struct bkpt *bkpt = csa->bkpt; int j, k, kk, nbps, pos; double alfa, s, slope, dzmax; /* delta > 0 means that xB[p] violates its lower bound, so to increase the dual objective lambdaB[p] must increase; delta < 0 means that xB[p] violates its upper bound, so to increase the dual objective lambdaB[p] must decrease */ /* s := sign(delta) */ s = (delta > 0.0 ? +1.0 : -1.0); /* determine breakpoints of the dual objective */ nbps = 0; for (pos = 1; pos <= trow_num; pos++) { j = trow_ind[pos]; #ifdef GLP_DEBUG xassert(1 <= j && j <= n); xassert(stat[j] != GLP_NS); #endif /* if there is free non-basic variable, switch to the standard ratio test */ if (stat[j] == GLP_NF) { nbps = 0; goto done; } /* lambdaN[j] = ... - alfa * t - ..., where t = s * lambdaB[i] is the dual ray parameter, t >= 0 */ alfa = s * trow_vec[j]; #ifdef GLP_DEBUG xassert(alfa != 0.0); xassert(stat[j] == GLP_NL || stat[j] == GLP_NU); #endif if (alfa > 0.0 && stat[j] == GLP_NL || alfa < 0.0 && stat[j] == GLP_NU) { /* either lambdaN[j] >= 0 (if stat = GLP_NL) and decreases or lambdaN[j] <= 0 (if stat = GLP_NU) and increases; in both cases we have a breakpoint */ nbps++; #ifdef GLP_DEBUG xassert(nbps <= n); #endif bkpt[nbps].j = j; bkpt[nbps].t = cbar[j] / alfa; /* if (stat[j] == GLP_NL && cbar[j] < 0.0 || stat[j] == GLP_NU && cbar[j] > 0.0) xprintf("%d %g\n", stat[j], cbar[j]); */ /* if t is negative, replace it by exact zero (see comments in the routine chuzc) */ if (bkpt[nbps].t < 0.0) bkpt[nbps].t = 0.0; } } /* if there are less than two breakpoints, switch to the standard ratio test */ if (nbps < 2) { nbps = 0; goto done; } /* sort breakpoints by ascending the dual ray parameter, t */ qsort(&bkpt[1], nbps, sizeof(struct bkpt), ls_func); /* determine last breakpoint, at which the dual objective still greater than at t = 0 */ dzmax = 0.0; slope = fabs(delta); /* initial slope */ for (kk = 1; kk <= nbps; kk++) { if (kk == 1) bkpt[kk].dz = 0.0 + slope * (bkpt[kk].t - 0.0); else bkpt[kk].dz = bkpt[kk-1].dz + slope * (bkpt[kk].t - bkpt[kk-1].t); if (dzmax < bkpt[kk].dz) dzmax = bkpt[kk].dz; else if (bkpt[kk].dz < 0.05 * (1.0 + dzmax)) { nbps = kk - 1; break; } j = bkpt[kk].j; k = head[m+j]; /* x[k] = xN[j] */ if (type[k] == GLP_DB) slope -= fabs(trow_vec[j]) * (ub[k] - lb[k]); else { nbps = kk; break; } } /* if there are less than two breakpoints, switch to the standard ratio test */ if (nbps < 2) { nbps = 0; goto done; } /* sort breakpoints by ascending the dual change, dz */ qsort(&bkpt[1], nbps, sizeof(struct bkpt), ls_func1); /* for (kk = 1; kk <= nbps; kk++) xprintf("%d; t = %g; dz = %g\n", kk, bkpt[kk].t, bkpt[kk].dz); */ done: csa->nbps = nbps; return; } #endif /*********************************************************************** * chuzc - choose non-basic variable (column of the simplex table) * * This routine chooses non-basic variable xN[q], which being entered * in the basis keeps dual feasibility of the basic solution. * * The parameter rtol is a relative tolerance used to relax zero bounds * of reduced costs of non-basic variables. If rtol = 0, the routine * implements the standard ratio test. Otherwise, if rtol > 0, the * routine implements Harris' two-pass ratio test. In the latter case * rtol should be about three times less than a tolerance used to check * dual feasibility. */ static void chuzc(struct csa *csa, double rtol) { #ifdef GLP_DEBUG int m = csa->m; int n = csa->n; #endif char *stat = csa->stat; double *cbar = csa->cbar; #ifdef GLP_DEBUG int p = csa->p; #endif double delta = csa->delta; int *trow_ind = csa->trow_ind; double *trow_vec = csa->trow_vec; int trow_num = csa->trow_num; int j, pos, q; double alfa, big, s, t, teta, tmax; #ifdef GLP_DEBUG xassert(1 <= p && p <= m); #endif /* delta > 0 means that xB[p] violates its lower bound and goes to it in the adjacent basis, so lambdaB[p] is increasing from its lower zero bound; delta < 0 means that xB[p] violates its upper bound and goes to it in the adjacent basis, so lambdaB[p] is decreasing from its upper zero bound */ #ifdef GLP_DEBUG xassert(delta != 0.0); #endif /* s := sign(delta) */ s = (delta > 0.0 ? +1.0 : -1.0); /*** FIRST PASS ***/ /* nothing is chosen so far */ q = 0, teta = DBL_MAX, big = 0.0; /* walk through significant elements of the pivot row */ for (pos = 1; pos <= trow_num; pos++) { j = trow_ind[pos]; #ifdef GLP_DEBUG xassert(1 <= j && j <= n); #endif alfa = s * trow_vec[j]; #ifdef GLP_DEBUG xassert(alfa != 0.0); #endif /* lambdaN[j] = ... - alfa * lambdaB[p] - ..., and due to s we need to consider only increasing lambdaB[p] */ if (alfa > 0.0) { /* lambdaN[j] is decreasing */ if (stat[j] == GLP_NL || stat[j] == GLP_NF) { /* lambdaN[j] has zero lower bound */ t = (cbar[j] + rtol) / alfa; } else { /* lambdaN[j] has no lower bound */ continue; } } else { /* lambdaN[j] is increasing */ if (stat[j] == GLP_NU || stat[j] == GLP_NF) { /* lambdaN[j] has zero upper bound */ t = (cbar[j] - rtol) / alfa; } else { /* lambdaN[j] has no upper bound */ continue; } } /* t is a change of lambdaB[p], on which lambdaN[j] reaches its zero bound (possibly relaxed); since the basic solution is assumed to be dual feasible, t has to be non-negative by definition; however, it may happen that lambdaN[j] slightly (i.e. within a tolerance) violates its zero bound, that leads to negative t; in the latter case, if xN[j] is chosen, negative t means that lambdaB[p] changes in wrong direction that may cause wrong results on updating reduced costs; thus, if t is negative, we should replace it by exact zero assuming that lambdaN[j] is exactly on its zero bound, and violation appears due to round-off errors */ if (t < 0.0) t = 0.0; /* apply minimal ratio test */ if (teta > t || teta == t && big < fabs(alfa)) q = j, teta = t, big = fabs(alfa); } /* the second pass is skipped in the following cases: */ /* if the standard ratio test is used */ if (rtol == 0.0) goto done; /* if no non-basic variable has been chosen on the first pass */ if (q == 0) goto done; /* if lambdaN[q] prevents lambdaB[p] from any change */ if (teta == 0.0) goto done; /*** SECOND PASS ***/ /* here tmax is a maximal change of lambdaB[p], on which the solution remains dual feasible within a tolerance */ #if 0 tmax = (1.0 + 10.0 * DBL_EPSILON) * teta; #else tmax = teta; #endif /* nothing is chosen so far */ q = 0, teta = DBL_MAX, big = 0.0; /* walk through significant elements of the pivot row */ for (pos = 1; pos <= trow_num; pos++) { j = trow_ind[pos]; #ifdef GLP_DEBUG xassert(1 <= j && j <= n); #endif alfa = s * trow_vec[j]; #ifdef GLP_DEBUG xassert(alfa != 0.0); #endif /* lambdaN[j] = ... - alfa * lambdaB[p] - ..., and due to s we need to consider only increasing lambdaB[p] */ if (alfa > 0.0) { /* lambdaN[j] is decreasing */ if (stat[j] == GLP_NL || stat[j] == GLP_NF) { /* lambdaN[j] has zero lower bound */ t = cbar[j] / alfa; } else { /* lambdaN[j] has no lower bound */ continue; } } else { /* lambdaN[j] is increasing */ if (stat[j] == GLP_NU || stat[j] == GLP_NF) { /* lambdaN[j] has zero upper bound */ t = cbar[j] / alfa; } else { /* lambdaN[j] has no upper bound */ continue; } } /* (see comments for the first pass) */ if (t < 0.0) t = 0.0; /* t is a change of lambdaB[p], on which lambdaN[j] reaches its zero (lower or upper) bound; if t <= tmax, all reduced costs can violate their zero bounds only within relaxation tolerance rtol, so we can choose non-basic variable having largest influence coefficient to avoid possible numerical instability */ if (t <= tmax && big < fabs(alfa)) q = j, teta = t, big = fabs(alfa); } /* something must be chosen on the second pass */ xassert(q != 0); done: /* store the index of non-basic variable xN[q] chosen */ csa->q = q; /* store reduced cost of xN[q] in the adjacent basis */ csa->new_dq = s * teta; return; } #if 1 /* copied from primal */ /*********************************************************************** * eval_tcol - compute pivot column of the simplex table * * This routine computes the pivot column of the simplex table, which * corresponds to non-basic variable xN[q] chosen. * * The pivot column is the following vector: * * tcol = T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q], * * where B is the current basis matrix, N[q] is a column of the matrix * (I|-A) corresponding to variable xN[q]. */ static void eval_tcol(struct csa *csa) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif int *head = csa->head; int q = csa->q; int *tcol_ind = csa->tcol_ind; double *tcol_vec = csa->tcol_vec; double *h = csa->tcol_vec; int i, k, nnz; #ifdef GLP_DEBUG xassert(1 <= q && q <= n); #endif k = head[m+q]; /* x[k] = xN[q] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif /* construct the right-hand side vector h = - N[q] */ for (i = 1; i <= m; i++) h[i] = 0.0; if (k <= m) { /* N[q] is k-th column of submatrix I */ h[k] = -1.0; } else { /* N[q] is (k-m)-th column of submatrix (-A) */ int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int beg, end, ptr; beg = A_ptr[k-m]; end = A_ptr[k-m+1]; for (ptr = beg; ptr < end; ptr++) h[A_ind[ptr]] = A_val[ptr]; } /* solve system B * tcol = h */ xassert(csa->valid); bfd_ftran(csa->bfd, tcol_vec); /* construct sparse pattern of the pivot column */ nnz = 0; for (i = 1; i <= m; i++) { if (tcol_vec[i] != 0.0) tcol_ind[++nnz] = i; } csa->tcol_nnz = nnz; return; } #endif #if 1 /* copied from primal */ /*********************************************************************** * refine_tcol - refine pivot column of the simplex table * * This routine refines the pivot column of the simplex table assuming * that it was previously computed by the routine eval_tcol. */ static void refine_tcol(struct csa *csa) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif int *head = csa->head; int q = csa->q; int *tcol_ind = csa->tcol_ind; double *tcol_vec = csa->tcol_vec; double *h = csa->work3; int i, k, nnz; #ifdef GLP_DEBUG xassert(1 <= q && q <= n); #endif k = head[m+q]; /* x[k] = xN[q] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif /* construct the right-hand side vector h = - N[q] */ for (i = 1; i <= m; i++) h[i] = 0.0; if (k <= m) { /* N[q] is k-th column of submatrix I */ h[k] = -1.0; } else { /* N[q] is (k-m)-th column of submatrix (-A) */ int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int beg, end, ptr; beg = A_ptr[k-m]; end = A_ptr[k-m+1]; for (ptr = beg; ptr < end; ptr++) h[A_ind[ptr]] = A_val[ptr]; } /* refine solution of B * tcol = h */ refine_ftran(csa, h, tcol_vec); /* construct sparse pattern of the pivot column */ nnz = 0; for (i = 1; i <= m; i++) { if (tcol_vec[i] != 0.0) tcol_ind[++nnz] = i; } csa->tcol_nnz = nnz; return; } #endif /*********************************************************************** * update_cbar - update reduced costs of non-basic variables * * This routine updates reduced costs of all (except fixed) non-basic * variables for the adjacent basis. */ static void update_cbar(struct csa *csa) { #ifdef GLP_DEBUG int n = csa->n; #endif double *cbar = csa->cbar; int trow_nnz = csa->trow_nnz; int *trow_ind = csa->trow_ind; double *trow_vec = csa->trow_vec; int q = csa->q; double new_dq = csa->new_dq; int j, pos; #ifdef GLP_DEBUG xassert(1 <= q && q <= n); #endif /* set new reduced cost of xN[q] */ cbar[q] = new_dq; /* update reduced costs of other non-basic variables */ if (new_dq == 0.0) goto done; for (pos = 1; pos <= trow_nnz; pos++) { j = trow_ind[pos]; #ifdef GLP_DEBUG xassert(1 <= j && j <= n); #endif if (j != q) cbar[j] -= trow_vec[j] * new_dq; } done: return; } /*********************************************************************** * update_bbar - update values of basic variables * * This routine updates values of all basic variables for the adjacent * basis. */ static void update_bbar(struct csa *csa) { #ifdef GLP_DEBUG int m = csa->m; int n = csa->n; #endif double *bbar = csa->bbar; int p = csa->p; double delta = csa->delta; int q = csa->q; int tcol_nnz = csa->tcol_nnz; int *tcol_ind = csa->tcol_ind; double *tcol_vec = csa->tcol_vec; int i, pos; double teta; #ifdef GLP_DEBUG xassert(1 <= p && p <= m); xassert(1 <= q && q <= n); #endif /* determine the change of xN[q] in the adjacent basis */ #ifdef GLP_DEBUG xassert(tcol_vec[p] != 0.0); #endif teta = delta / tcol_vec[p]; /* set new primal value of xN[q] */ bbar[p] = get_xN(csa, q) + teta; /* update primal values of other basic variables */ if (teta == 0.0) goto done; for (pos = 1; pos <= tcol_nnz; pos++) { i = tcol_ind[pos]; #ifdef GLP_DEBUG xassert(1 <= i && i <= m); #endif if (i != p) bbar[i] += tcol_vec[i] * teta; } done: return; } /*********************************************************************** * update_gamma - update steepest edge coefficients * * This routine updates steepest-edge coefficients for the adjacent * basis. */ static void update_gamma(struct csa *csa) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif char *type = csa->type; int *head = csa->head; char *refsp = csa->refsp; double *gamma = csa->gamma; int p = csa->p; int trow_nnz = csa->trow_nnz; int *trow_ind = csa->trow_ind; double *trow_vec = csa->trow_vec; int q = csa->q; int tcol_nnz = csa->tcol_nnz; int *tcol_ind = csa->tcol_ind; double *tcol_vec = csa->tcol_vec; double *u = csa->work3; int i, j, k,pos; double gamma_p, eta_p, pivot, t, t1, t2; #ifdef GLP_DEBUG xassert(1 <= p && p <= m); xassert(1 <= q && q <= n); #endif /* the basis changes, so decrease the count */ xassert(csa->refct > 0); csa->refct--; /* recompute gamma[p] for the current basis more accurately and compute auxiliary vector u */ #ifdef GLP_DEBUG xassert(type[head[p]] != GLP_FR); #endif gamma_p = eta_p = (refsp[head[p]] ? 1.0 : 0.0); for (i = 1; i <= m; i++) u[i] = 0.0; for (pos = 1; pos <= trow_nnz; pos++) { j = trow_ind[pos]; #ifdef GLP_DEBUG xassert(1 <= j && j <= n); #endif k = head[m+j]; /* x[k] = xN[j] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); xassert(type[k] != GLP_FX); #endif if (!refsp[k]) continue; t = trow_vec[j]; gamma_p += t * t; /* u := u + N[j] * delta[j] * trow[j] */ if (k <= m) { /* N[k] = k-j stolbec submatrix I */ u[k] += t; } else { /* N[k] = k-m-k stolbec (-A) */ int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int beg, end, ptr; beg = A_ptr[k-m]; end = A_ptr[k-m+1]; for (ptr = beg; ptr < end; ptr++) u[A_ind[ptr]] -= t * A_val[ptr]; } } xassert(csa->valid); bfd_ftran(csa->bfd, u); /* update gamma[i] for other basic variables (except xB[p] and free variables) */ pivot = tcol_vec[p]; #ifdef GLP_DEBUG xassert(pivot != 0.0); #endif for (pos = 1; pos <= tcol_nnz; pos++) { i = tcol_ind[pos]; #ifdef GLP_DEBUG xassert(1 <= i && i <= m); #endif k = head[i]; #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif /* skip xB[p] */ if (i == p) continue; /* skip free basic variable */ if (type[head[i]] == GLP_FR) { #ifdef GLP_DEBUG xassert(gamma[i] == 1.0); #endif continue; } /* compute gamma[i] for the adjacent basis */ t = tcol_vec[i] / pivot; t1 = gamma[i] + t * t * gamma_p + 2.0 * t * u[i]; t2 = (refsp[k] ? 1.0 : 0.0) + eta_p * t * t; gamma[i] = (t1 >= t2 ? t1 : t2); /* (though gamma[i] can be exact zero, because the reference space does not include non-basic fixed variables) */ if (gamma[i] < DBL_EPSILON) gamma[i] = DBL_EPSILON; } /* compute gamma[p] for the adjacent basis */ if (type[head[m+q]] == GLP_FR) gamma[p] = 1.0; else { gamma[p] = gamma_p / (pivot * pivot); if (gamma[p] < DBL_EPSILON) gamma[p] = DBL_EPSILON; } /* if xB[p], which becomes xN[q] in the adjacent basis, is fixed and belongs to the reference space, remove it from there, and change all gamma's appropriately */ k = head[p]; if (type[k] == GLP_FX && refsp[k]) { refsp[k] = 0; for (pos = 1; pos <= tcol_nnz; pos++) { i = tcol_ind[pos]; if (i == p) { if (type[head[m+q]] == GLP_FR) continue; t = 1.0 / tcol_vec[p]; } else { if (type[head[i]] == GLP_FR) continue; t = tcol_vec[i] / tcol_vec[p]; } gamma[i] -= t * t; if (gamma[i] < DBL_EPSILON) gamma[i] = DBL_EPSILON; } } return; } #if 1 /* copied from primal */ /*********************************************************************** * err_in_bbar - compute maximal relative error in primal solution * * This routine returns maximal relative error: * * max |beta[i] - bbar[i]| / (1 + |beta[i]|), * * where beta and bbar are, respectively, directly computed and the * current (updated) values of basic variables. * * NOTE: The routine is intended only for debugginig purposes. */ static double err_in_bbar(struct csa *csa) { int m = csa->m; double *bbar = csa->bbar; int i; double e, emax, *beta; beta = xcalloc(1+m, sizeof(double)); eval_beta(csa, beta); emax = 0.0; for (i = 1; i <= m; i++) { e = fabs(beta[i] - bbar[i]) / (1.0 + fabs(beta[i])); if (emax < e) emax = e; } xfree(beta); return emax; } #endif #if 1 /* copied from primal */ /*********************************************************************** * err_in_cbar - compute maximal relative error in dual solution * * This routine returns maximal relative error: * * max |cost[j] - cbar[j]| / (1 + |cost[j]|), * * where cost and cbar are, respectively, directly computed and the * current (updated) reduced costs of non-basic non-fixed variables. * * NOTE: The routine is intended only for debugginig purposes. */ static double err_in_cbar(struct csa *csa) { int m = csa->m; int n = csa->n; char *stat = csa->stat; double *cbar = csa->cbar; int j; double e, emax, cost, *pi; pi = xcalloc(1+m, sizeof(double)); eval_pi(csa, pi); emax = 0.0; for (j = 1; j <= n; j++) { if (stat[j] == GLP_NS) continue; cost = eval_cost(csa, pi, j); e = fabs(cost - cbar[j]) / (1.0 + fabs(cost)); if (emax < e) emax = e; } xfree(pi); return emax; } #endif /*********************************************************************** * err_in_gamma - compute maximal relative error in steepest edge cff. * * This routine returns maximal relative error: * * max |gamma'[j] - gamma[j]| / (1 + |gamma'[j]), * * where gamma'[j] and gamma[j] are, respectively, directly computed * and the current (updated) steepest edge coefficients for non-basic * non-fixed variable x[j]. * * NOTE: The routine is intended only for debugginig purposes. */ static double err_in_gamma(struct csa *csa) { int m = csa->m; char *type = csa->type; int *head = csa->head; double *gamma = csa->gamma; double *exact = csa->work4; int i; double e, emax, temp; eval_gamma(csa, exact); emax = 0.0; for (i = 1; i <= m; i++) { if (type[head[i]] == GLP_FR) { xassert(gamma[i] == 1.0); xassert(exact[i] == 1.0); continue; } temp = exact[i]; e = fabs(temp - gamma[i]) / (1.0 + fabs(temp)); if (emax < e) emax = e; } return emax; } /*********************************************************************** * change_basis - change basis header * * This routine changes the basis header to make it corresponding to * the adjacent basis. */ static void change_basis(struct csa *csa) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif char *type = csa->type; int *head = csa->head; #if 1 /* 06/IV-2009 */ int *bind = csa->bind; #endif char *stat = csa->stat; int p = csa->p; double delta = csa->delta; int q = csa->q; int k; /* xB[p] leaves the basis, xN[q] enters the basis */ #ifdef GLP_DEBUG xassert(1 <= p && p <= m); xassert(1 <= q && q <= n); #endif /* xB[p] <-> xN[q] */ k = head[p], head[p] = head[m+q], head[m+q] = k; #if 1 /* 06/IV-2009 */ bind[head[p]] = p, bind[head[m+q]] = m + q; #endif if (type[k] == GLP_FX) stat[q] = GLP_NS; else if (delta > 0.0) { #ifdef GLP_DEBUG xassert(type[k] == GLP_LO || type[k] == GLP_DB); #endif stat[q] = GLP_NL; } else /* delta < 0.0 */ { #ifdef GLP_DEBUG xassert(type[k] == GLP_UP || type[k] == GLP_DB); #endif stat[q] = GLP_NU; } return; } /*********************************************************************** * check_feas - check dual feasibility of basic solution * * If the current basic solution is dual feasible within a tolerance, * this routine returns zero, otherwise it returns non-zero. */ static int check_feas(struct csa *csa, double tol_dj) { int m = csa->m; int n = csa->n; char *orig_type = csa->orig_type; int *head = csa->head; double *cbar = csa->cbar; int j, k; for (j = 1; j <= n; j++) { k = head[m+j]; /* x[k] = xN[j] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (cbar[j] < - tol_dj) if (orig_type[k] == GLP_LO || orig_type[k] == GLP_FR) return 1; if (cbar[j] > + tol_dj) if (orig_type[k] == GLP_UP || orig_type[k] == GLP_FR) return 1; } return 0; } /*********************************************************************** * set_aux_bnds - assign auxiliary bounds to variables * * This routine assigns auxiliary bounds to variables to construct an * LP problem solved on phase I. */ static void set_aux_bnds(struct csa *csa) { int m = csa->m; int n = csa->n; char *type = csa->type; double *lb = csa->lb; double *ub = csa->ub; char *orig_type = csa->orig_type; int *head = csa->head; char *stat = csa->stat; double *cbar = csa->cbar; int j, k; for (k = 1; k <= m+n; k++) { switch (orig_type[k]) { case GLP_FR: #if 0 type[k] = GLP_DB, lb[k] = -1.0, ub[k] = +1.0; #else /* to force free variables to enter the basis */ type[k] = GLP_DB, lb[k] = -1e3, ub[k] = +1e3; #endif break; case GLP_LO: type[k] = GLP_DB, lb[k] = 0.0, ub[k] = +1.0; break; case GLP_UP: type[k] = GLP_DB, lb[k] = -1.0, ub[k] = 0.0; break; case GLP_DB: case GLP_FX: type[k] = GLP_FX, lb[k] = ub[k] = 0.0; break; default: xassert(orig_type != orig_type); } } for (j = 1; j <= n; j++) { k = head[m+j]; /* x[k] = xN[j] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (type[k] == GLP_FX) stat[j] = GLP_NS; else if (cbar[j] >= 0.0) stat[j] = GLP_NL; else stat[j] = GLP_NU; } return; } /*********************************************************************** * set_orig_bnds - restore original bounds of variables * * This routine restores original types and bounds of variables and * determines statuses of non-basic variables assuming that the current * basis is dual feasible. */ static void set_orig_bnds(struct csa *csa) { int m = csa->m; int n = csa->n; char *type = csa->type; double *lb = csa->lb; double *ub = csa->ub; char *orig_type = csa->orig_type; double *orig_lb = csa->orig_lb; double *orig_ub = csa->orig_ub; int *head = csa->head; char *stat = csa->stat; double *cbar = csa->cbar; int j, k; memcpy(&type[1], &orig_type[1], (m+n) * sizeof(char)); memcpy(&lb[1], &orig_lb[1], (m+n) * sizeof(double)); memcpy(&ub[1], &orig_ub[1], (m+n) * sizeof(double)); for (j = 1; j <= n; j++) { k = head[m+j]; /* x[k] = xN[j] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif switch (type[k]) { case GLP_FR: stat[j] = GLP_NF; break; case GLP_LO: stat[j] = GLP_NL; break; case GLP_UP: stat[j] = GLP_NU; break; case GLP_DB: if (cbar[j] >= +DBL_EPSILON) stat[j] = GLP_NL; else if (cbar[j] <= -DBL_EPSILON) stat[j] = GLP_NU; else if (fabs(lb[k]) <= fabs(ub[k])) stat[j] = GLP_NL; else stat[j] = GLP_NU; break; case GLP_FX: stat[j] = GLP_NS; break; default: xassert(type != type); } } return; } /*********************************************************************** * check_stab - check numerical stability of basic solution * * If the current basic solution is dual feasible within a tolerance, * this routine returns zero, otherwise it returns non-zero. */ static int check_stab(struct csa *csa, double tol_dj) { int n = csa->n; char *stat = csa->stat; double *cbar = csa->cbar; int j; for (j = 1; j <= n; j++) { if (cbar[j] < - tol_dj) if (stat[j] == GLP_NL || stat[j] == GLP_NF) return 1; if (cbar[j] > + tol_dj) if (stat[j] == GLP_NU || stat[j] == GLP_NF) return 1; } return 0; } #if 1 /* copied from primal */ /*********************************************************************** * eval_obj - compute original objective function * * This routine computes the current value of the original objective * function. */ static double eval_obj(struct csa *csa) { int m = csa->m; int n = csa->n; double *obj = csa->obj; int *head = csa->head; double *bbar = csa->bbar; int i, j, k; double sum; sum = obj[0]; /* walk through the list of basic variables */ for (i = 1; i <= m; i++) { k = head[i]; /* x[k] = xB[i] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (k > m) sum += obj[k-m] * bbar[i]; } /* walk through the list of non-basic variables */ for (j = 1; j <= n; j++) { k = head[m+j]; /* x[k] = xN[j] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (k > m) sum += obj[k-m] * get_xN(csa, j); } return sum; } #endif /*********************************************************************** * display - display the search progress * * This routine displays some information about the search progress. */ static void display(struct csa *csa, const glp_smcp *parm, int spec) { int m = csa->m; int n = csa->n; double *coef = csa->coef; char *orig_type = csa->orig_type; int *head = csa->head; char *stat = csa->stat; int phase = csa->phase; double *bbar = csa->bbar; double *cbar = csa->cbar; int i, j, cnt; double sum; if (parm->msg_lev < GLP_MSG_ON) goto skip; if (parm->out_dly > 0 && 1000.0 * xdifftime(xtime(), csa->tm_beg) < parm->out_dly) goto skip; if (csa->it_cnt == csa->it_dpy) goto skip; if (!spec && csa->it_cnt % parm->out_frq != 0) goto skip; /* compute the sum of dual infeasibilities */ sum = 0.0; if (phase == 1) { for (i = 1; i <= m; i++) sum -= coef[head[i]] * bbar[i]; for (j = 1; j <= n; j++) sum -= coef[head[m+j]] * get_xN(csa, j); } else { for (j = 1; j <= n; j++) { if (cbar[j] < 0.0) if (stat[j] == GLP_NL || stat[j] == GLP_NF) sum -= cbar[j]; if (cbar[j] > 0.0) if (stat[j] == GLP_NU || stat[j] == GLP_NF) sum += cbar[j]; } } /* determine the number of basic fixed variables */ cnt = 0; for (i = 1; i <= m; i++) if (orig_type[head[i]] == GLP_FX) cnt++; if (csa->phase == 1) xprintf(" %6d: %24s infeas = %10.3e (%d)\n", csa->it_cnt, "", sum, cnt); else xprintf("|%6d: obj = %17.9e infeas = %10.3e (%d)\n", csa->it_cnt, eval_obj(csa), sum, cnt); csa->it_dpy = csa->it_cnt; skip: return; } #if 1 /* copied from primal */ /*********************************************************************** * store_sol - store basic solution back to the problem object * * This routine stores basic solution components back to the problem * object. */ static void store_sol(struct csa *csa, glp_prob *lp, int p_stat, int d_stat, int ray) { int m = csa->m; int n = csa->n; double zeta = csa->zeta; int *head = csa->head; char *stat = csa->stat; double *bbar = csa->bbar; double *cbar = csa->cbar; int i, j, k; #ifdef GLP_DEBUG xassert(lp->m == m); xassert(lp->n == n); #endif /* basis factorization */ #ifdef GLP_DEBUG xassert(!lp->valid && lp->bfd == NULL); xassert(csa->valid && csa->bfd != NULL); #endif lp->valid = 1, csa->valid = 0; lp->bfd = csa->bfd, csa->bfd = NULL; memcpy(&lp->head[1], &head[1], m * sizeof(int)); /* basic solution status */ lp->pbs_stat = p_stat; lp->dbs_stat = d_stat; /* objective function value */ lp->obj_val = eval_obj(csa); /* simplex iteration count */ lp->it_cnt = csa->it_cnt; /* unbounded ray */ lp->some = ray; /* basic variables */ for (i = 1; i <= m; i++) { k = head[i]; /* x[k] = xB[i] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (k <= m) { GLPROW *row = lp->row[k]; row->stat = GLP_BS; row->bind = i; row->prim = bbar[i] / row->rii; row->dual = 0.0; } else { GLPCOL *col = lp->col[k-m]; col->stat = GLP_BS; col->bind = i; col->prim = bbar[i] * col->sjj; col->dual = 0.0; } } /* non-basic variables */ for (j = 1; j <= n; j++) { k = head[m+j]; /* x[k] = xN[j] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (k <= m) { GLPROW *row = lp->row[k]; row->stat = stat[j]; row->bind = 0; #if 0 row->prim = get_xN(csa, j) / row->rii; #else switch (stat[j]) { case GLP_NL: row->prim = row->lb; break; case GLP_NU: row->prim = row->ub; break; case GLP_NF: row->prim = 0.0; break; case GLP_NS: row->prim = row->lb; break; default: xassert(stat != stat); } #endif row->dual = (cbar[j] * row->rii) / zeta; } else { GLPCOL *col = lp->col[k-m]; col->stat = stat[j]; col->bind = 0; #if 0 col->prim = get_xN(csa, j) * col->sjj; #else switch (stat[j]) { case GLP_NL: col->prim = col->lb; break; case GLP_NU: col->prim = col->ub; break; case GLP_NF: col->prim = 0.0; break; case GLP_NS: col->prim = col->lb; break; default: xassert(stat != stat); } #endif col->dual = (cbar[j] / col->sjj) / zeta; } } return; } #endif /*********************************************************************** * free_csa - deallocate common storage area * * This routine frees all the memory allocated to arrays in the common * storage area (CSA). */ static void free_csa(struct csa *csa) { xfree(csa->type); xfree(csa->lb); xfree(csa->ub); xfree(csa->coef); xfree(csa->orig_type); xfree(csa->orig_lb); xfree(csa->orig_ub); xfree(csa->obj); xfree(csa->A_ptr); xfree(csa->A_ind); xfree(csa->A_val); #if 1 /* 06/IV-2009 */ xfree(csa->AT_ptr); xfree(csa->AT_ind); xfree(csa->AT_val); #endif xfree(csa->head); #if 1 /* 06/IV-2009 */ xfree(csa->bind); #endif xfree(csa->stat); #if 0 /* 06/IV-2009 */ xfree(csa->N_ptr); xfree(csa->N_len); xfree(csa->N_ind); xfree(csa->N_val); #endif xfree(csa->bbar); xfree(csa->cbar); xfree(csa->refsp); xfree(csa->gamma); xfree(csa->trow_ind); xfree(csa->trow_vec); #ifdef GLP_LONG_STEP /* 07/IV-2009 */ xfree(csa->bkpt); #endif xfree(csa->tcol_ind); xfree(csa->tcol_vec); xfree(csa->work1); xfree(csa->work2); xfree(csa->work3); xfree(csa->work4); xfree(csa); return; } /*********************************************************************** * spx_dual - core LP solver based on the dual simplex method * * SYNOPSIS * * #include "glpspx.h" * int spx_dual(glp_prob *lp, const glp_smcp *parm); * * DESCRIPTION * * The routine spx_dual is a core LP solver based on the two-phase dual * simplex method. * * RETURNS * * 0 LP instance has been successfully solved. * * GLP_EOBJLL * Objective lower limit has been reached (maximization). * * GLP_EOBJUL * Objective upper limit has been reached (minimization). * * GLP_EITLIM * Iteration limit has been exhausted. * * GLP_ETMLIM * Time limit has been exhausted. * * GLP_EFAIL * The solver failed to solve LP instance. */ int spx_dual(glp_prob *lp, const glp_smcp *parm) { struct csa *csa; int binv_st = 2; /* status of basis matrix factorization: 0 - invalid; 1 - just computed; 2 - updated */ int bbar_st = 0; /* status of primal values of basic variables: 0 - invalid; 1 - just computed; 2 - updated */ int cbar_st = 0; /* status of reduced costs of non-basic variables: 0 - invalid; 1 - just computed; 2 - updated */ int rigorous = 0; /* rigorous mode flag; this flag is used to enable iterative refinement on computing pivot rows and columns of the simplex table */ int check = 0; int p_stat, d_stat, ret; #if 1 /* 16/VII-2013 */ int degen = 0; /* degenerated step count */ #endif /* allocate and initialize the common storage area */ csa = alloc_csa(lp); init_csa(csa, lp); if (parm->msg_lev >= GLP_MSG_DBG) xprintf("Objective scale factor = %g\n", csa->zeta); loop: /* main loop starts here */ /* compute factorization of the basis matrix */ if (binv_st == 0) { ret = invert_B(csa); if (ret != 0) { if (parm->msg_lev >= GLP_MSG_ERR) { xprintf("Error: unable to factorize the basis matrix (%d" ")\n", ret); xprintf("Sorry, basis recovery procedure not implemented" " yet\n"); } xassert(!lp->valid && lp->bfd == NULL); lp->bfd = csa->bfd, csa->bfd = NULL; lp->pbs_stat = lp->dbs_stat = GLP_UNDEF; lp->obj_val = 0.0; lp->it_cnt = csa->it_cnt; lp->some = 0; ret = GLP_EFAIL; goto done; } csa->valid = 1; binv_st = 1; /* just computed */ /* invalidate basic solution components */ bbar_st = cbar_st = 0; } #if 1 /* 16/VII-2013 */ if (degen >= 5000 && parm->meth == GLP_DUALP) { if (parm->msg_lev >= GLP_MSG_ERR) xprintf("Warning: dual degeneracy; switching to primal simp" "lex\n"); store_sol(csa, lp, GLP_UNDEF, GLP_UNDEF, 0); ret = GLP_EFAIL; goto done; } #endif /* compute reduced costs of non-basic variables */ if (cbar_st == 0) { eval_cbar(csa); cbar_st = 1; /* just computed */ /* determine the search phase, if not determined yet */ if (csa->phase == 0) { if (check_feas(csa, 0.90 * parm->tol_dj) != 0) { /* current basic solution is dual infeasible */ /* start searching for dual feasible solution */ csa->phase = 1; set_aux_bnds(csa); } else { /* current basic solution is dual feasible */ /* start searching for optimal solution */ csa->phase = 2; set_orig_bnds(csa); } xassert(check_stab(csa, parm->tol_dj) == 0); /* some non-basic double-bounded variables might become fixed (on phase I) or vice versa (on phase II) */ #if 0 /* 06/IV-2009 */ build_N(csa); #endif csa->refct = 0; /* bounds of non-basic variables have been changed, so invalidate primal values */ bbar_st = 0; } /* make sure that the current basic solution remains dual feasible */ if (check_stab(csa, parm->tol_dj) != 0) { if (parm->msg_lev >= GLP_MSG_ERR) xprintf("Warning: numerical instability (dual simplex, p" "hase %s)\n", csa->phase == 1 ? "I" : "II"); #if 1 if (parm->meth == GLP_DUALP) { store_sol(csa, lp, GLP_UNDEF, GLP_UNDEF, 0); ret = GLP_EFAIL; goto done; } #endif /* restart the search */ csa->phase = 0; binv_st = 0; rigorous = 5; goto loop; } } xassert(csa->phase == 1 || csa->phase == 2); /* on phase I we do not need to wait until the current basic solution becomes primal feasible; it is sufficient to make sure that all reduced costs have correct signs */ if (csa->phase == 1 && check_feas(csa, parm->tol_dj) == 0) { /* the current basis is dual feasible; switch to phase II */ display(csa, parm, 1); csa->phase = 2; if (cbar_st != 1) { eval_cbar(csa); cbar_st = 1; } set_orig_bnds(csa); #if 0 /* 06/IV-2009 */ build_N(csa); #endif csa->refct = 0; bbar_st = 0; } /* compute primal values of basic variables */ if (bbar_st == 0) { eval_bbar(csa); if (csa->phase == 2) csa->bbar[0] = eval_obj(csa); bbar_st = 1; /* just computed */ } /* redefine the reference space, if required */ switch (parm->pricing) { case GLP_PT_STD: break; case GLP_PT_PSE: if (csa->refct == 0) reset_refsp(csa); break; default: xassert(parm != parm); } /* at this point the basis factorization and all basic solution components are valid */ xassert(binv_st && bbar_st && cbar_st); /* check accuracy of current basic solution components (only for debugging) */ if (check) { double e_bbar = err_in_bbar(csa); double e_cbar = err_in_cbar(csa); double e_gamma = (parm->pricing == GLP_PT_PSE ? err_in_gamma(csa) : 0.0); xprintf("e_bbar = %10.3e; e_cbar = %10.3e; e_gamma = %10.3e\n", e_bbar, e_cbar, e_gamma); xassert(e_bbar <= 1e-5 && e_cbar <= 1e-5 && e_gamma <= 1e-3); } /* if the objective has to be maximized, check if it has reached its lower limit */ if (csa->phase == 2 && csa->zeta < 0.0 && parm->obj_ll > -DBL_MAX && csa->bbar[0] <= parm->obj_ll) { if (bbar_st != 1 || cbar_st != 1) { if (bbar_st != 1) bbar_st = 0; if (cbar_st != 1) cbar_st = 0; goto loop; } display(csa, parm, 1); if (parm->msg_lev >= GLP_MSG_ALL) xprintf("OBJECTIVE LOWER LIMIT REACHED; SEARCH TERMINATED\n" ); store_sol(csa, lp, GLP_INFEAS, GLP_FEAS, 0); ret = GLP_EOBJLL; goto done; } /* if the objective has to be minimized, check if it has reached its upper limit */ if (csa->phase == 2 && csa->zeta > 0.0 && parm->obj_ul < +DBL_MAX && csa->bbar[0] >= parm->obj_ul) { if (bbar_st != 1 || cbar_st != 1) { if (bbar_st != 1) bbar_st = 0; if (cbar_st != 1) cbar_st = 0; goto loop; } display(csa, parm, 1); if (parm->msg_lev >= GLP_MSG_ALL) xprintf("OBJECTIVE UPPER LIMIT REACHED; SEARCH TERMINATED\n" ); store_sol(csa, lp, GLP_INFEAS, GLP_FEAS, 0); ret = GLP_EOBJUL; goto done; } /* check if the iteration limit has been exhausted */ if (parm->it_lim < INT_MAX && csa->it_cnt - csa->it_beg >= parm->it_lim) { if (csa->phase == 2 && bbar_st != 1 || cbar_st != 1) { if (csa->phase == 2 && bbar_st != 1) bbar_st = 0; if (cbar_st != 1) cbar_st = 0; goto loop; } display(csa, parm, 1); if (parm->msg_lev >= GLP_MSG_ALL) xprintf("ITERATION LIMIT EXCEEDED; SEARCH TERMINATED\n"); switch (csa->phase) { case 1: d_stat = GLP_INFEAS; set_orig_bnds(csa); eval_bbar(csa); break; case 2: d_stat = GLP_FEAS; break; default: xassert(csa != csa); } store_sol(csa, lp, GLP_INFEAS, d_stat, 0); ret = GLP_EITLIM; goto done; } /* check if the time limit has been exhausted */ if (parm->tm_lim < INT_MAX && 1000.0 * xdifftime(xtime(), csa->tm_beg) >= parm->tm_lim) { if (csa->phase == 2 && bbar_st != 1 || cbar_st != 1) { if (csa->phase == 2 && bbar_st != 1) bbar_st = 0; if (cbar_st != 1) cbar_st = 0; goto loop; } display(csa, parm, 1); if (parm->msg_lev >= GLP_MSG_ALL) xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n"); switch (csa->phase) { case 1: d_stat = GLP_INFEAS; set_orig_bnds(csa); eval_bbar(csa); break; case 2: d_stat = GLP_FEAS; break; default: xassert(csa != csa); } store_sol(csa, lp, GLP_INFEAS, d_stat, 0); ret = GLP_ETMLIM; goto done; } /* display the search progress */ display(csa, parm, 0); /* choose basic variable xB[p] */ chuzr(csa, parm->tol_bnd); if (csa->p == 0) { if (bbar_st != 1 || cbar_st != 1) { if (bbar_st != 1) bbar_st = 0; if (cbar_st != 1) cbar_st = 0; goto loop; } display(csa, parm, 1); switch (csa->phase) { case 1: if (parm->msg_lev >= GLP_MSG_ALL) #if 0 /* 13/VII-2013; suggested by Prof. Fischetti */ xprintf("PROBLEM HAS NO DUAL FEASIBLE SOLUTION\n"); #else xprintf("LP HAS NO DUAL FEASIBLE SOLUTION\n"); #endif set_orig_bnds(csa); eval_bbar(csa); p_stat = GLP_INFEAS, d_stat = GLP_NOFEAS; break; case 2: if (parm->msg_lev >= GLP_MSG_ALL) #if 0 /* 13/VII-2013; suggested by Prof. Fischetti */ xprintf("OPTIMAL SOLUTION FOUND\n"); #else xprintf("OPTIMAL LP SOLUTION FOUND\n"); #endif p_stat = d_stat = GLP_FEAS; break; default: xassert(csa != csa); } store_sol(csa, lp, p_stat, d_stat, 0); ret = 0; goto done; } /* compute pivot row of the simplex table */ { double *rho = csa->work4; eval_rho(csa, rho); if (rigorous) refine_rho(csa, rho); eval_trow(csa, rho); sort_trow(csa, parm->tol_bnd); } /* unlike primal simplex there is no need to check accuracy of the primal value of xB[p] (which might be computed using the pivot row), since bbar is a result of FTRAN */ #ifdef GLP_LONG_STEP /* 07/IV-2009 */ long_step(csa); if (csa->nbps > 0) { csa->q = csa->bkpt[csa->nbps].j; if (csa->delta > 0.0) csa->new_dq = + csa->bkpt[csa->nbps].t; else csa->new_dq = - csa->bkpt[csa->nbps].t; } else #endif /* choose non-basic variable xN[q] */ switch (parm->r_test) { case GLP_RT_STD: chuzc(csa, 0.0); break; case GLP_RT_HAR: chuzc(csa, 0.30 * parm->tol_dj); break; default: xassert(parm != parm); } if (csa->q == 0) { if (bbar_st != 1 || cbar_st != 1 || !rigorous) { if (bbar_st != 1) bbar_st = 0; if (cbar_st != 1) cbar_st = 0; rigorous = 1; goto loop; } display(csa, parm, 1); switch (csa->phase) { case 1: if (parm->msg_lev >= GLP_MSG_ERR) xprintf("Error: unable to choose non-basic variable o" "n phase I\n"); xassert(!lp->valid && lp->bfd == NULL); lp->bfd = csa->bfd, csa->bfd = NULL; lp->pbs_stat = lp->dbs_stat = GLP_UNDEF; lp->obj_val = 0.0; lp->it_cnt = csa->it_cnt; lp->some = 0; ret = GLP_EFAIL; break; case 2: if (parm->msg_lev >= GLP_MSG_ALL) #if 0 /* 13/VII-2013; suggested by Prof. Fischetti */ xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n"); #else xprintf("LP HAS UNBOUNDED DUAL SOLUTION\n"); #endif store_sol(csa, lp, GLP_NOFEAS, GLP_FEAS, csa->head[csa->p]); ret = 0; break; default: xassert(csa != csa); } goto done; } /* check if the pivot element is acceptable */ { double piv = csa->trow_vec[csa->q]; double eps = 1e-5 * (1.0 + 0.01 * csa->trow_max); if (fabs(piv) < eps) { if (parm->msg_lev >= GLP_MSG_DBG) xprintf("piv = %.12g; eps = %g\n", piv, eps); if (!rigorous) { rigorous = 5; goto loop; } } } /* now xN[q] and xB[p] have been chosen anyhow */ /* compute pivot column of the simplex table */ eval_tcol(csa); if (rigorous) refine_tcol(csa); /* accuracy check based on the pivot element */ { double piv1 = csa->tcol_vec[csa->p]; /* more accurate */ double piv2 = csa->trow_vec[csa->q]; /* less accurate */ xassert(piv1 != 0.0); if (fabs(piv1 - piv2) > 1e-8 * (1.0 + fabs(piv1)) || !(piv1 > 0.0 && piv2 > 0.0 || piv1 < 0.0 && piv2 < 0.0)) { if (parm->msg_lev >= GLP_MSG_DBG) xprintf("piv1 = %.12g; piv2 = %.12g\n", piv1, piv2); if (binv_st != 1 || !rigorous) { if (binv_st != 1) binv_st = 0; rigorous = 5; goto loop; } /* (not a good idea; should be revised later) */ if (csa->tcol_vec[csa->p] == 0.0) { csa->tcol_nnz++; xassert(csa->tcol_nnz <= csa->m); csa->tcol_ind[csa->tcol_nnz] = csa->p; } csa->tcol_vec[csa->p] = piv2; } } /* update primal values of basic variables */ #ifdef GLP_LONG_STEP /* 07/IV-2009 */ if (csa->nbps > 0) { int kk, j, k; for (kk = 1; kk < csa->nbps; kk++) { if (csa->bkpt[kk].t >= csa->bkpt[csa->nbps].t) continue; j = csa->bkpt[kk].j; k = csa->head[csa->m + j]; xassert(csa->type[k] == GLP_DB); if (csa->stat[j] == GLP_NL) csa->stat[j] = GLP_NU; else csa->stat[j] = GLP_NL; } } bbar_st = 0; #else update_bbar(csa); if (csa->phase == 2) csa->bbar[0] += (csa->cbar[csa->q] / csa->zeta) * (csa->delta / csa->tcol_vec[csa->p]); bbar_st = 2; /* updated */ #endif /* update reduced costs of non-basic variables */ update_cbar(csa); cbar_st = 2; /* updated */ /* update steepest edge coefficients */ switch (parm->pricing) { case GLP_PT_STD: break; case GLP_PT_PSE: if (csa->refct > 0) update_gamma(csa); break; default: xassert(parm != parm); } /* update factorization of the basis matrix */ ret = update_B(csa, csa->p, csa->head[csa->m+csa->q]); if (ret == 0) binv_st = 2; /* updated */ else { csa->valid = 0; binv_st = 0; /* invalid */ } #if 0 /* 06/IV-2009 */ /* update matrix N */ del_N_col(csa, csa->q, csa->head[csa->m+csa->q]); if (csa->type[csa->head[csa->p]] != GLP_FX) add_N_col(csa, csa->q, csa->head[csa->p]); #endif /* change the basis header */ change_basis(csa); /* iteration complete */ csa->it_cnt++; #if 1 /* 16/VII-2013 */ if (-1e-9 <= csa->new_dq && csa->new_dq <= +1e-9) { /* degenerated step */ degen++; } else { /* non-degenerated step */ degen = 0; } #endif if (rigorous > 0) rigorous--; goto loop; done: /* deallocate the common storage area */ free_csa(csa); /* return to the calling program */ return ret; } /* eof */ Rglpk/src/GLPK/sva.c0000644000176000001440000004553612245352174013664 0ustar ripleyusers/* sva.c (sparse vector area) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #include "sva.h" /*********************************************************************** * sva_create_area - create sparse vector area (SVA) * * This routine creates the sparse vector area (SVA), which initially * is empty. * * The parameter n_max specifies the initial number of vectors that can * be allocated in the SVA, n_max > 0. * * The parameter size specifies the initial number of free locations in * the SVA, size > 0. * * On exit the routine returns a pointer to the SVA created. */ SVA *sva_create_area(int n_max, int size) { SVA *sva; xassert(0 < n_max && n_max < INT_MAX); xassert(0 < size && size < INT_MAX); sva = talloc(1, SVA); sva->n_max = n_max; sva->n = 0; sva->ptr = talloc(1+n_max, int); sva->len = talloc(1+n_max, int); sva->cap = talloc(1+n_max, int); sva->size = size; sva->m_ptr = 1; sva->r_ptr = size+1; sva->head = sva->tail = 0; sva->prev = talloc(1+n_max, int); sva->next = talloc(1+n_max, int); sva->ind = talloc(1+size, int); sva->val = talloc(1+size, double); sva->talky = 0; return sva; } /*********************************************************************** * sva_alloc_vecs - allocate new vectors in SVA * * This routine allocates nnn new empty vectors, nnn > 0, in the sparse * vector area (SVA). * * The new vectors are assigned reference numbers k, k+1, ..., k+nnn-1, * where k is a reference number assigned to the very first new vector, * which is returned by the routine on exit. */ int sva_alloc_vecs(SVA *sva, int nnn) { int n = sva->n; int n_max = sva->n_max; int *ptr = sva->ptr; int *len = sva->len; int *cap = sva->cap; int *prev = sva->prev; int *next = sva->next; int k, new_n; #if 1 if (sva->talky) xprintf("sva_alloc_vecs: nnn = %d\n", nnn); #endif xassert(nnn > 0); /* determine new number of vectors in SVA */ new_n = n + nnn; xassert(new_n > n); if (n_max < new_n) { /* enlarge the SVA arrays */ while (n_max < new_n) { n_max += n_max; xassert(n_max > 0); } sva->n_max = n_max; sva->ptr = ptr = trealloc(ptr, 1+n_max, int); sva->len = len = trealloc(len, 1+n_max, int); sva->cap = cap = trealloc(cap, 1+n_max, int); sva->prev = prev = trealloc(prev, 1+n_max, int); sva->next = next = trealloc(next, 1+n_max, int); } /* initialize new vectors */ sva->n = new_n; for (k = n+1; k <= new_n; k++) { ptr[k] = len[k] = cap[k] = 0; prev[k] = next[k] = -1; } #if 1 if (sva->talky) xprintf("now sva->n_max = %d, sva->n = %d\n", sva->n_max, sva->n); #endif /* return reference number of very first new vector */ return n+1; } /*********************************************************************** * sva_resize_area - change size of SVA storage * * This routine increases or decrases the size of the SVA storage by * reallocating it. * * The parameter delta specifies the number of location by which the * current size of the SVA storage should be increased (if delta > 0) * or decreased (if delta < 0). Note that if delta is negative, it * should not be less than the current size of the middle part. * * As a result of this operation the size of the middle part of SVA is * increased/decreased by delta locations. * * NOTE: This operation changes ptr[k] for all vectors stored in the * right part of SVA. */ void sva_resize_area(SVA *sva, int delta) { int n = sva->n; int *ptr = sva->ptr; int size = sva->size; int m_ptr = sva->m_ptr; int r_ptr = sva->r_ptr; int k, r_size; #if 1 if (sva->talky) xprintf("sva_resize_area: delta = %d\n", delta); #endif xassert(delta != 0); /* determine size of the right part, in locations */ r_size = size - r_ptr + 1; /* relocate the right part in case of negative delta */ if (delta < 0) { xassert(delta >= m_ptr - r_ptr); sva->r_ptr += delta; memmove(&sva->ind[sva->r_ptr], &sva->ind[r_ptr], r_size * sizeof(int)); memmove(&sva->val[sva->r_ptr], &sva->val[r_ptr], r_size * sizeof(double)); } /* reallocate the storage arrays */ xassert(delta < INT_MAX - sva->size); sva->size += delta; sva->ind = trealloc(sva->ind, 1+sva->size, int); sva->val = trealloc(sva->val, 1+sva->size, double); /* relocate the right part in case of positive delta */ if (delta > 0) { sva->r_ptr += delta; memmove(&sva->ind[sva->r_ptr], &sva->ind[r_ptr], r_size * sizeof(int)); memmove(&sva->val[sva->r_ptr], &sva->val[r_ptr], r_size * sizeof(double)); } /* update pointers to vectors stored in the right part */ for (k = 1; k <= n; k++) { if (ptr[k] >= r_ptr) ptr[k] += delta; } #if 1 if (sva->talky) xprintf("now sva->size = %d\n", sva->size); #endif return; } /*********************************************************************** * sva_defrag_area - defragment left part of SVA * * This routine performs "garbage" collection to defragment the left * part of SVA. * * NOTE: This operation may change ptr[k] and cap[k] for all vectors * stored in the left part of SVA. */ void sva_defrag_area(SVA *sva) { int *ptr = sva->ptr; int *len = sva->len; int *cap = sva->cap; int *prev = sva->prev; int *next = sva->next; int *ind = sva->ind; double *val = sva->val; int k, next_k, ptr_k, len_k, m_ptr, head, tail; #if 1 if (sva->talky) { xprintf("sva_defrag_area:\n"); xprintf("before defragmenting = %d %d %d\n", sva->m_ptr - 1, sva->r_ptr - sva->m_ptr, sva->size + 1 - sva->r_ptr); } #endif m_ptr = 1; head = tail = 0; /* walk through the linked list of vectors stored in the left * part of SVA */ for (k = sva->head; k != 0; k = next_k) { /* save number of next vector in the list */ next_k = next[k]; /* determine length of k-th vector */ len_k = len[k]; if (len_k == 0) { /* k-th vector is empty; remove it from the left part */ ptr[k] = cap[k] = 0; prev[k] = next[k] = -1; } else { /* determine pointer to first location of k-th vector */ ptr_k = ptr[k]; xassert(m_ptr <= ptr_k); /* relocate k-th vector to the beginning of the left part, * if necessary */ if (m_ptr < ptr_k) { memmove(&ind[m_ptr], &ind[ptr_k], len_k * sizeof(int)); memmove(&val[m_ptr], &val[ptr_k], len_k * sizeof(double)); ptr[k] = m_ptr; } /* remove unused locations from k-th vector */ cap[k] = len_k; /* the left part of SVA has been enlarged */ m_ptr += len_k; /* add k-th vector to the end of the new linked list */ prev[k] = tail; next[k] = 0; if (head == 0) head = k; else next[tail] = k; tail = k; } } /* set new pointer to the middle part of SVA */ xassert(m_ptr <= sva->r_ptr); sva->m_ptr = m_ptr; /* set new head and tail of the linked list */ sva->head = head; sva->tail = tail; #if 1 if (sva->talky) xprintf("after defragmenting = %d %d %d\n", sva->m_ptr - 1, sva->r_ptr - sva->m_ptr, sva->size + 1 - sva->r_ptr); #endif return; } /*********************************************************************** * sva_more_space - increase size of middle (free) part of SVA * * This routine increases the size of the middle (free) part of the * sparse vector area (SVA). * * The parameter m_size specifies the minimal size, in locations, of * the middle part to be provided. This new size should be greater than * the current size of the middle part. * * First, the routine defragments the left part of SVA. Then, if the * size of the left part has not sufficiently increased, the routine * increases the total size of the SVA storage by reallocating it. */ void sva_more_space(SVA *sva, int m_size) { int size, delta; #if 1 if (sva->talky) xprintf("sva_more_space: m_size = %d\n", m_size); #endif xassert(m_size > sva->r_ptr - sva->m_ptr); /* defragment the left part */ sva_defrag_area(sva); /* set, heuristically, the minimal size of the middle part to be * not less than the size of the defragmented left part */ if (m_size < sva->m_ptr - 1) m_size = sva->m_ptr - 1; /* if there is still not enough room, increase the total size of * the SVA storage */ if (sva->r_ptr - sva->m_ptr < m_size) { size = sva->size; /* new sva size */ for (;;) { delta = size - sva->size; if (sva->r_ptr - sva->m_ptr + delta >= m_size) break; size += size; xassert(size > 0); } sva_resize_area(sva, delta); xassert(sva->r_ptr - sva->m_ptr >= m_size); } return; } /*********************************************************************** * sva_enlarge_cap - enlarge capacity of specified vector * * This routine enlarges the current capacity of the specified vector * by relocating its content. * * The parameter k specifies the reference number of the vector whose * capacity should be enlarged, 1 <= k <= n. This vector should either * have zero capacity or be stored in the left (dynamic) part of SVA. * * The parameter new_cap specifies the new capacity of the vector, * in locations. This new capacity should be greater than the current * capacity of the vector. * * The parameter skip is a flag. If this flag is set, the routine does * *not* copy numerical values of elements of the vector on relocating * its content, i.e. only element indices are copied. * * NOTE: On entry to the routine the middle part of SVA should have at * least new_cap free locations. */ void sva_enlarge_cap(SVA *sva, int k, int new_cap, int skip) { int *ptr = sva->ptr; int *len = sva->len; int *cap = sva->cap; int *prev = sva->prev; int *next = sva->next; int *ind = sva->ind; double *val = sva->val; xassert(1 <= k && k <= sva->n); xassert(new_cap > cap[k]); /* there should be at least new_cap free locations */ xassert(sva->r_ptr - sva->m_ptr >= new_cap); /* relocate the vector */ if (cap[k] == 0) { /* the vector is empty */ xassert(ptr[k] == 0); xassert(len[k] == 0); } else { /* the vector has non-zero capacity */ xassert(ptr[k] + len[k] <= sva->m_ptr); /* copy the current vector content to the beginning of the * middle part */ if (len[k] > 0) { memcpy(&ind[sva->m_ptr], &ind[ptr[k]], len[k] * sizeof(int)); if (!skip) memcpy(&val[sva->m_ptr], &val[ptr[k]], len[k] * sizeof(double)); } /* remove the vector from the linked list */ if (prev[k] == 0) sva->head = next[k]; else { /* preceding vector exists; increase its capacity */ cap[prev[k]] += cap[k]; next[prev[k]] = next[k]; } if (next[k] == 0) sva->tail = prev[k]; else prev[next[k]] = prev[k]; } /* set new pointer and capacity of the vector */ ptr[k] = sva->m_ptr; cap[k] = new_cap; /* add the vector to the end of the linked list */ prev[k] = sva->tail; next[k] = 0; if (sva->head == 0) sva->head = k; else next[sva->tail] = k; sva->tail = k; /* new_cap free locations have been consumed */ sva->m_ptr += new_cap; xassert(sva->m_ptr <= sva->r_ptr); return; } /*********************************************************************** * sva_reserve_cap - reserve locations for specified vector * * This routine reserves locations for the specified vector in the * right (static) part of SVA. * * The parameter k specifies the reference number of the vector (this * vector should have zero capacity), 1 <= k <= n. * * The parameter new_cap specifies a non-zero capacity of the vector, * in locations. * * NOTE: On entry to the routine the middle part of SVA should have at * least new_cap free locations. */ void sva_reserve_cap(SVA *sva, int k, int new_cap) { int *ptr = sva->ptr; int *len = sva->len; int *cap = sva->cap; xassert(1 <= k && k <= sva->n); xassert(new_cap > 0); xassert(ptr[k] == 0 && len[k] == 0 && cap[k] == 0); /* there should be at least new_cap free locations */ xassert(sva->r_ptr - sva->m_ptr >= new_cap); /* set the pointer and capacity of the vector */ ptr[k] = sva->r_ptr - new_cap; cap[k] = new_cap; /* new_cap free locations have been consumed */ sva->r_ptr -= new_cap; return; } /*********************************************************************** * sva_make_static - relocate specified vector to right part of SVA * * Assuming that the specified vector is stored in the left (dynamic) * part of SVA, this routine makes the vector static by relocating its * content to the right (static) part of SVA. However, if the specified * vector has zero capacity, the routine does nothing. * * The parameter k specifies the reference number of the vector to be * relocated, 1 <= k <= n. * * NOTE: On entry to the routine the middle part of SVA should have at * least len[k] free locations, where len[k] is the length of the * vector to be relocated. */ void sva_make_static(SVA *sva, int k) { int *ptr = sva->ptr; int *len = sva->len; int *cap = sva->cap; int *prev = sva->prev; int *next = sva->next; int *ind = sva->ind; double *val = sva->val; int ptr_k, len_k; xassert(1 <= k && k <= sva->n); /* if the vector has zero capacity, do nothing */ if (cap[k] == 0) { xassert(ptr[k] == 0); xassert(len[k] == 0); goto done; } /* there should be at least len[k] free locations */ len_k = len[k]; xassert(sva->r_ptr - sva->m_ptr >= len_k); /* remove the vector from the linked list */ if (prev[k] == 0) sva->head = next[k]; else { /* preceding vector exists; increase its capacity */ cap[prev[k]] += cap[k]; next[prev[k]] = next[k]; } if (next[k] == 0) sva->tail = prev[k]; else prev[next[k]] = prev[k]; /* if the vector has zero length, make it empty */ if (len_k == 0) { ptr[k] = cap[k] = 0; goto done; } /* copy the vector content to the beginning of the right part */ ptr_k = sva->r_ptr - len_k; memcpy(&ind[ptr_k], &ind[ptr[k]], len_k * sizeof(int)); memcpy(&val[ptr_k], &val[ptr[k]], len_k * sizeof(double)); /* set new pointer and capacity of the vector */ ptr[k] = ptr_k; cap[k] = len_k; /* len[k] free locations have been consumed */ sva->r_ptr -= len_k; done: return; } /*********************************************************************** * sva_check_area - check sparse vector area (SVA) * * This routine checks the SVA data structures for correctness. * * NOTE: For testing/debugging only. */ void sva_check_area(SVA *sva) { int n_max = sva->n_max; int n = sva->n; int *ptr = sva->ptr; int *len = sva->len; int *cap = sva->cap; int size = sva->size; int m_ptr = sva->m_ptr; int r_ptr = sva->r_ptr; int head = sva->head; int tail = sva->tail; int *prev = sva->prev; int *next = sva->next; int k; xassert(1 <= n && n <= n_max); xassert(1 <= m_ptr && m_ptr <= r_ptr && r_ptr <= size+1); /* all vectors included the linked list should have non-zero * capacity and be stored in the left part */ for (k = head; k != 0; k = next[k]) { xassert(1 <= k && k <= n); xassert(cap[k] > 0); xassert(0 <= len[k] && len[k] <= cap[k]); if (prev[k] == 0) xassert(k == head); else { xassert(1 <= prev[k] && prev[k] <= n); xassert(next[prev[k]] == k); } if (next[k] == 0) { xassert(k == tail); xassert(ptr[k] + cap[k] <= m_ptr); } else { xassert(1 <= next[k] && next[k] <= n); xassert(prev[next[k]] == k); xassert(ptr[k] + cap[k] <= ptr[next[k]]); } cap[k] = -cap[k]; } /* all other vectors should either have zero capacity or be * stored in the right part */ for (k = 1; k <= n; k++) { if (cap[k] < 0) { /* k-th vector is stored in the left part */ cap[k] = -cap[k]; } else if (cap[k] == 0) { /* k-th vector has zero capacity */ xassert(ptr[k] == 0); xassert(len[k] == 0); } else /* cap[k] > 0 */ { /* k-th vector is stored in the right part */ xassert(0 <= len[k] && len[k] <= cap[k]); xassert(r_ptr <= ptr[k] && ptr[k] + cap[k] <= size+1); } } return; } /*********************************************************************** * sva_delete_area - delete sparse vector area (SVA) * * This routine deletes the sparse vector area (SVA) freeing all the * memory allocated to it. */ void sva_delete_area(SVA *sva) { tfree(sva->ptr); tfree(sva->len); tfree(sva->cap); tfree(sva->prev); tfree(sva->next); tfree(sva->ind); tfree(sva->val); tfree(sva); return; } /* eof */ Rglpk/src/GLPK/jd.h0000644000176000001440000000242712245352174013465 0ustar ripleyusers/* jd.h (conversions between calendar date and Julian day number) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #define jday _glp_jday int jday(int d, int m, int y); /* convert calendar date to Julian day number */ #define jdate _glp_jdate int jdate(int j, int *d, int *m, int *y); /* convert Julian day number to calendar date */ /* eof */ Rglpk/src/GLPK/glpmpl02.c0000644000176000001440000013073312245352174014522 0ustar ripleyusers/* glpmpl02.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #define _GLPSTD_STDIO #include "env.h" #include "glpmpl.h" /**********************************************************************/ /* * * PROCESSING DATA SECTION * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- create_slice - create slice. -- -- This routine creates a slice, which initially has no components. */ SLICE *create_slice(MPL *mpl) { SLICE *slice; xassert(mpl == mpl); slice = NULL; return slice; } /*---------------------------------------------------------------------- -- expand_slice - append new component to slice. -- -- This routine expands slice appending to it either a given symbol or -- null component, which becomes the last component of the slice. */ SLICE *expand_slice ( MPL *mpl, SLICE *slice, /* destroyed */ SYMBOL *sym /* destroyed */ ) { SLICE *tail, *temp; /* create a new component */ tail = dmp_get_atom(mpl->tuples, sizeof(SLICE)); tail->sym = sym; tail->next = NULL; /* and append it to the component list */ if (slice == NULL) slice = tail; else { for (temp = slice; temp->next != NULL; temp = temp->next); temp->next = tail; } return slice; } /*---------------------------------------------------------------------- -- slice_dimen - determine dimension of slice. -- -- This routine returns dimension of slice, which is number of all its -- components including null ones. */ int slice_dimen ( MPL *mpl, SLICE *slice /* not changed */ ) { SLICE *temp; int dim; xassert(mpl == mpl); dim = 0; for (temp = slice; temp != NULL; temp = temp->next) dim++; return dim; } /*---------------------------------------------------------------------- -- slice_arity - determine arity of slice. -- -- This routine returns arity of slice, i.e. number of null components -- (indicated by asterisks) in the slice. */ int slice_arity ( MPL *mpl, SLICE *slice /* not changed */ ) { SLICE *temp; int arity; xassert(mpl == mpl); arity = 0; for (temp = slice; temp != NULL; temp = temp->next) if (temp->sym == NULL) arity++; return arity; } /*---------------------------------------------------------------------- -- fake_slice - create fake slice of all asterisks. -- -- This routine creates a fake slice of given dimension, which contains -- asterisks in all components. Zero dimension is allowed. */ SLICE *fake_slice(MPL *mpl, int dim) { SLICE *slice; slice = create_slice(mpl); while (dim-- > 0) slice = expand_slice(mpl, slice, NULL); return slice; } /*---------------------------------------------------------------------- -- delete_slice - delete slice. -- -- This routine deletes specified slice. */ void delete_slice ( MPL *mpl, SLICE *slice /* destroyed */ ) { SLICE *temp; while (slice != NULL) { temp = slice; slice = temp->next; if (temp->sym != NULL) delete_symbol(mpl, temp->sym); xassert(sizeof(SLICE) == sizeof(TUPLE)); dmp_free_atom(mpl->tuples, temp, sizeof(TUPLE)); } return; } /*---------------------------------------------------------------------- -- is_number - check if current token is number. -- -- If the current token is a number, this routine returns non-zero. -- Otherwise zero is returned. */ int is_number(MPL *mpl) { return mpl->token == T_NUMBER; } /*---------------------------------------------------------------------- -- is_symbol - check if current token is symbol. -- -- If the current token is suitable to be a symbol, the routine returns -- non-zero. Otherwise zero is returned. */ int is_symbol(MPL *mpl) { return mpl->token == T_NUMBER || mpl->token == T_SYMBOL || mpl->token == T_STRING; } /*---------------------------------------------------------------------- -- is_literal - check if current token is given symbolic literal. -- -- If the current token is given symbolic literal, this routine returns -- non-zero. Otherwise zero is returned. -- -- This routine is used on processing the data section in the same way -- as the routine is_keyword on processing the model section. */ int is_literal(MPL *mpl, char *literal) { return is_symbol(mpl) && strcmp(mpl->image, literal) == 0; } /*---------------------------------------------------------------------- -- read_number - read number. -- -- This routine reads the current token, which must be a number, and -- returns its numeric value. */ double read_number(MPL *mpl) { double num; xassert(is_number(mpl)); num = mpl->value; get_token(mpl /* */); return num; } /*---------------------------------------------------------------------- -- read_symbol - read symbol. -- -- This routine reads the current token, which must be a symbol, and -- returns its symbolic value. */ SYMBOL *read_symbol(MPL *mpl) { SYMBOL *sym; xassert(is_symbol(mpl)); if (is_number(mpl)) sym = create_symbol_num(mpl, mpl->value); else sym = create_symbol_str(mpl, create_string(mpl, mpl->image)); get_token(mpl /* */); return sym; } /*---------------------------------------------------------------------- -- read_slice - read slice. -- -- This routine reads slice using the syntax: -- -- ::= [ ] -- ::= ( ) -- ::= -- ::= , -- ::= -- ::= * -- -- The bracketed form of slice is used for members of multi-dimensional -- objects while the parenthesized form is used for elemental sets. */ SLICE *read_slice ( MPL *mpl, char *name, /* not changed */ int dim ) { SLICE *slice; int close; xassert(name != NULL); switch (mpl->token) { case T_LBRACKET: close = T_RBRACKET; break; case T_LEFT: xassert(dim > 0); close = T_RIGHT; break; default: xassert(mpl != mpl); } if (dim == 0) error(mpl, "%s cannot be subscripted", name); get_token(mpl /* ( | [ */); /* read slice components */ slice = create_slice(mpl); for (;;) { /* the current token must be a symbol or asterisk */ if (is_symbol(mpl)) slice = expand_slice(mpl, slice, read_symbol(mpl)); else if (mpl->token == T_ASTERISK) { slice = expand_slice(mpl, slice, NULL); get_token(mpl /* * */); } else error(mpl, "number, symbol, or asterisk missing where expec" "ted"); /* check a token that follows the symbol */ if (mpl->token == T_COMMA) get_token(mpl /* , */); else if (mpl->token == close) break; else error(mpl, "syntax error in slice"); } /* number of slice components must be the same as the appropriate dimension */ if (slice_dimen(mpl, slice) != dim) { switch (close) { case T_RBRACKET: error(mpl, "%s must have %d subscript%s, not %d", name, dim, dim == 1 ? "" : "s", slice_dimen(mpl, slice)); break; case T_RIGHT: error(mpl, "%s has dimension %d, not %d", name, dim, slice_dimen(mpl, slice)); break; default: xassert(close != close); } } get_token(mpl /* ) | ] */); return slice; } /*---------------------------------------------------------------------- -- select_set - select set to saturate it with elemental sets. -- -- This routine selects set to saturate it with elemental sets provided -- in the data section. */ SET *select_set ( MPL *mpl, char *name /* not changed */ ) { SET *set; AVLNODE *node; xassert(name != NULL); node = avl_find_node(mpl->tree, name); if (node == NULL || avl_get_node_type(node) != A_SET) error(mpl, "%s not a set", name); set = (SET *)avl_get_node_link(node); if (set->assign != NULL || set->gadget != NULL) error(mpl, "%s needs no data", name); set->data = 1; return set; } /*---------------------------------------------------------------------- -- simple_format - read set data block in simple format. -- -- This routine reads set data block using the syntax: -- -- ::= , , ... , -- -- where are used to construct a complete n-tuple, which is -- included in elemental set assigned to the set member. Commae between -- symbols are optional and may be omitted anywhere. -- -- Number of components in the slice must be the same as dimension of -- n-tuples in elemental sets assigned to the set members. To construct -- complete n-tuple the routine replaces null positions in the slice by -- corresponding . -- -- If the slice contains at least one null position, the current token -- must be symbol. Otherwise, the routine reads no symbols to construct -- the n-tuple, so the current token is not checked. */ void simple_format ( MPL *mpl, SET *set, /* not changed */ MEMBER *memb, /* modified */ SLICE *slice /* not changed */ ) { TUPLE *tuple; SLICE *temp; SYMBOL *sym, *with = NULL; xassert(set != NULL); xassert(memb != NULL); xassert(slice != NULL); xassert(set->dimen == slice_dimen(mpl, slice)); xassert(memb->value.set->dim == set->dimen); if (slice_arity(mpl, slice) > 0) xassert(is_symbol(mpl)); /* read symbols and construct complete n-tuple */ tuple = create_tuple(mpl); for (temp = slice; temp != NULL; temp = temp->next) { if (temp->sym == NULL) { /* substitution is needed; read symbol */ if (!is_symbol(mpl)) { int lack = slice_arity(mpl, temp); /* with cannot be null due to assertion above */ xassert(with != NULL); if (lack == 1) error(mpl, "one item missing in data group beginning " "with %s", format_symbol(mpl, with)); else error(mpl, "%d items missing in data group beginning " "with %s", lack, format_symbol(mpl, with)); } sym = read_symbol(mpl); if (with == NULL) with = sym; } else { /* copy symbol from the slice */ sym = copy_symbol(mpl, temp->sym); } /* append the symbol to the n-tuple */ tuple = expand_tuple(mpl, tuple, sym); /* skip optional comma *between* */ if (temp->next != NULL && mpl->token == T_COMMA) get_token(mpl /* , */); } /* add constructed n-tuple to elemental set */ check_then_add(mpl, memb->value.set, tuple); return; } /*---------------------------------------------------------------------- -- matrix_format - read set data block in matrix format. -- -- This routine reads set data block using the syntax: -- -- ::= ... := -- +/- +/- ... +/- -- +/- +/- ... +/- -- . . . . . . . . . . . -- +/- +/- ... +/- -- -- where are symbols that denote rows of the matrix, -- are symbols that denote columns of the matrix, "+" and "-" indicate -- whether corresponding n-tuple needs to be included in the elemental -- set or not, respectively. -- -- Number of the slice components must be the same as dimension of the -- elemental set. The slice must have two null positions. To construct -- complete n-tuple for particular element of the matrix the routine -- replaces first null position of the slice by the corresponding -- (or , if the flag tr is on) and second null position by the -- corresponding (or by , if the flag tr is on). */ void matrix_format ( MPL *mpl, SET *set, /* not changed */ MEMBER *memb, /* modified */ SLICE *slice, /* not changed */ int tr ) { SLICE *list, *col, *temp; TUPLE *tuple; SYMBOL *row; xassert(set != NULL); xassert(memb != NULL); xassert(slice != NULL); xassert(set->dimen == slice_dimen(mpl, slice)); xassert(memb->value.set->dim == set->dimen); xassert(slice_arity(mpl, slice) == 2); /* read the matrix heading that contains column symbols (there may be no columns at all) */ list = create_slice(mpl); while (mpl->token != T_ASSIGN) { /* read column symbol and append it to the column list */ if (!is_symbol(mpl)) error(mpl, "number, symbol, or := missing where expected"); list = expand_slice(mpl, list, read_symbol(mpl)); } get_token(mpl /* := */); /* read zero or more rows that contain matrix data */ while (is_symbol(mpl)) { /* read row symbol (if the matrix has no columns, row symbols are just ignored) */ row = read_symbol(mpl); /* read the matrix row accordingly to the column list */ for (col = list; col != NULL; col = col->next) { int which = 0; /* check indicator */ if (is_literal(mpl, "+")) ; else if (is_literal(mpl, "-")) { get_token(mpl /* - */); continue; } else { int lack = slice_dimen(mpl, col); if (lack == 1) error(mpl, "one item missing in data group beginning " "with %s", format_symbol(mpl, row)); else error(mpl, "%d items missing in data group beginning " "with %s", lack, format_symbol(mpl, row)); } /* construct complete n-tuple */ tuple = create_tuple(mpl); for (temp = slice; temp != NULL; temp = temp->next) { if (temp->sym == NULL) { /* substitution is needed */ switch (++which) { case 1: /* substitute in the first null position */ tuple = expand_tuple(mpl, tuple, copy_symbol(mpl, tr ? col->sym : row)); break; case 2: /* substitute in the second null position */ tuple = expand_tuple(mpl, tuple, copy_symbol(mpl, tr ? row : col->sym)); break; default: xassert(which != which); } } else { /* copy symbol from the slice */ tuple = expand_tuple(mpl, tuple, copy_symbol(mpl, temp->sym)); } } xassert(which == 2); /* add constructed n-tuple to elemental set */ check_then_add(mpl, memb->value.set, tuple); get_token(mpl /* + */); } /* delete the row symbol */ delete_symbol(mpl, row); } /* delete the column list */ delete_slice(mpl, list); return; } /*---------------------------------------------------------------------- -- set_data - read set data. -- -- This routine reads set data using the syntax: -- -- ::= set ; -- ::= set [ ] ; -- ::= -- ::= -- ::= , := -- ::= , ( ) -- ::= , -- ::= , : -- ::= , (tr) -- ::= , (tr) : -- -- Commae in are optional and may be omitted anywhere. */ void set_data(MPL *mpl) { SET *set; TUPLE *tuple; MEMBER *memb; SLICE *slice; int tr = 0; xassert(is_literal(mpl, "set")); get_token(mpl /* set */); /* symbolic name of set must follows the keyword 'set' */ if (!is_symbol(mpl)) error(mpl, "set name missing where expected"); /* select the set to saturate it with data */ set = select_set(mpl, mpl->image); get_token(mpl /* */); /* read optional subscript list, which identifies member of the set to be read */ tuple = create_tuple(mpl); if (mpl->token == T_LBRACKET) { /* subscript list is specified */ if (set->dim == 0) error(mpl, "%s cannot be subscripted", set->name); get_token(mpl /* [ */); /* read symbols and construct subscript list */ for (;;) { if (!is_symbol(mpl)) error(mpl, "number or symbol missing where expected"); tuple = expand_tuple(mpl, tuple, read_symbol(mpl)); if (mpl->token == T_COMMA) get_token(mpl /* , */); else if (mpl->token == T_RBRACKET) break; else error(mpl, "syntax error in subscript list"); } if (set->dim != tuple_dimen(mpl, tuple)) error(mpl, "%s must have %d subscript%s rather than %d", set->name, set->dim, set->dim == 1 ? "" : "s", tuple_dimen(mpl, tuple)); get_token(mpl /* ] */); } else { /* subscript list is not specified */ if (set->dim != 0) error(mpl, "%s must be subscripted", set->name); } /* there must be no member with the same subscript list */ if (find_member(mpl, set->array, tuple) != NULL) error(mpl, "%s%s already defined", set->name, format_tuple(mpl, '[', tuple)); /* add new member to the set and assign it empty elemental set */ memb = add_member(mpl, set->array, tuple); memb->value.set = create_elemset(mpl, set->dimen); /* create an initial fake slice of all asterisks */ slice = fake_slice(mpl, set->dimen); /* read zero or more data assignments */ for (;;) { /* skip optional comma */ if (mpl->token == T_COMMA) get_token(mpl /* , */); /* process assignment element */ if (mpl->token == T_ASSIGN) { /* assignment ligature is non-significant element */ get_token(mpl /* := */); } else if (mpl->token == T_LEFT) { /* left parenthesis begins either new slice or "transpose" indicator */ int is_tr; get_token(mpl /* ( */); is_tr = is_literal(mpl, "tr"); unget_token(mpl /* ( */); if (is_tr) goto left; /* delete the current slice and read new one */ delete_slice(mpl, slice); slice = read_slice(mpl, set->name, set->dimen); /* each new slice resets the "transpose" indicator */ tr = 0; /* if the new slice is 0-ary, formally there is one 0-tuple (in the simple format) that follows it */ if (slice_arity(mpl, slice) == 0) simple_format(mpl, set, memb, slice); } else if (is_symbol(mpl)) { /* number or symbol begins data in the simple format */ simple_format(mpl, set, memb, slice); } else if (mpl->token == T_COLON) { /* colon begins data in the matrix format */ if (slice_arity(mpl, slice) != 2) err1: error(mpl, "slice currently used must specify 2 asterisk" "s, not %d", slice_arity(mpl, slice)); get_token(mpl /* : */); /* read elemental set data in the matrix format */ matrix_format(mpl, set, memb, slice, tr); } else if (mpl->token == T_LEFT) left: { /* left parenthesis begins the "transpose" indicator, which is followed by data in the matrix format */ get_token(mpl /* ( */); if (!is_literal(mpl, "tr")) err2: error(mpl, "transpose indicator (tr) incomplete"); if (slice_arity(mpl, slice) != 2) goto err1; get_token(mpl /* tr */); if (mpl->token != T_RIGHT) goto err2; get_token(mpl /* ) */); /* in this case the colon is optional */ if (mpl->token == T_COLON) get_token(mpl /* : */); /* set the "transpose" indicator */ tr = 1; /* read elemental set data in the matrix format */ matrix_format(mpl, set, memb, slice, tr); } else if (mpl->token == T_SEMICOLON) { /* semicolon terminates the data block */ get_token(mpl /* ; */); break; } else error(mpl, "syntax error in set data block"); } /* delete the current slice */ delete_slice(mpl, slice); return; } /*---------------------------------------------------------------------- -- select_parameter - select parameter to saturate it with data. -- -- This routine selects parameter to saturate it with data provided in -- the data section. */ PARAMETER *select_parameter ( MPL *mpl, char *name /* not changed */ ) { PARAMETER *par; AVLNODE *node; xassert(name != NULL); node = avl_find_node(mpl->tree, name); if (node == NULL || avl_get_node_type(node) != A_PARAMETER) error(mpl, "%s not a parameter", name); par = (PARAMETER *)avl_get_node_link(node); if (par->assign != NULL) error(mpl, "%s needs no data", name); if (par->data) error(mpl, "%s already provided with data", name); par->data = 1; return par; } /*---------------------------------------------------------------------- -- set_default - set default parameter value. -- -- This routine sets default value for specified parameter. */ void set_default ( MPL *mpl, PARAMETER *par, /* not changed */ SYMBOL *altval /* destroyed */ ) { xassert(par != NULL); xassert(altval != NULL); if (par->option != NULL) error(mpl, "default value for %s already specified in model se" "ction", par->name); xassert(par->defval == NULL); par->defval = altval; return; } /*---------------------------------------------------------------------- -- read_value - read value and assign it to parameter member. -- -- This routine reads numeric or symbolic value from the input stream -- and assigns to new parameter member specified by its n-tuple, which -- (the member) is created and added to the parameter array. */ MEMBER *read_value ( MPL *mpl, PARAMETER *par, /* not changed */ TUPLE *tuple /* destroyed */ ) { MEMBER *memb; xassert(par != NULL); xassert(is_symbol(mpl)); /* there must be no member with the same n-tuple */ if (find_member(mpl, par->array, tuple) != NULL) error(mpl, "%s%s already defined", par->name, format_tuple(mpl, '[', tuple)); /* create new parameter member with given n-tuple */ memb = add_member(mpl, par->array, tuple); /* read value and assigns it to the new parameter member */ switch (par->type) { case A_NUMERIC: case A_INTEGER: case A_BINARY: if (!is_number(mpl)) error(mpl, "%s requires numeric data", par->name); memb->value.num = read_number(mpl); break; case A_SYMBOLIC: memb->value.sym = read_symbol(mpl); break; default: xassert(par != par); } return memb; } /*---------------------------------------------------------------------- -- plain_format - read parameter data block in plain format. -- -- This routine reads parameter data block using the syntax: -- -- ::= , , ... , , -- -- where are used to determine a complete subscript list for -- parameter member, is a numeric or symbolic value assigned to -- the parameter member. Commae between data items are optional and may -- be omitted anywhere. -- -- Number of components in the slice must be the same as dimension of -- the parameter. To construct the complete subscript list the routine -- replaces null positions in the slice by corresponding . */ void plain_format ( MPL *mpl, PARAMETER *par, /* not changed */ SLICE *slice /* not changed */ ) { TUPLE *tuple; SLICE *temp; SYMBOL *sym, *with = NULL; xassert(par != NULL); xassert(par->dim == slice_dimen(mpl, slice)); xassert(is_symbol(mpl)); /* read symbols and construct complete subscript list */ tuple = create_tuple(mpl); for (temp = slice; temp != NULL; temp = temp->next) { if (temp->sym == NULL) { /* substitution is needed; read symbol */ if (!is_symbol(mpl)) { int lack = slice_arity(mpl, temp) + 1; xassert(with != NULL); xassert(lack > 1); error(mpl, "%d items missing in data group beginning wit" "h %s", lack, format_symbol(mpl, with)); } sym = read_symbol(mpl); if (with == NULL) with = sym; } else { /* copy symbol from the slice */ sym = copy_symbol(mpl, temp->sym); } /* append the symbol to the subscript list */ tuple = expand_tuple(mpl, tuple, sym); /* skip optional comma */ if (mpl->token == T_COMMA) get_token(mpl /* , */); } /* read value and assign it to new parameter member */ if (!is_symbol(mpl)) { xassert(with != NULL); error(mpl, "one item missing in data group beginning with %s", format_symbol(mpl, with)); } read_value(mpl, par, tuple); return; } /*---------------------------------------------------------------------- -- tabular_format - read parameter data block in tabular format. -- -- This routine reads parameter data block using the syntax: -- -- ::= ... := -- ... -- ... -- . . . . . . . . . . . -- ... -- -- where are symbols that denote rows of the table, -- are symbols that denote columns of the table, are numeric -- or symbolic values assigned to the corresponding parameter members. -- If is specified as single point, no value is provided. -- -- Number of components in the slice must be the same as dimension of -- the parameter. The slice must have two null positions. To construct -- complete subscript list for particular the routine replaces -- the first null position of the slice by the corresponding (or -- , if the flag tr is on) and the second null position by the -- corresponding (or by , if the flag tr is on). */ void tabular_format ( MPL *mpl, PARAMETER *par, /* not changed */ SLICE *slice, /* not changed */ int tr ) { SLICE *list, *col, *temp; TUPLE *tuple; SYMBOL *row; xassert(par != NULL); xassert(par->dim == slice_dimen(mpl, slice)); xassert(slice_arity(mpl, slice) == 2); /* read the table heading that contains column symbols (the table may have no columns) */ list = create_slice(mpl); while (mpl->token != T_ASSIGN) { /* read column symbol and append it to the column list */ if (!is_symbol(mpl)) error(mpl, "number, symbol, or := missing where expected"); list = expand_slice(mpl, list, read_symbol(mpl)); } get_token(mpl /* := */); /* read zero or more rows that contain tabular data */ while (is_symbol(mpl)) { /* read row symbol (if the table has no columns, these symbols are just ignored) */ row = read_symbol(mpl); /* read values accordingly to the column list */ for (col = list; col != NULL; col = col->next) { int which = 0; /* if the token is single point, no value is provided */ if (is_literal(mpl, ".")) { get_token(mpl /* . */); continue; } /* construct complete subscript list */ tuple = create_tuple(mpl); for (temp = slice; temp != NULL; temp = temp->next) { if (temp->sym == NULL) { /* substitution is needed */ switch (++which) { case 1: /* substitute in the first null position */ tuple = expand_tuple(mpl, tuple, copy_symbol(mpl, tr ? col->sym : row)); break; case 2: /* substitute in the second null position */ tuple = expand_tuple(mpl, tuple, copy_symbol(mpl, tr ? row : col->sym)); break; default: xassert(which != which); } } else { /* copy symbol from the slice */ tuple = expand_tuple(mpl, tuple, copy_symbol(mpl, temp->sym)); } } xassert(which == 2); /* read value and assign it to new parameter member */ if (!is_symbol(mpl)) { int lack = slice_dimen(mpl, col); if (lack == 1) error(mpl, "one item missing in data group beginning " "with %s", format_symbol(mpl, row)); else error(mpl, "%d items missing in data group beginning " "with %s", lack, format_symbol(mpl, row)); } read_value(mpl, par, tuple); } /* delete the row symbol */ delete_symbol(mpl, row); } /* delete the column list */ delete_slice(mpl, list); return; } /*---------------------------------------------------------------------- -- tabbing_format - read parameter data block in tabbing format. -- -- This routine reads parameter data block using the syntax: -- -- ::= , ... , , := , -- , ... , , , ... , , -- , ... , , , ... , , -- . . . . . . . . . . . . . . . . . -- , ... , , , ... , -- ::= -- ::= : -- -- where are names of parameters (all the parameters must be -- subscripted and have identical dimensions), are symbols -- used to define subscripts of parameter members, are numeric -- or symbolic values assigned to the corresponding parameter members. -- Optional may specify a simple set, in which case n-tuples -- built of for each row of the data table (i.e. subscripts -- of parameter members) are added to the specified set. Commae between -- data items are optional and may be omitted anywhere. -- -- If the parameter altval is not NULL, it specifies a default value -- provided for all the parameters specified in the data block. */ void tabbing_format ( MPL *mpl, SYMBOL *altval /* not changed */ ) { SET *set = NULL; PARAMETER *par; SLICE *list, *col; TUPLE *tuple; int next_token, j, dim = 0; char *last_name = NULL; /* read the optional */ if (is_symbol(mpl)) { get_token(mpl /* */); next_token = mpl->token; unget_token(mpl /* */); if (next_token == T_COLON) { /* select the set to saturate it with data */ set = select_set(mpl, mpl->image); /* the set must be simple (i.e. not set of sets) */ if (set->dim != 0) error(mpl, "%s must be a simple set", set->name); /* and must not be defined yet */ if (set->array->head != NULL) error(mpl, "%s already defined", set->name); /* add new (the only) member to the set and assign it empty elemental set */ add_member(mpl, set->array, NULL)->value.set = create_elemset(mpl, set->dimen); last_name = set->name, dim = set->dimen; get_token(mpl /* */); xassert(mpl->token == T_COLON); get_token(mpl /* : */); } } /* read the table heading that contains parameter names */ list = create_slice(mpl); while (mpl->token != T_ASSIGN) { /* there must be symbolic name of parameter */ if (!is_symbol(mpl)) error(mpl, "parameter name or := missing where expected"); /* select the parameter to saturate it with data */ par = select_parameter(mpl, mpl->image); /* the parameter must be subscripted */ if (par->dim == 0) error(mpl, "%s not a subscripted parameter", mpl->image); /* the set (if specified) and all the parameters in the data block must have identical dimension */ if (dim != 0 && par->dim != dim) { xassert(last_name != NULL); error(mpl, "%s has dimension %d while %s has dimension %d", last_name, dim, par->name, par->dim); } /* set default value for the parameter (if specified) */ if (altval != NULL) set_default(mpl, par, copy_symbol(mpl, altval)); /* append the parameter to the column list */ list = expand_slice(mpl, list, (SYMBOL *)par); last_name = par->name, dim = par->dim; get_token(mpl /* */); /* skip optional comma */ if (mpl->token == T_COMMA) get_token(mpl /* , */); } if (slice_dimen(mpl, list) == 0) error(mpl, "at least one parameter name required"); get_token(mpl /* := */); /* skip optional comma */ if (mpl->token == T_COMMA) get_token(mpl /* , */); /* read rows that contain tabbing data */ while (is_symbol(mpl)) { /* read subscript list */ tuple = create_tuple(mpl); for (j = 1; j <= dim; j++) { /* read j-th subscript */ if (!is_symbol(mpl)) { int lack = slice_dimen(mpl, list) + dim - j + 1; xassert(tuple != NULL); xassert(lack > 1); error(mpl, "%d items missing in data group beginning wit" "h %s", lack, format_symbol(mpl, tuple->sym)); } /* read and append j-th subscript to the n-tuple */ tuple = expand_tuple(mpl, tuple, read_symbol(mpl)); /* skip optional comma *between* */ if (j < dim && mpl->token == T_COMMA) get_token(mpl /* , */); } /* if the set is specified, add to it new n-tuple, which is a copy of the subscript list just read */ if (set != NULL) check_then_add(mpl, set->array->head->value.set, copy_tuple(mpl, tuple)); /* skip optional comma between and */ if (mpl->token == T_COMMA) get_token(mpl /* , */); /* read values accordingly to the column list */ for (col = list; col != NULL; col = col->next) { /* if the token is single point, no value is provided */ if (is_literal(mpl, ".")) { get_token(mpl /* . */); continue; } /* read value and assign it to new parameter member */ if (!is_symbol(mpl)) { int lack = slice_dimen(mpl, col); xassert(tuple != NULL); if (lack == 1) error(mpl, "one item missing in data group beginning " "with %s", format_symbol(mpl, tuple->sym)); else error(mpl, "%d items missing in data group beginning " "with %s", lack, format_symbol(mpl, tuple->sym)); } read_value(mpl, (PARAMETER *)col->sym, copy_tuple(mpl, tuple)); /* skip optional comma preceding the next value */ if (col->next != NULL && mpl->token == T_COMMA) get_token(mpl /* , */); } /* delete the original subscript list */ delete_tuple(mpl, tuple); /* skip optional comma (only if there is next data group) */ if (mpl->token == T_COMMA) { get_token(mpl /* , */); if (!is_symbol(mpl)) unget_token(mpl /* , */); } } /* delete the column list (it contains parameters, not symbols, so nullify it before) */ for (col = list; col != NULL; col = col->next) col->sym = NULL; delete_slice(mpl, list); return; } /*---------------------------------------------------------------------- -- parameter_data - read parameter data. -- -- This routine reads parameter data using the syntax: -- -- ::= param : ; -- ::= param -- ; -- ::= -- ::= -- ::= default -- ::= -- ::= , := -- ::= , [ ] -- ::= , -- ::= , : -- ::= , (tr) -- ::= , (tr) : -- -- Commae in are optional and may be omitted anywhere. */ void parameter_data(MPL *mpl) { PARAMETER *par; SYMBOL *altval = NULL; SLICE *slice; int tr = 0; xassert(is_literal(mpl, "param")); get_token(mpl /* param */); /* read optional default value */ if (is_literal(mpl, "default")) { get_token(mpl /* default */); if (!is_symbol(mpl)) error(mpl, "default value missing where expected"); altval = read_symbol(mpl); /* if the default value follows the keyword 'param', the next token must be only the colon */ if (mpl->token != T_COLON) error(mpl, "colon missing where expected"); } /* being used after the keyword 'param' or the optional default value the colon begins data in the tabbing format */ if (mpl->token == T_COLON) { get_token(mpl /* : */); /* skip optional comma */ if (mpl->token == T_COMMA) get_token(mpl /* , */); /* read parameter data in the tabbing format */ tabbing_format(mpl, altval); /* on reading data in the tabbing format the default value is always copied, so delete the original symbol */ if (altval != NULL) delete_symbol(mpl, altval); /* the next token must be only semicolon */ if (mpl->token != T_SEMICOLON) error(mpl, "symbol, number, or semicolon missing where expe" "cted"); get_token(mpl /* ; */); goto done; } /* in other cases there must be symbolic name of parameter, which follows the keyword 'param' */ if (!is_symbol(mpl)) error(mpl, "parameter name missing where expected"); /* select the parameter to saturate it with data */ par = select_parameter(mpl, mpl->image); get_token(mpl /* */); /* read optional default value */ if (is_literal(mpl, "default")) { get_token(mpl /* default */); if (!is_symbol(mpl)) error(mpl, "default value missing where expected"); altval = read_symbol(mpl); /* set default value for the parameter */ set_default(mpl, par, altval); } /* create initial fake slice of all asterisks */ slice = fake_slice(mpl, par->dim); /* read zero or more data assignments */ for (;;) { /* skip optional comma */ if (mpl->token == T_COMMA) get_token(mpl /* , */); /* process current assignment */ if (mpl->token == T_ASSIGN) { /* assignment ligature is non-significant element */ get_token(mpl /* := */); } else if (mpl->token == T_LBRACKET) { /* left bracket begins new slice; delete the current slice and read new one */ delete_slice(mpl, slice); slice = read_slice(mpl, par->name, par->dim); /* each new slice resets the "transpose" indicator */ tr = 0; } else if (is_symbol(mpl)) { /* number or symbol begins data in the plain format */ plain_format(mpl, par, slice); } else if (mpl->token == T_COLON) { /* colon begins data in the tabular format */ if (par->dim == 0) err1: error(mpl, "%s not a subscripted parameter", par->name); if (slice_arity(mpl, slice) != 2) err2: error(mpl, "slice currently used must specify 2 asterisk" "s, not %d", slice_arity(mpl, slice)); get_token(mpl /* : */); /* read parameter data in the tabular format */ tabular_format(mpl, par, slice, tr); } else if (mpl->token == T_LEFT) { /* left parenthesis begins the "transpose" indicator, which is followed by data in the tabular format */ get_token(mpl /* ( */); if (!is_literal(mpl, "tr")) err3: error(mpl, "transpose indicator (tr) incomplete"); if (par->dim == 0) goto err1; if (slice_arity(mpl, slice) != 2) goto err2; get_token(mpl /* tr */); if (mpl->token != T_RIGHT) goto err3; get_token(mpl /* ) */); /* in this case the colon is optional */ if (mpl->token == T_COLON) get_token(mpl /* : */); /* set the "transpose" indicator */ tr = 1; /* read parameter data in the tabular format */ tabular_format(mpl, par, slice, tr); } else if (mpl->token == T_SEMICOLON) { /* semicolon terminates the data block */ get_token(mpl /* ; */); break; } else error(mpl, "syntax error in parameter data block"); } /* delete the current slice */ delete_slice(mpl, slice); done: return; } /*---------------------------------------------------------------------- -- data_section - read data section. -- -- This routine reads data section using the syntax: -- -- ::= -- ::= ; -- ::= -- ::= -- -- Reading data section is terminated by either the keyword 'end' or -- the end of file. */ void data_section(MPL *mpl) { while (!(mpl->token == T_EOF || is_literal(mpl, "end"))) { if (is_literal(mpl, "set")) set_data(mpl); else if (is_literal(mpl, "param")) parameter_data(mpl); else error(mpl, "syntax error in data section"); } return; } /* eof */ Rglpk/src/GLPK/glplib.h0000644000176000001440000000453212245352174014340 0ustar ripleyusers/* glplib.h (miscellaneous library routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPLIB_H #define GLPLIB_H #define str2int _glp_lib_str2int int str2int(const char *str, int *val); /* convert character string to value of int type */ #define str2num _glp_lib_str2num int str2num(const char *str, double *val); /* convert character string to value of double type */ #define strspx _glp_lib_strspx char *strspx(char *str); /* remove all spaces from character string */ #define strtrim _glp_lib_strtrim char *strtrim(char *str); /* remove trailing spaces from character string */ #define strrev _glp_lib_strrev char *strrev(char *s); /* reverse character string */ #define gcd _glp_lib_gcd int gcd(int x, int y); /* find greatest common divisor of two integers */ #define gcdn _glp_lib_gcdn int gcdn(int n, int x[]); /* find greatest common divisor of n integers */ #define lcm _glp_lib_lcm int lcm(int x, int y); /* find least common multiple of two integers */ #define lcmn _glp_lib_lcmn int lcmn(int n, int x[]); /* find least common multiple of n integers */ #define round2n _glp_lib_round2n double round2n(double x); /* round floating-point number to nearest power of two */ #define fp2rat _glp_lib_fp2rat int fp2rat(double x, double eps, double *p, double *q); /* convert floating-point number to rational number */ #endif /* eof */ Rglpk/src/GLPK/glpspm.h0000644000176000001440000001175112245352174014372 0ustar ripleyusers/* glpspm.h (general sparse matrix) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPSPM_H #define GLPSPM_H #include "dmp.h" typedef struct SPM SPM; typedef struct SPME SPME; struct SPM { /* general sparse matrix */ int m; /* number of rows, m >= 0 */ int n; /* number of columns, n >= 0 */ DMP *pool; /* memory pool to store matrix elements */ SPME **row; /* SPME *row[1+m]; */ /* row[i], 1 <= i <= m, is a pointer to i-th row list */ SPME **col; /* SPME *col[1+n]; */ /* col[j], 1 <= j <= n, is a pointer to j-th column list */ }; struct SPME { /* sparse matrix element */ int i; /* row number */ int j; /* column number */ double val; /* element value */ SPME *r_prev; /* pointer to previous element in the same row */ SPME *r_next; /* pointer to next element in the same row */ SPME *c_prev; /* pointer to previous element in the same column */ SPME *c_next; /* pointer to next element in the same column */ }; typedef struct PER PER; struct PER { /* permutation matrix */ int n; /* matrix order, n >= 0 */ int *row; /* int row[1+n]; */ /* row[i] = j means p[i,j] = 1 */ int *col; /* int col[1+n]; */ /* col[j] = i means p[i,j] = 1 */ }; #define spm_create_mat _glp_spm_create_mat SPM *spm_create_mat(int m, int n); /* create general sparse matrix */ #define spm_new_elem _glp_spm_new_elem SPME *spm_new_elem(SPM *A, int i, int j, double val); /* add new element to sparse matrix */ #define spm_delete_mat _glp_spm_delete_mat void spm_delete_mat(SPM *A); /* delete general sparse matrix */ #define spm_test_mat_e _glp_spm_test_mat_e SPM *spm_test_mat_e(int n, int c); /* create test sparse matrix of E(n,c) class */ #define spm_test_mat_d _glp_spm_test_mat_d SPM *spm_test_mat_d(int n, int c); /* create test sparse matrix of D(n,c) class */ #define spm_show_mat _glp_spm_show_mat int spm_show_mat(const SPM *A, const char *fname); /* write sparse matrix pattern in BMP file format */ #define spm_read_hbm _glp_spm_read_hbm SPM *spm_read_hbm(const char *fname); /* read sparse matrix in Harwell-Boeing format */ #define spm_count_nnz _glp_spm_count_nnz int spm_count_nnz(const SPM *A); /* determine number of non-zeros in sparse matrix */ #define spm_drop_zeros _glp_spm_drop_zeros int spm_drop_zeros(SPM *A, double eps); /* remove zero elements from sparse matrix */ #define spm_read_mat _glp_spm_read_mat SPM *spm_read_mat(const char *fname); /* read sparse matrix from text file */ #define spm_write_mat _glp_spm_write_mat int spm_write_mat(const SPM *A, const char *fname); /* write sparse matrix to text file */ #define spm_transpose _glp_spm_transpose SPM *spm_transpose(const SPM *A); /* transpose sparse matrix */ #define spm_add_sym _glp_spm_add_sym SPM *spm_add_sym(const SPM *A, const SPM *B); /* add two sparse matrices (symbolic phase) */ #define spm_add_num _glp_spm_add_num void spm_add_num(SPM *C, double alfa, const SPM *A, double beta, const SPM *B); /* add two sparse matrices (numeric phase) */ #define spm_add_mat _glp_spm_add_mat SPM *spm_add_mat(double alfa, const SPM *A, double beta, const SPM *B); /* add two sparse matrices (driver routine) */ #define spm_mul_sym _glp_spm_mul_sym SPM *spm_mul_sym(const SPM *A, const SPM *B); /* multiply two sparse matrices (symbolic phase) */ #define spm_mul_num _glp_spm_mul_num void spm_mul_num(SPM *C, const SPM *A, const SPM *B); /* multiply two sparse matrices (numeric phase) */ #define spm_mul_mat _glp_spm_mul_mat SPM *spm_mul_mat(const SPM *A, const SPM *B); /* multiply two sparse matrices (driver routine) */ #define spm_create_per _glp_spm_create_per PER *spm_create_per(int n); /* create permutation matrix */ #define spm_check_per _glp_spm_check_per void spm_check_per(PER *P); /* check permutation matrix for correctness */ #define spm_delete_per _glp_spm_delete_per void spm_delete_per(PER *P); /* delete permutation matrix */ #endif /* eof */ Rglpk/src/GLPK/wclique1.h0000644000176000001440000000244312245352174014620 0ustar ripleyusers/* wclique1.h (maximum weight clique, greedy heuristic) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef WCLIQUE1_H #define WCLIQUE1_H #define wclique1 _glp_wclique1 int wclique1(int n, const double w[], int (*func)(void *info, int i, int ind[]), void *info, int c[]); /* find maximum weight clique with greedy heuristic */ #endif /* eof */ Rglpk/src/GLPK/fhv.h0000644000176000001440000001037112245352174013650 0ustar ripleyusers/* fhv.h (sparse updatable FHV-factorization) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef FHV_H #define FHV_H #include "luf.h" /*********************************************************************** * The structure FHV describes sparse updatable FHV-factorization. * * The FHV-factorization has the following format: * * A = F * H * V, (1) * * F = P0 * L * P0', (2) * * H = H[1] * H[2] * ... * H[nfs], (3) * * V = P * U * Q, (4) * * where: A is a given (unsymmetric) square matrix; F, H, V are matrix * factors actually computed; L is a lower triangular matrix with unity * diagonal; U is an upper tringular matrix; H[k], k = 1, 2, ..., nfs, * is a row-like factor, which differs from unity matrix only in one * row called a non-trivial row; P0, P, Q are permutation matrices; and * P0' is a matrix transposed to P0. * * Matrices F, V, P, Q are stored in the underlying LUF object. * * Non-trivial rows of factors H[k] are stored as sparse vectors in the * right (static) part of the sparse vector area (SVA). Note that unity * diagonal elements of non-trivial rows are not stored. * * Matrix P0 is stored in the same way as matrix P. * * Matrices L and U are completely defined by matrices F, V, P, and Q, * and therefore not stored explicitly. */ typedef struct FHV FHV; struct FHV { /* FHV-factorization */ LUF *luf; /* LU-factorization (contains matrices F, V, P, Q) */ /*--------------------------------------------------------------*/ /* matrix H in the form of eta file */ int nfs_max; /* maximal number of row-like factors (this limits the number of * updates of the factorization) */ int nfs; /* current number of row-like factors, 0 <= nfs <= nfs_max */ int *hh_ind; /* int hh_ind[1+nfs_max]; */ /* hh_ind[0] is not used; * hh_ind[k], 1 <= k <= nfs, is number of non-trivial row of * factor H[k] */ int hh_ref; /* reference number of sparse vector in SVA, which is non-trivial * row of factor H[1] */ #if 0 + 0 int *hh_ptr = &sva->ptr[hh_ref-1]; /* hh_ptr[0] is not used; * hh_ptr[k], 1 <= k <= nfs, is pointer to non-trivial row of * factor H[k] */ int *hh_len = &sva->len[hh_ref-1]; /* hh_len[0] is not used; * hh_len[k], 1 <= k <= nfs, is number of non-zero elements in * non-trivial row of factor H[k] */ #endif /*--------------------------------------------------------------*/ /* matrix P0 */ int *p0_ind; /* int p0_ind[1+n]; */ /* p0_ind[i] = j means that P0[i,j] = 1 */ int *p0_inv; /* int p0_inv[1+n]; */ /* p0_inv[j] = i means that P0[i,j] = 1 */ }; #define fhv_ft_update _glp_fhv_ft_update int fhv_ft_update(FHV *fhv, int q, int aq_len, const int aq_ind[], const double aq_val[], int ind[/*1+n*/], double val[/*1+n*/], double work[/*1+n*/]); /* update FHV-factorization (Forrest-Tomlin) */ #define fhv_h_solve _glp_fhv_h_solve void fhv_h_solve(FHV *fhv, double x[/*1+n*/]); /* solve system H * x = b */ #define fhv_ht_solve _glp_fhv_ht_solve void fhv_ht_solve(FHV *fhv, double x[/*1+n*/]); /* solve system H' * x = b */ #endif /* eof */ Rglpk/src/GLPK/sva.h0000644000176000001440000001474012245352174013662 0ustar ripleyusers/* sva.h (sparse vector area) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef SVA_H #define SVA_H /*********************************************************************** * Sparse Vector Area (SVA) is a container for sparse vectors. This * program object is used mainly on computing factorization, where the * sparse vectors are rows and columns of sparse matrices. * * The SVA storage is a set of locations numbered 1, 2, ..., size, * where size is the size of SVA, which is the total number of * locations currently allocated. Each location is identified by its * pointer p, 1 <= p <= size, and is the pair (ind[p], val[p]), where * ind[p] and val[p] are, respectively, the index and value fields used * to store the index and numeric value of a particular vector element. * * Each sparse vector is identified by its reference number k, * 1 <= k <= n, where n is the total number of vectors currently stored * in SVA, and defined by the triplet (ptr[k], len[k], cap[k]), where: * ptr[k] is a pointer to the first location of the vector; len[k] is * the vector length, which is the number of its non-zero elements, * len[k] >= 0; and cap[k] is the capacity of the vector, which is the * total number of adjacent locations allocated to that vector, * cap[k] >= len[k]. Thus, non-zero elements of k-th vector are stored * in locations ptr[k], ptr[k]+1, ..., ptr[k]+len[k]-1, and locations * ptr[k]+len[k], ptr[k]+len[k]+1, ..., ptr[k]+cap[k]-1 are reserved. * * The SVA storage is divided into three parts as follows: * * Locations 1, 2, ..., m_ptr-1 constitute the left (dynamic) part of * SVA. This part is used to store vectors, whose capacity may change. * Note that all vectors stored in the left part are also included in * a doubly linked list, where they are ordered by increasing their * pointers ptr[k] (this list is needed for efficient implementation * of the garbage collector used to defragment the left part of SVA); * * Locations m_ptr, m_ptr+1, ..., r_ptr-1 are free and constitute the * middle (free) part of SVA. * * Locations r_ptr, r_ptr+1, ..., size constitute the right (static) * part of SVA. This part is used to store vectors, whose capacity is * not changed. */ typedef struct SVA SVA; struct SVA { /* sparse vector area */ int n_max; /* maximal value of n (enlarged automatically) */ int n; /* number of currently allocated vectors, 0 <= n <= n_max */ int *ptr; /* int ptr[1+n_max]; */ /* ptr[0] is not used; * ptr[k], 1 <= i <= n, is pointer to first location of k-th * vector in the arrays ind and val */ int *len; /* int len[1+n_max]; */ /* len[0] is not used; * len[k], 1 <= k <= n, is length of k-th vector, len[k] >= 0 */ int *cap; /* int cap[1+n_max]; */ /* cap[0] is not used; * cap[k], 1 <= k <= n, is capacity of k-th vector (the number * of adjacent locations allocated to it), cap[k] >= len[k] */ /* NOTE: if cap[k] = 0, then ptr[k] = 0 and len[k] = 0 */ int size; /* total number of locations in SVA */ int m_ptr, r_ptr; /* partitioning pointers that define the left, middle, and right * parts of SVA (see above); 1 <= m_ptr <= r_ptr <= size+1 */ int head; /* number of first (leftmost) vector in the linked list */ int tail; /* number of last (rightmost) vector in the linked list */ int *prev; /* int prev[1+n_max]; */ /* prev[0] is not used; * prev[k] is number of vector which precedes k-th vector in the * linked list; * prev[k] < 0 means that k-th vector is not in the list */ int *next; /* int next[1+n_max]; */ /* next[0] is not used; * next[k] is number of vector which succedes k-th vector in the * linked list; * next[k] < 0 means that k-th vector is not in the list */ /* NOTE: only vectors having non-zero capacity and stored in the * left part of SVA are included in this linked list */ int *ind; /* int ind[1+size]; */ /* ind[0] is not used; * ind[p], 1 <= p <= size, is index field of location p */ double *val; /* double val[1+size]; */ /* val[0] is not used; * val[p], 1 <= p <= size, is value field of location p */ #if 1 int talky; /* option to enable talky mode */ #endif }; #define sva_create_area _glp_sva_create_area SVA *sva_create_area(int n_max, int size); /* create sparse vector area (SVA) */ #define sva_alloc_vecs _glp_sva_alloc_vecs int sva_alloc_vecs(SVA *sva, int nnn); /* allocate new vectors in SVA */ #define sva_resize_area _glp_sva_resize_area void sva_resize_area(SVA *sva, int delta); /* change size of SVA storage */ #define sva_defrag_area _glp_sva_defrag_area void sva_defrag_area(SVA *sva); /* defragment left part of SVA */ #define sva_more_space _glp_sva_more_space void sva_more_space(SVA *sva, int m_size); /* increase size of middle (free) part of SVA */ #define sva_enlarge_cap _glp_sva_enlarge_cap void sva_enlarge_cap(SVA *sva, int k, int new_cap, int skip); /* enlarge capacity of specified vector */ #define sva_reserve_cap _glp_sva_reserve_cap void sva_reserve_cap(SVA *sva, int k, int new_cap); /* reserve locations for specified vector */ #define sva_make_static _glp_sva_make_static void sva_make_static(SVA *sva, int k); /* relocate specified vector to right part of SVA */ #define sva_check_area _glp_sva_check_area void sva_check_area(SVA *sva); /* check sparse vector area (SVA) */ #define sva_delete_area _glp_sva_delete_area void sva_delete_area(SVA *sva); /* delete sparse vector area (SVA) */ #endif /* eof */ Rglpk/src/GLPK/glpios05.c0000644000176000001440000002363212245352174014526 0ustar ripleyusers/* glpios05.c (Gomory's mixed integer cut generator) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpios.h" /*********************************************************************** * NAME * * ios_gmi_gen - generate Gomory's mixed integer cuts. * * SYNOPSIS * * #include "glpios.h" * void ios_gmi_gen(glp_tree *tree, IOSPOOL *pool); * * DESCRIPTION * * The routine ios_gmi_gen generates Gomory's mixed integer cuts for * the current point and adds them to the cut pool. */ #define MAXCUTS 50 /* maximal number of cuts to be generated for one round */ struct worka { /* Gomory's cut generator working area */ int *ind; /* int ind[1+n]; */ double *val; /* double val[1+n]; */ double *phi; /* double phi[1+m+n]; */ }; #define f(x) ((x) - floor(x)) /* compute fractional part of x */ static void gen_cut(glp_tree *tree, struct worka *worka, int j) { /* this routine tries to generate Gomory's mixed integer cut for specified structural variable x[m+j] of integer kind, which is basic and has fractional value in optimal solution to current LP relaxation */ glp_prob *mip = tree->mip; int m = mip->m; int n = mip->n; int *ind = worka->ind; double *val = worka->val; double *phi = worka->phi; int i, k, len, kind, stat; double lb, ub, alfa, beta, ksi, phi1, rhs; /* compute row of the simplex tableau, which (row) corresponds to specified basic variable xB[i] = x[m+j]; see (23) */ len = glp_eval_tab_row(mip, m+j, ind, val); /* determine beta[i], which a value of xB[i] in optimal solution to current LP relaxation; note that this value is the same as if it would be computed with formula (27); it is assumed that beta[i] is fractional enough */ beta = mip->col[j]->prim; /* compute cut coefficients phi and right-hand side rho, which correspond to formula (30); dense format is used, because rows of the simplex tableau is usually dense */ for (k = 1; k <= m+n; k++) phi[k] = 0.0; rhs = f(beta); /* initial value of rho; see (28), (32) */ for (j = 1; j <= len; j++) { /* determine original number of non-basic variable xN[j] */ k = ind[j]; xassert(1 <= k && k <= m+n); /* determine the kind, bounds and current status of xN[j] in optimal solution to LP relaxation */ if (k <= m) { /* auxiliary variable */ GLPROW *row = mip->row[k]; kind = GLP_CV; lb = row->lb; ub = row->ub; stat = row->stat; } else { /* structural variable */ GLPCOL *col = mip->col[k-m]; kind = col->kind; lb = col->lb; ub = col->ub; stat = col->stat; } /* xN[j] cannot be basic */ xassert(stat != GLP_BS); /* determine row coefficient ksi[i,j] at xN[j]; see (23) */ ksi = val[j]; /* if ksi[i,j] is too large in the magnitude, do not generate the cut */ if (fabs(ksi) > 1e+05) goto fini; /* if ksi[i,j] is too small in the magnitude, skip it */ if (fabs(ksi) < 1e-10) goto skip; /* compute row coefficient alfa[i,j] at y[j]; see (26) */ switch (stat) { case GLP_NF: /* xN[j] is free (unbounded) having non-zero ksi[i,j]; do not generate the cut */ goto fini; case GLP_NL: /* xN[j] has active lower bound */ alfa = - ksi; break; case GLP_NU: /* xN[j] has active upper bound */ alfa = + ksi; break; case GLP_NS: /* xN[j] is fixed; skip it */ goto skip; default: xassert(stat != stat); } /* compute cut coefficient phi'[j] at y[j]; see (21), (28) */ switch (kind) { case GLP_IV: /* y[j] is integer */ if (fabs(alfa - floor(alfa + 0.5)) < 1e-10) { /* alfa[i,j] is close to nearest integer; skip it */ goto skip; } else if (f(alfa) <= f(beta)) phi1 = f(alfa); else phi1 = (f(beta) / (1.0 - f(beta))) * (1.0 - f(alfa)); break; case GLP_CV: /* y[j] is continuous */ if (alfa >= 0.0) phi1 = + alfa; else phi1 = (f(beta) / (1.0 - f(beta))) * (- alfa); break; default: xassert(kind != kind); } /* compute cut coefficient phi[j] at xN[j] and update right- hand side rho; see (31), (32) */ switch (stat) { case GLP_NL: /* xN[j] has active lower bound */ phi[k] = + phi1; rhs += phi1 * lb; break; case GLP_NU: /* xN[j] has active upper bound */ phi[k] = - phi1; rhs -= phi1 * ub; break; default: xassert(stat != stat); } skip: ; } /* now the cut has the form sum_k phi[k] * x[k] >= rho, where cut coefficients are stored in the array phi in dense format; x[1,...,m] are auxiliary variables, x[m+1,...,m+n] are struc- tural variables; see (30) */ /* eliminate auxiliary variables in order to express the cut only through structural variables; see (33) */ for (i = 1; i <= m; i++) { GLPROW *row; GLPAIJ *aij; if (fabs(phi[i]) < 1e-10) continue; /* auxiliary variable x[i] has non-zero cut coefficient */ row = mip->row[i]; /* x[i] cannot be fixed */ xassert(row->type != GLP_FX); /* substitute x[i] = sum_j a[i,j] * x[m+j] */ for (aij = row->ptr; aij != NULL; aij = aij->r_next) phi[m+aij->col->j] += phi[i] * aij->val; } /* convert the final cut to sparse format and substitute fixed (structural) variables */ len = 0; for (j = 1; j <= n; j++) { GLPCOL *col; if (fabs(phi[m+j]) < 1e-10) continue; /* structural variable x[m+j] has non-zero cut coefficient */ col = mip->col[j]; if (col->type == GLP_FX) { /* eliminate x[m+j] */ rhs -= phi[m+j] * col->lb; } else { len++; ind[len] = j; val[len] = phi[m+j]; } } if (fabs(rhs) < 1e-12) rhs = 0.0; /* if the cut inequality seems to be badly scaled, reject it to avoid numeric difficulties */ for (k = 1; k <= len; k++) { if (fabs(val[k]) < 1e-03) goto fini; if (fabs(val[k]) > 1e+03) goto fini; } /* add the cut to the cut pool for further consideration */ #if 0 ios_add_cut_row(tree, pool, GLP_RF_GMI, len, ind, val, GLP_LO, rhs); #else glp_ios_add_row(tree, NULL, GLP_RF_GMI, 0, len, ind, val, GLP_LO, rhs); #endif fini: return; } struct var { int j; double f; }; static int fcmp(const void *p1, const void *p2) { const struct var *v1 = p1, *v2 = p2; if (v1->f > v2->f) return -1; if (v1->f < v2->f) return +1; return 0; } void ios_gmi_gen(glp_tree *tree) { /* main routine to generate Gomory's cuts */ glp_prob *mip = tree->mip; int m = mip->m; int n = mip->n; struct var *var; int k, nv, j, size; struct worka _worka, *worka = &_worka; /* allocate working arrays */ var = xcalloc(1+n, sizeof(struct var)); worka->ind = xcalloc(1+n, sizeof(int)); worka->val = xcalloc(1+n, sizeof(double)); worka->phi = xcalloc(1+m+n, sizeof(double)); /* build the list of integer structural variables, which are basic and have fractional value in optimal solution to current LP relaxation */ nv = 0; for (j = 1; j <= n; j++) { GLPCOL *col = mip->col[j]; double frac; if (col->kind != GLP_IV) continue; if (col->type == GLP_FX) continue; if (col->stat != GLP_BS) continue; frac = f(col->prim); if (!(0.05 <= frac && frac <= 0.95)) continue; /* add variable to the list */ nv++, var[nv].j = j, var[nv].f = frac; } /* order the list by descending fractionality */ qsort(&var[1], nv, sizeof(struct var), fcmp); /* try to generate cuts by one for each variable in the list, but not more than MAXCUTS cuts */ size = glp_ios_pool_size(tree); for (k = 1; k <= nv; k++) { if (glp_ios_pool_size(tree) - size >= MAXCUTS) break; gen_cut(tree, worka, var[k].j); } /* free working arrays */ xfree(var); xfree(worka->ind); xfree(worka->val); xfree(worka->phi); return; } /* eof */ Rglpk/src/GLPK/glpapi03.c0000644000176000001440000001217312245352174014501 0ustar ripleyusers/* glpapi03.c (row and column searching routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpapi.h" /*********************************************************************** * NAME * * glp_create_index - create the name index * * SYNOPSIS * * void glp_create_index(glp_prob *lp); * * DESCRIPTION * * The routine glp_create_index creates the name index for the * specified problem object. The name index is an auxiliary data * structure, which is intended to quickly (i.e. for logarithmic time) * find rows and columns by their names. * * This routine can be called at any time. If the name index already * exists, the routine does nothing. */ void glp_create_index(glp_prob *lp) { GLPROW *row; GLPCOL *col; int i, j; /* create row name index */ if (lp->r_tree == NULL) { lp->r_tree = avl_create_tree(avl_strcmp, NULL); for (i = 1; i <= lp->m; i++) { row = lp->row[i]; xassert(row->node == NULL); if (row->name != NULL) { row->node = avl_insert_node(lp->r_tree, row->name); avl_set_node_link(row->node, row); } } } /* create column name index */ if (lp->c_tree == NULL) { lp->c_tree = avl_create_tree(avl_strcmp, NULL); for (j = 1; j <= lp->n; j++) { col = lp->col[j]; xassert(col->node == NULL); if (col->name != NULL) { col->node = avl_insert_node(lp->c_tree, col->name); avl_set_node_link(col->node, col); } } } return; } /*********************************************************************** * NAME * * glp_find_row - find row by its name * * SYNOPSIS * * int glp_find_row(glp_prob *lp, const char *name); * * RETURNS * * The routine glp_find_row returns the ordinal number of a row, * which is assigned (by the routine glp_set_row_name) the specified * symbolic name. If no such row exists, the routine returns 0. */ int glp_find_row(glp_prob *lp, const char *name) { AVLNODE *node; int i = 0; if (lp->r_tree == NULL) xerror("glp_find_row: row name index does not exist\n"); if (!(name == NULL || name[0] == '\0' || strlen(name) > 255)) { node = avl_find_node(lp->r_tree, name); if (node != NULL) i = ((GLPROW *)avl_get_node_link(node))->i; } return i; } /*********************************************************************** * NAME * * glp_find_col - find column by its name * * SYNOPSIS * * int glp_find_col(glp_prob *lp, const char *name); * * RETURNS * * The routine glp_find_col returns the ordinal number of a column, * which is assigned (by the routine glp_set_col_name) the specified * symbolic name. If no such column exists, the routine returns 0. */ int glp_find_col(glp_prob *lp, const char *name) { AVLNODE *node; int j = 0; if (lp->c_tree == NULL) xerror("glp_find_col: column name index does not exist\n"); if (!(name == NULL || name[0] == '\0' || strlen(name) > 255)) { node = avl_find_node(lp->c_tree, name); if (node != NULL) j = ((GLPCOL *)avl_get_node_link(node))->j; } return j; } /*********************************************************************** * NAME * * glp_delete_index - delete the name index * * SYNOPSIS * * void glp_delete_index(glp_prob *lp); * * DESCRIPTION * * The routine glp_delete_index deletes the name index previously * created by the routine glp_create_index and frees the memory * allocated to this auxiliary data structure. * * This routine can be called at any time. If the name index does not * exist, the routine does nothing. */ void glp_delete_index(glp_prob *lp) { int i, j; /* delete row name index */ if (lp->r_tree != NULL) { for (i = 1; i <= lp->m; i++) lp->row[i]->node = NULL; avl_delete_tree(lp->r_tree), lp->r_tree = NULL; } /* delete column name index */ if (lp->c_tree != NULL) { for (j = 1; j <= lp->n; j++) lp->col[j]->node = NULL; avl_delete_tree(lp->c_tree), lp->c_tree = NULL; } return; } /* eof */ Rglpk/src/GLPK/glpbfx.h0000644000176000001440000000457112245352174014354 0ustar ripleyusers/* glpbfx.h (basis factorization interface, bignum arithmetic) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPBFX_H #define GLPBFX_H #include "glpgmp.h" #ifndef GLPBFX_DEFINED #define GLPBFX_DEFINED typedef struct { double _opaque_bfx; } BFX; #endif #define bfx_create_binv _glp_bfx_create_binv #define bfx_is_valid _glp_bfx_is_valid #define bfx_invalidate _glp_bfx_invalidate #define bfx_factorize _glp_bfx_factorize #define bfx_ftran _glp_bfx_ftran #define bfx_btran _glp_bfx_btran #define bfx_update _glp_bfx_update #define bfx_delete_binv _glp_bfx_delete_binv BFX *bfx_create_binv(void); /* create factorization of the basis matrix */ int bfx_is_valid(BFX *binv); /* check if factorization is valid */ void bfx_invalidate(BFX *binv); /* invalidate factorization of the basis matrix */ int bfx_factorize(BFX *binv, int m, int (*col)(void *info, int j, int ind[], mpq_t val[]), void *info); /* compute factorization of the basis matrix */ void bfx_ftran(BFX *binv, mpq_t x[], int save); /* perform forward transformation (FTRAN) */ void bfx_btran(BFX *binv, mpq_t x[]); /* perform backward transformation (BTRAN) */ int bfx_update(BFX *binv, int j); /* update factorization of the basis matrix */ void bfx_delete_binv(BFX *binv); /* delete factorization of the basis matrix */ #endif /* eof */ Rglpk/src/GLPK/fhvint.h0000644000176000001440000000466112245352174014370 0ustar ripleyusers/* fhvint.h (interface to FHV-factorization) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef FHVINT_H #define FHVINT_H #include "fhv.h" #include "lufint.h" typedef struct FHVINT FHVINT; struct FHVINT { /* interface to FHV-factorization */ int valid; /* factorization is valid only if this flag is set */ FHV *fhv; /* FHV-factorization */ LUFINT *lufint; /* interface to underlying LU-factorization */ /*--------------------------------------------------------------*/ /* control parameters */ int nfs_max; /* required maximal number of row-like factors */ }; #define fhvint_create _glp_fhvint_create FHVINT *fhvint_create(void); /* create interface to FHV-factorization */ #define fhvint_factorize _glp_fhvint_factorize int fhvint_factorize(FHVINT *fi, int n, int (*col)(void *info, int j, int ind[], double val[]), void *info); /* compute FHV-factorization of specified matrix A */ #define fhvint_update _glp_fhvint_update int fhvint_update(FHVINT *fi, int j, int len, const int ind[], const double val[]); /* update FHV-factorization after replacing j-th column of A */ #define fhvint_ftran _glp_fhvint_ftran void fhvint_ftran(FHVINT *fi, double x[]); /* solve system A * x = b */ #define fhvint_btran _glp_fhvint_btran void fhvint_btran(FHVINT *fi, double x[]); /* solve system A'* x = b */ #define fhvint_delete _glp_fhvint_delete void fhvint_delete(FHVINT *fi); /* delete interface to FHV-factorization */ #endif /* eof */ Rglpk/src/GLPK/luf.h0000644000176000001440000001775712245352174013672 0ustar ripleyusers/* luf.h (sparse LU-factorization) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef LUF_H #define LUF_H #include "sva.h" /*********************************************************************** * The structure LUF describes sparse LU-factorization. * * The LU-factorization has the following format: * * A = F * V = P * L * U * Q, (1) * * F = P * L * P', (2) * * V = P * U * Q, (3) * * where A is a given (unsymmetric) square matrix, F and V are matrix * factors actually computed, L is a lower triangular matrix with unity * diagonal, U is an upper triangular matrix, P and Q are permutation * matrices, P' is a matrix transposed to P. All the matrices have the * same order n. * * Matrices F and V are stored in both row- and column-wise sparse * formats in the associated sparse vector area (SVA). Unity diagonal * elements of matrix F are not stored. Pivot elements of matrix V * (which correspond to diagonal elements of matrix U) are stored in * a separate ordinary array. * * Permutation matrices P and Q are stored in ordinary arrays in both * row- and column-like formats. * * Matrices L and U are completely defined by matrices F, V, P, and Q, * and therefore not stored explicitly. */ typedef struct LUF LUF; struct LUF { /* sparse LU-factorization */ int n; /* order of matrices A, F, V, P, Q */ SVA *sva; /* associated sparse vector area (SVA) used to store rows and * columns of matrices F and V; note that different objects may * share the same SVA */ /*--------------------------------------------------------------*/ /* matrix F in row-wise format */ /* during the factorization process this object is not used */ int fr_ref; /* reference number of sparse vector in SVA, which is the first * row of matrix F */ #if 0 + 0 int *fr_ptr = &sva->ptr[fr_ref-1]; /* fr_ptr[0] is not used; * fr_ptr[i], 1 <= i <= n, is pointer to i-th row in SVA */ int *fr_len = &sva->len[fr_ref-1]; /* fr_len[0] is not used; * fr_len[i], 1 <= i <= n, is length of i-th row */ #endif /*--------------------------------------------------------------*/ /* matrix F in column-wise format */ /* during the factorization process this object is constructed by columns */ int fc_ref; /* reference number of sparse vector in SVA, which is the first * column of matrix F */ #if 0 + 0 int *fc_ptr = &sva->ptr[fc_ref-1]; /* fc_ptr[0] is not used; * fc_ptr[j], 1 <= j <= n, is pointer to j-th column in SVA */ int *fc_len = &sva->len[fc_ref-1]; /* fc_len[0] is not used; * fc_len[j], 1 <= j <= n, is length of j-th column */ #endif /*--------------------------------------------------------------*/ /* matrix V in row-wise format */ int vr_ref; /* reference number of sparse vector in SVA, which is the first * row of matrix V */ #if 0 + 0 int *vr_ptr = &sva->ptr[vr_ref-1]; /* vr_ptr[0] is not used; * vr_ptr[i], 1 <= i <= n, is pointer to i-th row in SVA */ int *vr_len = &sva->len[vr_ref-1]; /* vr_len[0] is not used; * vr_len[i], 1 <= i <= n, is length of i-th row */ int *vr_cap = &sva->cap[vr_ref-1]; /* vr_cap[0] is not used; * vr_cap[i], 1 <= i <= n, is capacity of i-th row */ #endif double *vr_piv; /* double vr_piv[1+n]; */ /* vr_piv[0] is not used; * vr_piv[i], 1 <= i <= n, is pivot element of i-th row */ /*--------------------------------------------------------------*/ /* matrix V in column-wise format */ /* during the factorization process this object contains only the * patterns (row indices) of columns of the active submatrix */ int vc_ref; /* reference number of sparse vector in SVA, which is the first * column of matrix V */ #if 0 + 0 int *vc_ptr = &sva->ptr[vc_ref-1]; /* vc_ptr[0] is not used; * vc_ptr[j], 1 <= j <= n, is pointer to j-th column in SVA */ int *vc_len = &sva->len[vc_ref-1]; /* vc_len[0] is not used; * vc_len[j], 1 <= j <= n, is length of j-th column */ int *vc_cap = &sva->cap[vc_ref-1]; /* vc_cap[0] is not used; * vc_cap[j], 1 <= j <= n, is capacity of j-th column */ #endif /*--------------------------------------------------------------*/ /* matrix P */ int *pp_ind; /* int pp_ind[1+n]; */ /* pp_ind[i] = j means that P[i,j] = 1 */ int *pp_inv; /* int pp_inv[1+n]; */ /* pp_inv[j] = i means that P[i,j] = 1 */ /* if i-th row or column of matrix F is i'-th row or column of * matrix L, or if i-th row of matrix V is i'-th row of matrix U, * then pp_ind[i] = i' and pp_inv[i'] = i */ /*--------------------------------------------------------------*/ /* matrix Q */ int *qq_ind; /* int qq_ind[1+n]; */ /* qq_ind[i] = j means that Q[i,j] = 1 */ int *qq_inv; /* int qq_inv[1+n]; */ /* qq_inv[j] = i means that Q[i,j] = 1 */ /* if j-th column of matrix V is j'-th column of matrix U, then * qq_ind[j'] = j and qq_inv[j] = j' */ }; #define luf_swap_u_rows(i1, i2) \ do \ { int j1, j2; \ j1 = pp_inv[i1], j2 = pp_inv[i2]; \ pp_ind[j1] = i2, pp_inv[i2] = j1; \ pp_ind[j2] = i1, pp_inv[i1] = j2; \ } while (0) /* swap rows i1 and i2 of matrix U = P'* V * Q' */ #define luf_swap_u_cols(j1, j2) \ do \ { int i1, i2; \ i1 = qq_ind[j1], i2 = qq_ind[j2]; \ qq_ind[j1] = i2, qq_inv[i2] = j1; \ qq_ind[j2] = i1, qq_inv[i1] = j2; \ } while (0) /* swap columns j1 and j2 of matrix U = P'* V * Q' */ #define luf_check_all _glp_luf_check_all void luf_check_all(LUF *luf, int k); /* check LU-factorization before k-th elimination step */ #define luf_build_v_rows _glp_luf_build_v_rows void luf_build_v_rows(LUF *luf, int len[/*1+n*/]); /* build matrix V in row-wise format */ #define luf_build_f_rows _glp_luf_build_f_rows void luf_build_f_rows(LUF *luf, int len[/*1+n*/]); /* build matrix F in row-wise format */ #define luf_build_v_cols _glp_luf_build_v_cols void luf_build_v_cols(LUF *luf, int updat, int len[/*1+n*/]); /* build matrix V in column-wise format */ #define luf_check_f_rc _glp_luf_check_f_rc void luf_check_f_rc(LUF *luf); /* check rows and columns of matrix F */ #define luf_check_v_rc _glp_luf_check_v_rc void luf_check_v_rc(LUF *luf); /* check rows and columns of matrix V */ #define luf_f_solve _glp_luf_f_solve1 void luf_f_solve(LUF *luf, double x[/*1+n*/]); /* solve system F * x = b */ #define luf_ft_solve _glp_luf_ft_solve1 void luf_ft_solve(LUF *luf, double x[/*1+n*/]); /* solve system F' * x = b */ #define luf_v_solve _glp_luf_v_solve1 void luf_v_solve(LUF *luf, double b[/*1+n*/], double x[/*1+n*/]); /* solve system V * x = b */ #define luf_vt_solve _glp_luf_vt_solve1 void luf_vt_solve(LUF *luf, double b[/*1+n*/], double x[/*1+n*/]); /* solve system V' * x = b */ #endif /* eof */ Rglpk/src/GLPK/tls.c0000644000176000001440000000400612245352174013660 0ustar ripleyusers/* tls.c (thread local storage) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2001, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" static void *tls = NULL; /* NOTE: in a re-entrant version of the package this variable should be * placed in the Thread Local Storage (TLS) */ /*********************************************************************** * NAME * * tls_set_ptr - store global pointer in TLS * * SYNOPSIS * * #include "env.h" * void tls_set_ptr(void *ptr); * * DESCRIPTION * * The routine tls_set_ptr stores a pointer specified by the parameter * ptr in the Thread Local Storage (TLS). */ void tls_set_ptr(void *ptr) { tls = ptr; return; } /*********************************************************************** * NAME * * tls_get_ptr - retrieve global pointer from TLS * * SYNOPSIS * * #include "env.h" * void *tls_get_ptr(void); * * RETURNS * * The routine tls_get_ptr returns a pointer previously stored by the * routine tls_set_ptr. If the latter has not been called yet, NULL is * returned. */ void *tls_get_ptr(void) { void *ptr; ptr = tls; return ptr; } /* eof */ Rglpk/src/GLPK/glplpx03.c0000644000176000001440000002130512245352174014530 0ustar ripleyusers/* glplpx03.c (OPB format) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Author: Oscar Gustafsson . * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #define _GLPSTD_ERRNO #define _GLPSTD_STDIO #include "glpapi.h" #if 0 /* 24/XII-2009; by mao */ #include "glpipp.h" #endif /*---------------------------------------------------------------------- -- lpx_write_pb - write problem data in (normalized) OPB format. -- -- *Synopsis* -- -- #include "glplpx.h" -- int lpx_write_pb(LPX *lp, const char *fname, int normalized, -- int binarize); -- -- *Description* -- -- The routine lpx_write_pb writes problem data in OPB format -- to an output text file whose name is the character string fname. -- If normalized is non-zero the output will be generated in a -- normalized form with sequentially numbered variables, x1, x2 etc. -- If binarize, any integer variable will be repalzec by binary ones, -- see ipp_binarize -- -- *Returns* -- -- If the operation was successful, the routine returns zero. Otherwise -- the routine prints an error message and returns non-zero. */ #if 1 /* 24/XII-2009; by mao (disabled, because IPP was removed) */ int lpx_write_pb(LPX *lp, const char *fname, int normalized, int binarize) { xassert(lp == lp); xassert(fname == fname); xassert(normalized == normalized); xassert(binarize == binarize); xprintf("lpx_write_pb: sorry, currently this operation is not ava" "ilable\n"); return 1; } #else int lpx_write_pb(LPX *lp, const char *fname, int normalized, int binarize) { FILE* fp; int m,n,i,j,k,o,nonfree=0, obj_dir, dbl, *ndx, row_type, emptylhs=0; double coeff, *val, bound, constant/*=0.0*/; char* objconstname = "dummy_one"; char* emptylhsname = "dummy_zero"; /* Variables needed for possible binarization */ /*LPX* tlp;*/ IPP *ipp = NULL; /*tlp=lp;*/ if(binarize) /* Transform integer variables to binary ones */ { ipp = ipp_create_wksp(); ipp_load_orig(ipp, lp); ipp_binarize(ipp); lp = ipp_build_prob(ipp); } fp = fopen(fname, "w"); if(fp!= NULL) { xprintf( "lpx_write_pb: writing problem in %sOPB format to `%s'...\n", (normalized?"normalized ":""), fname); m = glp_get_num_rows(lp); n = glp_get_num_cols(lp); for(i=1;i<=m;i++) { switch(glp_get_row_type(lp,i)) { case GLP_LO: case GLP_UP: case GLP_FX: { nonfree += 1; break; } case GLP_DB: { nonfree += 2; break; } } } constant=glp_get_obj_coef(lp,0); fprintf(fp,"* #variables = %d #constraints = %d\n", n + (constant == 0?1:0), nonfree + (constant == 0?1:0)); /* Objective function */ obj_dir = glp_get_obj_dir(lp); fprintf(fp,"min: "); for(i=1;i<=n;i++) { coeff = glp_get_obj_coef(lp,i); if(coeff != 0.0) { if(obj_dir == GLP_MAX) coeff=-coeff; if(normalized) fprintf(fp, " %d x%d", (int)coeff, i); else fprintf(fp, " %d*%s", (int)coeff, glp_get_col_name(lp,i)); } } if(constant) { if(normalized) fprintf(fp, " %d x%d", (int)constant, n+1); else fprintf(fp, " %d*%s", (int)constant, objconstname); } fprintf(fp,";\n"); if(normalized && !binarize) /* Name substitution */ { fprintf(fp,"* Variable name substitution:\n"); for(j=1;j<=n;j++) { fprintf(fp, "* x%d = %s\n", j, glp_get_col_name(lp,j)); } if(constant) fprintf(fp, "* x%d = %s\n", n+1, objconstname); } ndx = xcalloc(1+n, sizeof(int)); val = xcalloc(1+n, sizeof(double)); /* Constraints */ for(j=1;j<=m;j++) { row_type=glp_get_row_type(lp,j); if(row_type!=GLP_FR) { if(row_type == GLP_DB) { dbl=2; row_type = GLP_UP; } else { dbl=1; } k=glp_get_mat_row(lp, j, ndx, val); for(o=1;o<=dbl;o++) { if(o==2) { row_type = GLP_LO; } if(k==0) /* Empty LHS */ { emptylhs = 1; if(normalized) { fprintf(fp, "0 x%d ", n+2); } else { fprintf(fp, "0*%s ", emptylhsname); } } for(i=1;i<=k;i++) { if(val[i] != 0.0) { if(normalized) { fprintf(fp, "%d x%d ", (row_type==GLP_UP)?(-(int)val[i]):((int)val[i]), ndx[i]); } else { fprintf(fp, "%d*%s ", (int)val[i], glp_get_col_name(lp,ndx[i])); } } } switch(row_type) { case GLP_LO: { fprintf(fp, ">="); bound = glp_get_row_lb(lp,j); break; } case GLP_UP: { if(normalized) { fprintf(fp, ">="); bound = -glp_get_row_ub(lp,j); } else { fprintf(fp, "<="); bound = glp_get_row_ub(lp,j); } break; } case GLP_FX: { fprintf(fp, "="); bound = glp_get_row_lb(lp,j); break; } } fprintf(fp," %d;\n",(int)bound); } } } xfree(ndx); xfree(val); if(constant) { xprintf( "lpx_write_pb: adding constant objective function variable\n"); if(normalized) fprintf(fp, "1 x%d = 1;\n", n+1); else fprintf(fp, "1*%s = 1;\n", objconstname); } if(emptylhs) { xprintf( "lpx_write_pb: adding dummy variable for empty left-hand si" "de constraint\n"); if(normalized) fprintf(fp, "1 x%d = 0;\n", n+2); else fprintf(fp, "1*%s = 0;\n", emptylhsname); } } else { xprintf("Problems opening file for writing: %s\n", fname); return(1); } fflush(fp); if (ferror(fp)) { xprintf("lpx_write_pb: can't write to `%s' - %s\n", fname, strerror(errno)); goto fail; } fclose(fp); if(binarize) { /* delete the resultant problem object */ if (lp != NULL) lpx_delete_prob(lp); /* delete MIP presolver workspace */ if (ipp != NULL) ipp_delete_wksp(ipp); /*lp=tlp;*/ } return 0; fail: if (fp != NULL) fclose(fp); return 1; } #endif /* eof */ Rglpk/src/GLPK/glpmpl05.c0000644000176000001440000005342212245352174014524 0ustar ripleyusers/* glpmpl05.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Authors: Andrew Makhorin * Heinrich Schuchardt * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #define _GLPSTD_STDIO #define _GLPSTD_TIME #include "glpmpl.h" #if 1 /* 11/VI-2013 */ #include "jd.h" #endif double fn_gmtime(MPL *mpl) { /* obtain the current calendar time (UTC) */ time_t timer; struct tm *tm; int j; time(&timer); if (timer == (time_t)(-1)) err: error(mpl, "gmtime(); unable to obtain current calendar time"); tm = gmtime(&timer); if (tm == NULL) goto err; j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year); if (j < 0) goto err; return (((double)(j - jday(1, 1, 1970)) * 24.0 + (double)tm->tm_hour) * 60.0 + (double)tm->tm_min) * 60.0 + (double)tm->tm_sec; } static char *week[] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" }; static char *moon[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; static void error1(MPL *mpl, const char *str, const char *s, const char *fmt, const char *f, const char *msg) { xprintf("Input string passed to str2time:\n"); xprintf("%s\n", str); xprintf("%*s\n", (s - str) + 1, "^"); xprintf("Format string passed to str2time:\n"); xprintf("%s\n", fmt); xprintf("%*s\n", (f - fmt) + 1, "^"); error(mpl, "%s", msg); /* no return */ } double fn_str2time(MPL *mpl, const char *str, const char *fmt) { /* convert character string to the calendar time */ int j, year, month, day, hh, mm, ss, zone; const char *s, *f; year = month = day = hh = mm = ss = -1, zone = INT_MAX; s = str; for (f = fmt; *f != '\0'; f++) { if (*f == '%') { f++; if (*f == 'b' || *f == 'h') { /* the abbreviated month name */ int k; char *name; if (month >= 0) error1(mpl, str, s, fmt, f, "month multiply specified" ); while (*s == ' ') s++; for (month = 1; month <= 12; month++) { name = moon[month-1]; for (k = 0; k <= 2; k++) { if (toupper((unsigned char)s[k]) != toupper((unsigned char)name[k])) goto next; } s += 3; for (k = 3; name[k] != '\0'; k++) { if (toupper((unsigned char)*s) != toupper((unsigned char)name[k])) break; s++; } break; next: ; } if (month > 12) error1(mpl, str, s, fmt, f, "abbreviated month name m" "issing or invalid"); } else if (*f == 'd') { /* the day of the month as a decimal number (01..31) */ if (day >= 0) error1(mpl, str, s, fmt, f, "day multiply specified"); while (*s == ' ') s++; if (!('0' <= *s && *s <= '9')) error1(mpl, str, s, fmt, f, "day missing or invalid"); day = (*s++) - '0'; if ('0' <= *s && *s <= '9') day = 10 * day + ((*s++) - '0'); if (!(1 <= day && day <= 31)) error1(mpl, str, s, fmt, f, "day out of range"); } else if (*f == 'H') { /* the hour as a decimal number, using a 24-hour clock (00..23) */ if (hh >= 0) error1(mpl, str, s, fmt, f, "hour multiply specified") ; while (*s == ' ') s++; if (!('0' <= *s && *s <= '9')) error1(mpl, str, s, fmt, f, "hour missing or invalid") ; hh = (*s++) - '0'; if ('0' <= *s && *s <= '9') hh = 10 * hh + ((*s++) - '0'); if (!(0 <= hh && hh <= 23)) error1(mpl, str, s, fmt, f, "hour out of range"); } else if (*f == 'm') { /* the month as a decimal number (01..12) */ if (month >= 0) error1(mpl, str, s, fmt, f, "month multiply specified" ); while (*s == ' ') s++; if (!('0' <= *s && *s <= '9')) error1(mpl, str, s, fmt, f, "month missing or invalid" ); month = (*s++) - '0'; if ('0' <= *s && *s <= '9') month = 10 * month + ((*s++) - '0'); if (!(1 <= month && month <= 12)) error1(mpl, str, s, fmt, f, "month out of range"); } else if (*f == 'M') { /* the minute as a decimal number (00..59) */ if (mm >= 0) error1(mpl, str, s, fmt, f, "minute multiply specifie" "d"); while (*s == ' ') s++; if (!('0' <= *s && *s <= '9')) error1(mpl, str, s, fmt, f, "minute missing or invali" "d"); mm = (*s++) - '0'; if ('0' <= *s && *s <= '9') mm = 10 * mm + ((*s++) - '0'); if (!(0 <= mm && mm <= 59)) error1(mpl, str, s, fmt, f, "minute out of range"); } else if (*f == 'S') { /* the second as a decimal number (00..60) */ if (ss >= 0) error1(mpl, str, s, fmt, f, "second multiply specifie" "d"); while (*s == ' ') s++; if (!('0' <= *s && *s <= '9')) error1(mpl, str, s, fmt, f, "second missing or invali" "d"); ss = (*s++) - '0'; if ('0' <= *s && *s <= '9') ss = 10 * ss + ((*s++) - '0'); if (!(0 <= ss && ss <= 60)) error1(mpl, str, s, fmt, f, "second out of range"); } else if (*f == 'y') { /* the year without a century as a decimal number (00..99); the values 00 to 68 mean the years 2000 to 2068 while the values 69 to 99 mean the years 1969 to 1999 */ if (year >= 0) error1(mpl, str, s, fmt, f, "year multiply specified") ; while (*s == ' ') s++; if (!('0' <= *s && *s <= '9')) error1(mpl, str, s, fmt, f, "year missing or invalid") ; year = (*s++) - '0'; if ('0' <= *s && *s <= '9') year = 10 * year + ((*s++) - '0'); year += (year >= 69 ? 1900 : 2000); } else if (*f == 'Y') { /* the year as a decimal number, using the Gregorian calendar */ if (year >= 0) error1(mpl, str, s, fmt, f, "year multiply specified") ; while (*s == ' ') s++; if (!('0' <= *s && *s <= '9')) error1(mpl, str, s, fmt, f, "year missing or invalid") ; year = 0; for (j = 1; j <= 4; j++) { if (!('0' <= *s && *s <= '9')) break; year = 10 * year + ((*s++) - '0'); } if (!(1 <= year && year <= 4000)) error1(mpl, str, s, fmt, f, "year out of range"); } else if (*f == 'z') { /* time zone offset in the form zhhmm */ int z, hh, mm; if (zone != INT_MAX) error1(mpl, str, s, fmt, f, "time zone offset multipl" "y specified"); while (*s == ' ') s++; if (*s == 'Z') { z = hh = mm = 0, s++; goto skip; } if (*s == '+') z = +1, s++; else if (*s == '-') z = -1, s++; else error1(mpl, str, s, fmt, f, "time zone offset sign mi" "ssing"); hh = 0; for (j = 1; j <= 2; j++) { if (!('0' <= *s && *s <= '9')) err1: error1(mpl, str, s, fmt, f, "time zone offset valu" "e incomplete or invalid"); hh = 10 * hh + ((*s++) - '0'); } if (hh > 23) err2: error1(mpl, str, s, fmt, f, "time zone offset value o" "ut of range"); if (*s == ':') { s++; if (!('0' <= *s && *s <= '9')) goto err1; } mm = 0; if (!('0' <= *s && *s <= '9')) goto skip; for (j = 1; j <= 2; j++) { if (!('0' <= *s && *s <= '9')) goto err1; mm = 10 * mm + ((*s++) - '0'); } if (mm > 59) goto err2; skip: zone = z * (60 * hh + mm); } else if (*f == '%') { /* literal % character */ goto test; } else error1(mpl, str, s, fmt, f, "invalid conversion specifie" "r"); } else if (*f == ' ') ; else test: { /* check a matching character in the input string */ if (*s != *f) error1(mpl, str, s, fmt, f, "character mismatch"); s++; } } if (year < 0) year = 1970; if (month < 0) month = 1; if (day < 0) day = 1; if (hh < 0) hh = 0; if (mm < 0) mm = 0; if (ss < 0) ss = 0; if (zone == INT_MAX) zone = 0; j = jday(day, month, year); xassert(j >= 0); return (((double)(j - jday(1, 1, 1970)) * 24.0 + (double)hh) * 60.0 + (double)mm) * 60.0 + (double)ss - 60.0 * (double)zone; } static void error2(MPL *mpl, const char *fmt, const char *f, const char *msg) { xprintf("Format string passed to time2str:\n"); xprintf("%s\n", fmt); xprintf("%*s\n", (f - fmt) + 1, "^"); error(mpl, "%s", msg); /* no return */ } static int weekday(int j) { /* determine weekday number (1 = Mon, ..., 7 = Sun) */ return (j + jday(1, 1, 1970)) % 7 + 1; } static int firstday(int year) { /* determine the first day of the first week for a specified year according to ISO 8601 */ int j; /* if 1 January is Monday, Tuesday, Wednesday or Thursday, it is in week 01; if 1 January is Friday, Saturday or Sunday, it is in week 52 or 53 of the previous year */ j = jday(1, 1, year) - jday(1, 1, 1970); switch (weekday(j)) { case 1: /* 1 Jan is Mon */ j += 0; break; case 2: /* 1 Jan is Tue */ j -= 1; break; case 3: /* 1 Jan is Wed */ j -= 2; break; case 4: /* 1 Jan is Thu */ j -= 3; break; case 5: /* 1 Jan is Fri */ j += 3; break; case 6: /* 1 Jan is Sat */ j += 2; break; case 7: /* 1 Jan is Sun */ j += 1; break; default: xassert(j != j); } /* the first day of the week must be Monday */ xassert(weekday(j) == 1); return j; } void fn_time2str(MPL *mpl, char *str, double t, const char *fmt) { /* convert the calendar time to character string */ int j, year, month, day, hh, mm, ss, len; double temp; const char *f; char buf[MAX_LENGTH+1]; if (!(-62135596800.0 <= t && t <= 64092211199.0)) error(mpl, "time2str(%.*g,...); argument out of range", DBL_DIG, t); t = floor(t + 0.5); temp = fabs(t) / 86400.0; j = (int)floor(temp); if (t < 0.0) { if (temp == floor(temp)) j = - j; else j = - (j + 1); } xassert(jdate(j + jday(1, 1, 1970), &day, &month, &year) == 0); ss = (int)(t - 86400.0 * (double)j); xassert(0 <= ss && ss < 86400); mm = ss / 60, ss %= 60; hh = mm / 60, mm %= 60; len = 0; for (f = fmt; *f != '\0'; f++) { if (*f == '%') { f++; if (*f == 'a') { /* the abbreviated weekday name */ memcpy(buf, week[weekday(j)-1], 3), buf[3] = '\0'; } else if (*f == 'A') { /* the full weekday name */ strcpy(buf, week[weekday(j)-1]); } else if (*f == 'b' || *f == 'h') { /* the abbreviated month name */ memcpy(buf, moon[month-1], 3), buf[3] = '\0'; } else if (*f == 'B') { /* the full month name */ strcpy(buf, moon[month-1]); } else if (*f == 'C') { /* the century of the year */ sprintf(buf, "%02d", year / 100); } else if (*f == 'd') { /* the day of the month as a decimal number (01..31) */ sprintf(buf, "%02d", day); } else if (*f == 'D') { /* the date using the format %m/%d/%y */ sprintf(buf, "%02d/%02d/%02d", month, day, year % 100); } else if (*f == 'e') { /* the day of the month like with %d, but padded with blank (1..31) */ sprintf(buf, "%2d", day); } else if (*f == 'F') { /* the date using the format %Y-%m-%d */ sprintf(buf, "%04d-%02d-%02d", year, month, day); } else if (*f == 'g') { /* the year corresponding to the ISO week number, but without the century (range 00 through 99); this has the same format and value as %y, except that if the ISO week number (see %V) belongs to the previous or next year, that year is used instead */ int iso; if (j < firstday(year)) iso = year - 1; else if (j < firstday(year + 1)) iso = year; else iso = year + 1; sprintf(buf, "%02d", iso % 100); } else if (*f == 'G') { /* the year corresponding to the ISO week number; this has the same format and value as %Y, excepth that if the ISO week number (see %V) belongs to the previous or next year, that year is used instead */ int iso; if (j < firstday(year)) iso = year - 1; else if (j < firstday(year + 1)) iso = year; else iso = year + 1; sprintf(buf, "%04d", iso); } else if (*f == 'H') { /* the hour as a decimal number, using a 24-hour clock (00..23) */ sprintf(buf, "%02d", hh); } else if (*f == 'I') { /* the hour as a decimal number, using a 12-hour clock (01..12) */ sprintf(buf, "%02d", hh == 0 ? 12 : hh <= 12 ? hh : hh - 12); } else if (*f == 'j') { /* the day of the year as a decimal number (001..366) */ sprintf(buf, "%03d", jday(day, month, year) - jday(1, 1, year) + 1); } else if (*f == 'k') { /* the hour as a decimal number, using a 24-hour clock like %H, but padded with blank (0..23) */ sprintf(buf, "%2d", hh); } else if (*f == 'l') { /* the hour as a decimal number, using a 12-hour clock like %I, but padded with blank (1..12) */ sprintf(buf, "%2d", hh == 0 ? 12 : hh <= 12 ? hh : hh - 12); } else if (*f == 'm') { /* the month as a decimal number (01..12) */ sprintf(buf, "%02d", month); } else if (*f == 'M') { /* the minute as a decimal number (00..59) */ sprintf(buf, "%02d", mm); } else if (*f == 'p') { /* either AM or PM, according to the given time value; noon is treated as PM and midnight as AM */ strcpy(buf, hh <= 11 ? "AM" : "PM"); } else if (*f == 'P') { /* either am or pm, according to the given time value; noon is treated as pm and midnight as am */ strcpy(buf, hh <= 11 ? "am" : "pm"); } else if (*f == 'r') { /* the calendar time using the format %I:%M:%S %p */ sprintf(buf, "%02d:%02d:%02d %s", hh == 0 ? 12 : hh <= 12 ? hh : hh - 12, mm, ss, hh <= 11 ? "AM" : "PM"); } else if (*f == 'R') { /* the hour and minute using the format %H:%M */ sprintf(buf, "%02d:%02d", hh, mm); } else if (*f == 'S') { /* the second as a decimal number (00..59) */ sprintf(buf, "%02d", ss); } else if (*f == 'T') { /* the time of day using the format %H:%M:%S */ sprintf(buf, "%02d:%02d:%02d", hh, mm, ss); } else if (*f == 'u') { /* the day of the week as a decimal number (1..7), Monday being 1 */ sprintf(buf, "%d", weekday(j)); } else if (*f == 'U') { /* the week number of the current year as a decimal number (range 00 through 53), starting with the first Sunday as the first day of the first week; days preceding the first Sunday in the year are considered to be in week 00 */ #if 1 /* 09/I-2009 */ #undef sun /* causes compilation error in SunOS */ #endif int sun; /* sun = the first Sunday of the year */ sun = jday(1, 1, year) - jday(1, 1, 1970); sun += (7 - weekday(sun)); sprintf(buf, "%02d", (j + 7 - sun) / 7); } else if (*f == 'V') { /* the ISO week number as a decimal number (range 01 through 53); ISO weeks start with Monday and end with Sunday; week 01 of a year is the first week which has the majority of its days in that year; week 01 of a year can contain days from the previous year; the week before week 01 of a year is the last week (52 or 53) of the previous year even if it contains days from the new year */ int iso; if (j < firstday(year)) iso = j - firstday(year - 1); else if (j < firstday(year + 1)) iso = j - firstday(year); else iso = j - firstday(year + 1); sprintf(buf, "%02d", iso / 7 + 1); } else if (*f == 'w') { /* the day of the week as a decimal number (0..6), Sunday being 0 */ sprintf(buf, "%d", weekday(j) % 7); } else if (*f == 'W') { /* the week number of the current year as a decimal number (range 00 through 53), starting with the first Monday as the first day of the first week; days preceding the first Monday in the year are considered to be in week 00 */ int mon; /* mon = the first Monday of the year */ mon = jday(1, 1, year) - jday(1, 1, 1970); mon += (8 - weekday(mon)) % 7; sprintf(buf, "%02d", (j + 7 - mon) / 7); } else if (*f == 'y') { /* the year without a century as a decimal number (00..99) */ sprintf(buf, "%02d", year % 100); } else if (*f == 'Y') { /* the year as a decimal number, using the Gregorian calendar */ sprintf(buf, "%04d", year); } else if (*f == '%') { /* a literal % character */ buf[0] = '%', buf[1] = '\0'; } else error2(mpl, fmt, f, "invalid conversion specifier"); } else buf[0] = *f, buf[1] = '\0'; if (len + strlen(buf) > MAX_LENGTH) error(mpl, "time2str; output string length exceeds %d chara" "cters", MAX_LENGTH); memcpy(str+len, buf, strlen(buf)); len += strlen(buf); } str[len] = '\0'; return; } /* eof */ Rglpk/src/GLPK/glpgmp.c0000644000176000001440000007603112245352174014353 0ustar ripleyusers/* glpgmp.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #define _GLPSTD_STDIO #if 1 /* 11/VI-2013 */ #include "bignum.h" #endif #include "dmp.h" #include "glpgmp.h" #include "env.h" #define xfault xerror #ifdef HAVE_GMP /* use GNU MP bignum library */ int gmp_pool_count(void) { return 0; } void gmp_free_mem(void) { return; } #else /* use GLPK bignum module */ static DMP *gmp_pool = NULL; static int gmp_size = 0; static unsigned short *gmp_work = NULL; void *gmp_get_atom(int size) { if (gmp_pool == NULL) gmp_pool = dmp_create_pool(); return dmp_get_atom(gmp_pool, size); } void gmp_free_atom(void *ptr, int size) { xassert(gmp_pool != NULL); dmp_free_atom(gmp_pool, ptr, size); return; } int gmp_pool_count(void) { if (gmp_pool == NULL) return 0; else #if 0 /* 10/VI-2013 */ return dmp_in_use(gmp_pool).lo; #else return dmp_in_use(gmp_pool); #endif } unsigned short *gmp_get_work(int size) { xassert(size > 0); if (gmp_size < size) { if (gmp_size == 0) { xassert(gmp_work == NULL); gmp_size = 100; } else { xassert(gmp_work != NULL); xfree(gmp_work); } while (gmp_size < size) gmp_size += gmp_size; gmp_work = xcalloc(gmp_size, sizeof(unsigned short)); } return gmp_work; } void gmp_free_mem(void) { if (gmp_pool != NULL) dmp_delete_pool(gmp_pool); if (gmp_work != NULL) xfree(gmp_work); gmp_pool = NULL; gmp_size = 0; gmp_work = NULL; return; } /*====================================================================*/ mpz_t _mpz_init(void) { /* initialize x, and set its value to 0 */ mpz_t x; x = gmp_get_atom(sizeof(struct mpz)); x->val = 0; x->ptr = NULL; return x; } void mpz_clear(mpz_t x) { /* free the space occupied by x */ mpz_set_si(x, 0); xassert(x->ptr == NULL); /* free the number descriptor */ gmp_free_atom(x, sizeof(struct mpz)); return; } void mpz_set(mpz_t z, mpz_t x) { /* set the value of z from x */ struct mpz_seg *e, *ee, *es; if (z != x) { mpz_set_si(z, 0); z->val = x->val; xassert(z->ptr == NULL); for (e = x->ptr, es = NULL; e != NULL; e = e->next) { ee = gmp_get_atom(sizeof(struct mpz_seg)); memcpy(ee->d, e->d, 12); ee->next = NULL; if (z->ptr == NULL) z->ptr = ee; else es->next = ee; es = ee; } } return; } void mpz_set_si(mpz_t x, int val) { /* set the value of x to val */ struct mpz_seg *e; /* free existing segments, if any */ while (x->ptr != NULL) { e = x->ptr; x->ptr = e->next; gmp_free_atom(e, sizeof(struct mpz_seg)); } /* assign new value */ if (val == 0x80000000) { /* long format is needed */ x->val = -1; x->ptr = e = gmp_get_atom(sizeof(struct mpz_seg)); memset(e->d, 0, 12); e->d[1] = 0x8000; e->next = NULL; } else { /* short format is enough */ x->val = val; } return; } double mpz_get_d(mpz_t x) { /* convert x to a double, truncating if necessary */ struct mpz_seg *e; int j; double val, deg; if (x->ptr == NULL) val = (double)x->val; else { xassert(x->val != 0); val = 0.0; deg = 1.0; for (e = x->ptr; e != NULL; e = e->next) { for (j = 0; j <= 5; j++) { val += deg * (double)((int)e->d[j]); deg *= 65536.0; } } if (x->val < 0) val = - val; } return val; } double mpz_get_d_2exp(int *exp, mpz_t x) { /* convert x to a double, truncating if necessary (i.e. rounding towards zero), and returning the exponent separately; the return value is in the range 0.5 <= |d| < 1 and the exponent is stored to *exp; d*2^exp is the (truncated) x value; if x is zero, the return is 0.0 and 0 is stored to *exp; this is similar to the standard C frexp function */ struct mpz_seg *e; int j, n, n1; double val; if (x->ptr == NULL) val = (double)x->val, n = 0; else { xassert(x->val != 0); val = 0.0, n = 0; for (e = x->ptr; e != NULL; e = e->next) { for (j = 0; j <= 5; j++) { val += (double)((int)e->d[j]); val /= 65536.0, n += 16; } } if (x->val < 0) val = - val; } val = frexp(val, &n1); *exp = n + n1; return val; } void mpz_swap(mpz_t x, mpz_t y) { /* swap the values x and y efficiently */ int val; void *ptr; val = x->val, ptr = x->ptr; x->val = y->val, x->ptr = y->ptr; y->val = val, y->ptr = ptr; return; } static void normalize(mpz_t x) { /* normalize integer x that includes removing non-significant (leading) zeros and converting to short format, if possible */ struct mpz_seg *es, *e; /* if the integer is in short format, it remains unchanged */ if (x->ptr == NULL) { xassert(x->val != 0x80000000); goto done; } xassert(x->val == +1 || x->val == -1); /* find the last (most significant) non-zero segment */ es = NULL; for (e = x->ptr; e != NULL; e = e->next) { if (e->d[0] || e->d[1] || e->d[2] || e->d[3] || e->d[4] || e->d[5]) es = e; } /* if all segments contain zeros, the integer is zero */ if (es == NULL) { mpz_set_si(x, 0); goto done; } /* remove non-significant (leading) zero segments */ while (es->next != NULL) { e = es->next; es->next = e->next; gmp_free_atom(e, sizeof(struct mpz_seg)); } /* convert the integer to short format, if possible */ e = x->ptr; if (e->next == NULL && e->d[1] <= 0x7FFF && !e->d[2] && !e->d[3] && !e->d[4] && !e->d[5]) { int val; val = (int)e->d[0] + ((int)e->d[1] << 16); if (x->val < 0) val = - val; mpz_set_si(x, val); } done: return; } void mpz_add(mpz_t z, mpz_t x, mpz_t y) { /* set z to x + y */ static struct mpz_seg zero = { { 0, 0, 0, 0, 0, 0 }, NULL }; struct mpz_seg dumx, dumy, *ex, *ey, *ez, *es, *ee; int k, sx, sy, sz; unsigned int t; /* if [x] = 0 then [z] = [y] */ if (x->val == 0) { xassert(x->ptr == NULL); mpz_set(z, y); goto done; } /* if [y] = 0 then [z] = [x] */ if (y->val == 0) { xassert(y->ptr == NULL); mpz_set(z, x); goto done; } /* special case when both [x] and [y] are in short format */ if (x->ptr == NULL && y->ptr == NULL) { int xval = x->val, yval = y->val, zval = x->val + y->val; xassert(xval != 0x80000000 && yval != 0x80000000); if (!(xval > 0 && yval > 0 && zval <= 0 || xval < 0 && yval < 0 && zval >= 0)) { mpz_set_si(z, zval); goto done; } } /* convert [x] to long format, if necessary */ if (x->ptr == NULL) { xassert(x->val != 0x80000000); if (x->val >= 0) { sx = +1; t = (unsigned int)(+ x->val); } else { sx = -1; t = (unsigned int)(- x->val); } ex = &dumx; ex->d[0] = (unsigned short)t; ex->d[1] = (unsigned short)(t >> 16); ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0; ex->next = NULL; } else { sx = x->val; xassert(sx == +1 || sx == -1); ex = x->ptr; } /* convert [y] to long format, if necessary */ if (y->ptr == NULL) { xassert(y->val != 0x80000000); if (y->val >= 0) { sy = +1; t = (unsigned int)(+ y->val); } else { sy = -1; t = (unsigned int)(- y->val); } ey = &dumy; ey->d[0] = (unsigned short)t; ey->d[1] = (unsigned short)(t >> 16); ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0; ey->next = NULL; } else { sy = y->val; xassert(sy == +1 || sy == -1); ey = y->ptr; } /* main fragment */ sz = sx; ez = es = NULL; if (sx > 0 && sy > 0 || sx < 0 && sy < 0) { /* [x] and [y] have identical signs -- addition */ t = 0; for (; ex || ey; ex = ex->next, ey = ey->next) { if (ex == NULL) ex = &zero; if (ey == NULL) ey = &zero; ee = gmp_get_atom(sizeof(struct mpz_seg)); for (k = 0; k <= 5; k++) { t += (unsigned int)ex->d[k]; t += (unsigned int)ey->d[k]; ee->d[k] = (unsigned short)t; t >>= 16; } ee->next = NULL; if (ez == NULL) ez = ee; else es->next = ee; es = ee; } if (t) { /* overflow -- one extra digit is needed */ ee = gmp_get_atom(sizeof(struct mpz_seg)); ee->d[0] = 1; ee->d[1] = ee->d[2] = ee->d[3] = ee->d[4] = ee->d[5] = 0; ee->next = NULL; xassert(es != NULL); es->next = ee; } } else { /* [x] and [y] have different signs -- subtraction */ t = 1; for (; ex || ey; ex = ex->next, ey = ey->next) { if (ex == NULL) ex = &zero; if (ey == NULL) ey = &zero; ee = gmp_get_atom(sizeof(struct mpz_seg)); for (k = 0; k <= 5; k++) { t += (unsigned int)ex->d[k]; t += (0xFFFF - (unsigned int)ey->d[k]); ee->d[k] = (unsigned short)t; t >>= 16; } ee->next = NULL; if (ez == NULL) ez = ee; else es->next = ee; es = ee; } if (!t) { /* |[x]| < |[y]| -- result in complement coding */ sz = - sz; t = 1; for (ee = ez; ee != NULL; ee = ee->next) for (k = 0; k <= 5; k++) { t += (0xFFFF - (unsigned int)ee->d[k]); ee->d[k] = (unsigned short)t; t >>= 16; } } } /* contruct and normalize result */ mpz_set_si(z, 0); z->val = sz; z->ptr = ez; normalize(z); done: return; } void mpz_sub(mpz_t z, mpz_t x, mpz_t y) { /* set z to x - y */ if (x == y) mpz_set_si(z, 0); else { y->val = - y->val; mpz_add(z, x, y); if (y != z) y->val = - y->val; } return; } void mpz_mul(mpz_t z, mpz_t x, mpz_t y) { /* set z to x * y */ struct mpz_seg dumx, dumy, *ex, *ey, *es, *e; int sx, sy, k, nx, ny, n; unsigned int t; unsigned short *work, *wx, *wy; /* if [x] = 0 then [z] = 0 */ if (x->val == 0) { xassert(x->ptr == NULL); mpz_set_si(z, 0); goto done; } /* if [y] = 0 then [z] = 0 */ if (y->val == 0) { xassert(y->ptr == NULL); mpz_set_si(z, 0); goto done; } /* special case when both [x] and [y] are in short format */ if (x->ptr == NULL && y->ptr == NULL) { int xval = x->val, yval = y->val, sz = +1; xassert(xval != 0x80000000 && yval != 0x80000000); if (xval < 0) xval = - xval, sz = - sz; if (yval < 0) yval = - yval, sz = - sz; if (xval <= 0x7FFFFFFF / yval) { mpz_set_si(z, sz * (xval * yval)); goto done; } } /* convert [x] to long format, if necessary */ if (x->ptr == NULL) { xassert(x->val != 0x80000000); if (x->val >= 0) { sx = +1; t = (unsigned int)(+ x->val); } else { sx = -1; t = (unsigned int)(- x->val); } ex = &dumx; ex->d[0] = (unsigned short)t; ex->d[1] = (unsigned short)(t >> 16); ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0; ex->next = NULL; } else { sx = x->val; xassert(sx == +1 || sx == -1); ex = x->ptr; } /* convert [y] to long format, if necessary */ if (y->ptr == NULL) { xassert(y->val != 0x80000000); if (y->val >= 0) { sy = +1; t = (unsigned int)(+ y->val); } else { sy = -1; t = (unsigned int)(- y->val); } ey = &dumy; ey->d[0] = (unsigned short)t; ey->d[1] = (unsigned short)(t >> 16); ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0; ey->next = NULL; } else { sy = y->val; xassert(sy == +1 || sy == -1); ey = y->ptr; } /* determine the number of digits of [x] */ nx = n = 0; for (e = ex; e != NULL; e = e->next) for (k = 0; k <= 5; k++) { n++; if (e->d[k]) nx = n; } xassert(nx > 0); /* determine the number of digits of [y] */ ny = n = 0; for (e = ey; e != NULL; e = e->next) for (k = 0; k <= 5; k++) { n++; if (e->d[k]) ny = n; } xassert(ny > 0); /* we need working array containing at least nx+ny+ny places */ work = gmp_get_work(nx+ny+ny); /* load digits of [x] */ wx = &work[0]; for (n = 0; n < nx; n++) wx[ny+n] = 0; for (n = 0, e = ex; e != NULL; e = e->next) for (k = 0; k <= 5; k++, n++) if (e->d[k]) wx[ny+n] = e->d[k]; /* load digits of [y] */ wy = &work[nx+ny]; for (n = 0; n < ny; n++) wy[n] = 0; for (n = 0, e = ey; e != NULL; e = e->next) for (k = 0; k <= 5; k++, n++) if (e->d[k]) wy[n] = e->d[k]; /* compute [x] * [y] */ bigmul(nx, ny, wx, wy); /* construct and normalize result */ mpz_set_si(z, 0); z->val = sx * sy; es = NULL; k = 6; for (n = 0; n < nx+ny; n++) { if (k > 5) { e = gmp_get_atom(sizeof(struct mpz_seg)); e->d[0] = e->d[1] = e->d[2] = 0; e->d[3] = e->d[4] = e->d[5] = 0; e->next = NULL; if (z->ptr == NULL) z->ptr = e; else es->next = e; es = e; k = 0; } es->d[k++] = wx[n]; } normalize(z); done: return; } void mpz_neg(mpz_t z, mpz_t x) { /* set z to 0 - x */ mpz_set(z, x); z->val = - z->val; return; } void mpz_abs(mpz_t z, mpz_t x) { /* set z to the absolute value of x */ mpz_set(z, x); if (z->val < 0) z->val = - z->val; return; } void mpz_div(mpz_t q, mpz_t r, mpz_t x, mpz_t y) { /* divide x by y, forming quotient q and/or remainder r if q = NULL then quotient is not stored; if r = NULL then remainder is not stored the sign of quotient is determined as in algebra while the sign of remainder is the same as the sign of dividend: +26 : +7 = +3, remainder is +5 -26 : +7 = -3, remainder is -5 +26 : -7 = -3, remainder is +5 -26 : -7 = +3, remainder is -5 */ struct mpz_seg dumx, dumy, *ex, *ey, *es, *e; int sx, sy, k, nx, ny, n; unsigned int t; unsigned short *work, *wx, *wy; /* divide by zero is not allowed */ if (y->val == 0) { xassert(y->ptr == NULL); xfault("mpz_div: divide by zero not allowed\n"); } /* if [x] = 0 then [q] = [r] = 0 */ if (x->val == 0) { xassert(x->ptr == NULL); if (q != NULL) mpz_set_si(q, 0); if (r != NULL) mpz_set_si(r, 0); goto done; } /* special case when both [x] and [y] are in short format */ if (x->ptr == NULL && y->ptr == NULL) { int xval = x->val, yval = y->val; xassert(xval != 0x80000000 && yval != 0x80000000); if (q != NULL) mpz_set_si(q, xval / yval); if (r != NULL) mpz_set_si(r, xval % yval); goto done; } /* convert [x] to long format, if necessary */ if (x->ptr == NULL) { xassert(x->val != 0x80000000); if (x->val >= 0) { sx = +1; t = (unsigned int)(+ x->val); } else { sx = -1; t = (unsigned int)(- x->val); } ex = &dumx; ex->d[0] = (unsigned short)t; ex->d[1] = (unsigned short)(t >> 16); ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0; ex->next = NULL; } else { sx = x->val; xassert(sx == +1 || sx == -1); ex = x->ptr; } /* convert [y] to long format, if necessary */ if (y->ptr == NULL) { xassert(y->val != 0x80000000); if (y->val >= 0) { sy = +1; t = (unsigned int)(+ y->val); } else { sy = -1; t = (unsigned int)(- y->val); } ey = &dumy; ey->d[0] = (unsigned short)t; ey->d[1] = (unsigned short)(t >> 16); ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0; ey->next = NULL; } else { sy = y->val; xassert(sy == +1 || sy == -1); ey = y->ptr; } /* determine the number of digits of [x] */ nx = n = 0; for (e = ex; e != NULL; e = e->next) for (k = 0; k <= 5; k++) { n++; if (e->d[k]) nx = n; } xassert(nx > 0); /* determine the number of digits of [y] */ ny = n = 0; for (e = ey; e != NULL; e = e->next) for (k = 0; k <= 5; k++) { n++; if (e->d[k]) ny = n; } xassert(ny > 0); /* if nx < ny then [q] = 0 and [r] = [x] */ if (nx < ny) { if (r != NULL) mpz_set(r, x); if (q != NULL) mpz_set_si(q, 0); goto done; } /* we need working array containing at least nx+ny+1 places */ work = gmp_get_work(nx+ny+1); /* load digits of [x] */ wx = &work[0]; for (n = 0; n < nx; n++) wx[n] = 0; for (n = 0, e = ex; e != NULL; e = e->next) for (k = 0; k <= 5; k++, n++) if (e->d[k]) wx[n] = e->d[k]; /* load digits of [y] */ wy = &work[nx+1]; for (n = 0; n < ny; n++) wy[n] = 0; for (n = 0, e = ey; e != NULL; e = e->next) for (k = 0; k <= 5; k++, n++) if (e->d[k]) wy[n] = e->d[k]; /* compute quotient and remainder */ xassert(wy[ny-1] != 0); bigdiv(nx-ny, ny, wx, wy); /* construct and normalize quotient */ if (q != NULL) { mpz_set_si(q, 0); q->val = sx * sy; es = NULL; k = 6; for (n = ny; n <= nx; n++) { if (k > 5) { e = gmp_get_atom(sizeof(struct mpz_seg)); e->d[0] = e->d[1] = e->d[2] = 0; e->d[3] = e->d[4] = e->d[5] = 0; e->next = NULL; if (q->ptr == NULL) q->ptr = e; else es->next = e; es = e; k = 0; } es->d[k++] = wx[n]; } normalize(q); } /* construct and normalize remainder */ if (r != NULL) { mpz_set_si(r, 0); r->val = sx; es = NULL; k = 6; for (n = 0; n < ny; n++) { if (k > 5) { e = gmp_get_atom(sizeof(struct mpz_seg)); e->d[0] = e->d[1] = e->d[2] = 0; e->d[3] = e->d[4] = e->d[5] = 0; e->next = NULL; if (r->ptr == NULL) r->ptr = e; else es->next = e; es = e; k = 0; } es->d[k++] = wx[n]; } normalize(r); } done: return; } void mpz_gcd(mpz_t z, mpz_t x, mpz_t y) { /* set z to the greatest common divisor of x and y */ /* in case of arbitrary integers GCD(x, y) = GCD(|x|, |y|), and, in particular, GCD(0, 0) = 0 */ mpz_t u, v, r; mpz_init(u); mpz_init(v); mpz_init(r); mpz_abs(u, x); mpz_abs(v, y); while (mpz_sgn(v)) { mpz_div(NULL, r, u, v); mpz_set(u, v); mpz_set(v, r); } mpz_set(z, u); mpz_clear(u); mpz_clear(v); mpz_clear(r); return; } int mpz_cmp(mpz_t x, mpz_t y) { /* compare x and y; return a positive value if x > y, zero if x = y, or a nefative value if x < y */ static struct mpz_seg zero = { { 0, 0, 0, 0, 0, 0 }, NULL }; struct mpz_seg dumx, dumy, *ex, *ey; int cc, sx, sy, k; unsigned int t; if (x == y) { cc = 0; goto done; } /* special case when both [x] and [y] are in short format */ if (x->ptr == NULL && y->ptr == NULL) { int xval = x->val, yval = y->val; xassert(xval != 0x80000000 && yval != 0x80000000); cc = (xval > yval ? +1 : xval < yval ? -1 : 0); goto done; } /* special case when [x] and [y] have different signs */ if (x->val > 0 && y->val <= 0 || x->val == 0 && y->val < 0) { cc = +1; goto done; } if (x->val < 0 && y->val >= 0 || x->val == 0 && y->val > 0) { cc = -1; goto done; } /* convert [x] to long format, if necessary */ if (x->ptr == NULL) { xassert(x->val != 0x80000000); if (x->val >= 0) { sx = +1; t = (unsigned int)(+ x->val); } else { sx = -1; t = (unsigned int)(- x->val); } ex = &dumx; ex->d[0] = (unsigned short)t; ex->d[1] = (unsigned short)(t >> 16); ex->d[2] = ex->d[3] = ex->d[4] = ex->d[5] = 0; ex->next = NULL; } else { sx = x->val; xassert(sx == +1 || sx == -1); ex = x->ptr; } /* convert [y] to long format, if necessary */ if (y->ptr == NULL) { xassert(y->val != 0x80000000); if (y->val >= 0) { sy = +1; t = (unsigned int)(+ y->val); } else { sy = -1; t = (unsigned int)(- y->val); } ey = &dumy; ey->d[0] = (unsigned short)t; ey->d[1] = (unsigned short)(t >> 16); ey->d[2] = ey->d[3] = ey->d[4] = ey->d[5] = 0; ey->next = NULL; } else { sy = y->val; xassert(sy == +1 || sy == -1); ey = y->ptr; } /* main fragment */ xassert(sx > 0 && sy > 0 || sx < 0 && sy < 0); cc = 0; for (; ex || ey; ex = ex->next, ey = ey->next) { if (ex == NULL) ex = &zero; if (ey == NULL) ey = &zero; for (k = 0; k <= 5; k++) { if (ex->d[k] > ey->d[k]) cc = +1; if (ex->d[k] < ey->d[k]) cc = -1; } } if (sx < 0) cc = - cc; done: return cc; } int mpz_sgn(mpz_t x) { /* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */ int s; s = (x->val > 0 ? +1 : x->val < 0 ? -1 : 0); return s; } int mpz_out_str(void *_fp, int base, mpz_t x) { /* output x on stream fp, as a string in given base; the base may vary from 2 to 36; return the number of bytes written, or if an error occurred, return 0 */ FILE *fp = _fp; mpz_t b, y, r; int n, j, nwr = 0; unsigned char *d; static char *set = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; if (!(2 <= base && base <= 36)) xfault("mpz_out_str: base = %d; invalid base\n", base); mpz_init(b); mpz_set_si(b, base); mpz_init(y); mpz_init(r); /* determine the number of digits */ mpz_abs(y, x); for (n = 0; mpz_sgn(y) != 0; n++) mpz_div(y, NULL, y, b); if (n == 0) n = 1; /* compute the digits */ d = xmalloc(n); mpz_abs(y, x); for (j = 0; j < n; j++) { mpz_div(y, r, y, b); xassert(0 <= r->val && r->val < base && r->ptr == NULL); d[j] = (unsigned char)r->val; } /* output the integer to the stream */ if (fp == NULL) fp = stdout; if (mpz_sgn(x) < 0) fputc('-', fp), nwr++; for (j = n-1; j >= 0; j--) fputc(set[d[j]], fp), nwr++; if (ferror(fp)) nwr = 0; mpz_clear(b); mpz_clear(y); mpz_clear(r); xfree(d); return nwr; } /*====================================================================*/ mpq_t _mpq_init(void) { /* initialize x, and set its value to 0/1 */ mpq_t x; x = gmp_get_atom(sizeof(struct mpq)); x->p.val = 0; x->p.ptr = NULL; x->q.val = 1; x->q.ptr = NULL; return x; } void mpq_clear(mpq_t x) { /* free the space occupied by x */ mpz_set_si(&x->p, 0); xassert(x->p.ptr == NULL); mpz_set_si(&x->q, 0); xassert(x->q.ptr == NULL); /* free the number descriptor */ gmp_free_atom(x, sizeof(struct mpq)); return; } void mpq_canonicalize(mpq_t x) { /* remove any factors that are common to the numerator and denominator of x, and make the denominator positive */ mpz_t f; xassert(x->q.val != 0); if (x->q.val < 0) { mpz_neg(&x->p, &x->p); mpz_neg(&x->q, &x->q); } mpz_init(f); mpz_gcd(f, &x->p, &x->q); if (!(f->val == 1 && f->ptr == NULL)) { mpz_div(&x->p, NULL, &x->p, f); mpz_div(&x->q, NULL, &x->q, f); } mpz_clear(f); return; } void mpq_set(mpq_t z, mpq_t x) { /* set the value of z from x */ if (z != x) { mpz_set(&z->p, &x->p); mpz_set(&z->q, &x->q); } return; } void mpq_set_si(mpq_t x, int p, unsigned int q) { /* set the value of x to p/q */ if (q == 0) xfault("mpq_set_si: zero denominator not allowed\n"); mpz_set_si(&x->p, p); xassert(q <= 0x7FFFFFFF); mpz_set_si(&x->q, q); return; } double mpq_get_d(mpq_t x) { /* convert x to a double, truncating if necessary */ int np, nq; double p, q; p = mpz_get_d_2exp(&np, &x->p); q = mpz_get_d_2exp(&nq, &x->q); return ldexp(p / q, np - nq); } void mpq_set_d(mpq_t x, double val) { /* set x to val; there is no rounding, the conversion is exact */ int s, n, d, j; double f; mpz_t temp; xassert(-DBL_MAX <= val && val <= +DBL_MAX); mpq_set_si(x, 0, 1); if (val > 0.0) s = +1; else if (val < 0.0) s = -1; else goto done; f = frexp(fabs(val), &n); /* |val| = f * 2^n, where 0.5 <= f < 1.0 */ mpz_init(temp); while (f != 0.0) { f *= 16.0, n -= 4; d = (int)f; xassert(0 <= d && d <= 15); f -= (double)d; /* x := 16 * x + d */ mpz_set_si(temp, 16); mpz_mul(&x->p, &x->p, temp); mpz_set_si(temp, d); mpz_add(&x->p, &x->p, temp); } mpz_clear(temp); /* x := x * 2^n */ if (n > 0) { for (j = 1; j <= n; j++) mpz_add(&x->p, &x->p, &x->p); } else if (n < 0) { for (j = 1; j <= -n; j++) mpz_add(&x->q, &x->q, &x->q); mpq_canonicalize(x); } if (s < 0) mpq_neg(x, x); done: return; } void mpq_add(mpq_t z, mpq_t x, mpq_t y) { /* set z to x + y */ mpz_t p, q; mpz_init(p); mpz_init(q); mpz_mul(p, &x->p, &y->q); mpz_mul(q, &x->q, &y->p); mpz_add(p, p, q); mpz_mul(q, &x->q, &y->q); mpz_set(&z->p, p); mpz_set(&z->q, q); mpz_clear(p); mpz_clear(q); mpq_canonicalize(z); return; } void mpq_sub(mpq_t z, mpq_t x, mpq_t y) { /* set z to x - y */ mpz_t p, q; mpz_init(p); mpz_init(q); mpz_mul(p, &x->p, &y->q); mpz_mul(q, &x->q, &y->p); mpz_sub(p, p, q); mpz_mul(q, &x->q, &y->q); mpz_set(&z->p, p); mpz_set(&z->q, q); mpz_clear(p); mpz_clear(q); mpq_canonicalize(z); return; } void mpq_mul(mpq_t z, mpq_t x, mpq_t y) { /* set z to x * y */ mpz_mul(&z->p, &x->p, &y->p); mpz_mul(&z->q, &x->q, &y->q); mpq_canonicalize(z); return; } void mpq_div(mpq_t z, mpq_t x, mpq_t y) { /* set z to x / y */ mpz_t p, q; if (mpq_sgn(y) == 0) xfault("mpq_div: zero divisor not allowed\n"); mpz_init(p); mpz_init(q); mpz_mul(p, &x->p, &y->q); mpz_mul(q, &x->q, &y->p); mpz_set(&z->p, p); mpz_set(&z->q, q); mpz_clear(p); mpz_clear(q); mpq_canonicalize(z); return; } void mpq_neg(mpq_t z, mpq_t x) { /* set z to 0 - x */ mpq_set(z, x); mpz_neg(&z->p, &z->p); return; } void mpq_abs(mpq_t z, mpq_t x) { /* set z to the absolute value of x */ mpq_set(z, x); mpz_abs(&z->p, &z->p); xassert(mpz_sgn(&x->q) > 0); return; } int mpq_cmp(mpq_t x, mpq_t y) { /* compare x and y; return a positive value if x > y, zero if x = y, or a nefative value if x < y */ mpq_t temp; int s; mpq_init(temp); mpq_sub(temp, x, y); s = mpq_sgn(temp); mpq_clear(temp); return s; } int mpq_sgn(mpq_t x) { /* return +1 if x > 0, 0 if x = 0, and -1 if x < 0 */ int s; s = mpz_sgn(&x->p); xassert(mpz_sgn(&x->q) > 0); return s; } int mpq_out_str(void *_fp, int base, mpq_t x) { /* output x on stream fp, as a string in given base; the base may vary from 2 to 36; output is in the form 'num/den' or if the denominator is 1 then just 'num'; if the parameter fp is a null pointer, stdout is assumed; return the number of bytes written, or if an error occurred, return 0 */ FILE *fp = _fp; int nwr; if (!(2 <= base && base <= 36)) xfault("mpq_out_str: base = %d; invalid base\n", base); if (fp == NULL) fp = stdout; nwr = mpz_out_str(fp, base, &x->p); if (x->q.val == 1 && x->q.ptr == NULL) ; else { fputc('/', fp), nwr++; nwr += mpz_out_str(fp, base, &x->q); } if (ferror(fp)) nwr = 0; return nwr; } #endif /* eof */ Rglpk/src/GLPK/glpnet04.c0000644000176000001440000006213712245352174014524 0ustar ripleyusers/* glpnet04.c (grid-like network problem generator) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * This code is a modified version of the program GRIDGEN, a grid-like * network problem generator developed by Yusin Lee and Jim Orlin. * The original code is publically available on the DIMACS ftp site at: * . * * All changes concern only the program interface, so this modified * version produces exactly the same instances as the original version. * * Changes were made by Andrew Makhorin . * * 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 . ***********************************************************************/ #include "glpapi.h" /*********************************************************************** * NAME * * glp_gridgen - grid-like network problem generator * * SYNOPSIS * * int glp_gridgen(glp_graph *G, int v_rhs, int a_cap, int a_cost, * const int parm[1+14]); * * DESCRIPTION * * The routine glp_gridgen is a grid-like network problem generator * developed by Yusin Lee and Jim Orlin. * * The parameter G specifies the graph object, to which the generated * problem data have to be stored. Note that on entry the graph object * is erased with the routine glp_erase_graph. * * The parameter v_rhs specifies an offset of the field of type double * in the vertex data block, to which the routine stores the supply or * demand value. If v_rhs < 0, the value is not stored. * * The parameter a_cap specifies an offset of the field of type double * in the arc data block, to which the routine stores the arc capacity. * If a_cap < 0, the capacity is not stored. * * The parameter a_cost specifies an offset of the field of type double * in the arc data block, to which the routine stores the per-unit cost * if the arc flow. If a_cost < 0, the cost is not stored. * * The array parm contains description of the network to be generated: * * parm[0] not used * parm[1] two-ways arcs indicator: * 1 - if links in both direction should be generated * 0 - otherwise * parm[2] random number seed (a positive integer) * parm[3] number of nodes (the number of nodes generated might be * slightly different to make the network a grid) * parm[4] grid width * parm[5] number of sources * parm[6] number of sinks * parm[7] average degree * parm[8] total flow * parm[9] distribution of arc costs: * 1 - uniform * 2 - exponential * parm[10] lower bound for arc cost (uniform) * 100 * lambda (exponential) * parm[11] upper bound for arc cost (uniform) * not used (exponential) * parm[12] distribution of arc capacities: * 1 - uniform * 2 - exponential * parm[13] lower bound for arc capacity (uniform) * 100 * lambda (exponential) * parm[14] upper bound for arc capacity (uniform) * not used (exponential) * * RETURNS * * If the instance was successfully generated, the routine glp_gridgen * returns zero; otherwise, if specified parameters are inconsistent, * the routine returns a non-zero error code. * * COMMENTS * * This network generator generates a grid-like network plus a super * node. In additional to the arcs connecting the nodes in the grid, * there is an arc from each supply node to the super node and from the * super node to each demand node to guarantee feasiblity. These arcs * have very high costs and very big capacities. * * The idea of this network generator is as follows: First, a grid of * n1 * n2 is generated. For example, 5 * 3. The nodes are numbered as * 1 to 15, and the supernode is numbered as n1*n2+1. Then arcs between * adjacent nodes are generated. For these arcs, the user is allowed to * specify either to generate two-way arcs or one-way arcs. If two-way * arcs are to be generated, two arcs, one in each direction, will be * generated between each adjacent node pairs. Otherwise, only one arc * will be generated. If this is the case, the arcs will be generated * in alterntive directions as shown below. * * 1 ---> 2 ---> 3 ---> 4 ---> 5 * | ^ | ^ | * | | | | | * V | V | V * 6 <--- 7 <--- 8 <--- 9 <--- 10 * | ^ | ^ | * | | | | | * V | V | V * 11 --->12 --->13 --->14 ---> 15 * * Then the arcs between the super node and the source/sink nodes are * added as mentioned before. If the number of arcs still doesn't reach * the requirement, additional arcs will be added by uniformly picking * random node pairs. There is no checking to prevent multiple arcs * between any pair of nodes. However, there will be no self-arcs (arcs * that poins back to its tail node) in the network. * * The source and sink nodes are selected uniformly in the network, and * the imbalances of each source/sink node are also assigned by uniform * distribution. */ struct stat_para { /* structure for statistical distributions */ int distribution; /* the distribution: */ #define UNIFORM 1 /* uniform distribution */ #define EXPONENTIAL 2 /* exponential distribution */ double parameter[5]; /* the parameters of the distribution */ }; struct arcs { int from; /* the FROM node of that arc */ int to; /* the TO node of that arc */ int cost; /* original cost of that arc */ int u; /* capacity of the arc */ }; struct imbalance { int node; /* Node ID */ int supply; /* Supply of that node */ }; struct csa { /* common storage area */ glp_graph *G; int v_rhs, a_cap, a_cost; int seed; /* random number seed */ int seed_original; /* the original seed from input */ int two_way; /* 0: generate arcs in both direction for the basic grid, except for the arcs to/from the super node. 1: o/w */ int n_node; /* total number of nodes in the network, numbered 1 to n_node, including the super node, which is the last one */ int n_arc; /* total number of arcs in the network, counting EVERY arc. */ int n_grid_arc; /* number of arcs in the basic grid, including the arcs to/from the super node */ int n_source, n_sink; /* number of source and sink nodes */ int avg_degree; /* average degree, arcs to and from the super node are counted */ int t_supply; /* total supply in the network */ int n1, n2; /* the two edges of the network grid. n1 >= n2 */ struct imbalance *source_list, *sink_list; /* head of the array of source/sink nodes */ struct stat_para arc_costs; /* the distribution of arc costs */ struct stat_para capacities; /* distribution of the capacities of the arcs */ struct arcs *arc_list; /* head of the arc list array. Arcs in this array are in the order of grid_arcs, arcs to/from super node, and other arcs */ }; #define G (csa->G) #define v_rhs (csa->v_rhs) #define a_cap (csa->a_cap) #define a_cost (csa->a_cost) #define seed (csa->seed) #define seed_original (csa->seed_original) #define two_way (csa->two_way) #define n_node (csa->n_node) #define n_arc (csa->n_arc) #define n_grid_arc (csa->n_grid_arc) #define n_source (csa->n_source) #define n_sink (csa->n_sink) #define avg_degree (csa->avg_degree) #define t_supply (csa->t_supply) #define n1 (csa->n1) #define n2 (csa->n2) #define source_list (csa->source_list) #define sink_list (csa->sink_list) #define arc_costs (csa->arc_costs) #define capacities (csa->capacities) #define arc_list (csa->arc_list) static void assign_capacities(struct csa *csa); static void assign_costs(struct csa *csa); static void assign_imbalance(struct csa *csa); static int exponential(struct csa *csa, double lambda[1]); static struct arcs *gen_additional_arcs(struct csa *csa, struct arcs *arc_ptr); static struct arcs *gen_basic_grid(struct csa *csa, struct arcs *arc_ptr); static void gen_more_arcs(struct csa *csa, struct arcs *arc_ptr); static void generate(struct csa *csa); static void output(struct csa *csa); static double randy(struct csa *csa); static void select_source_sinks(struct csa *csa); static int uniform(struct csa *csa, double a[2]); int glp_gridgen(glp_graph *G_, int _v_rhs, int _a_cap, int _a_cost, const int parm[1+14]) { struct csa _csa, *csa = &_csa; int n, ret; G = G_; v_rhs = _v_rhs; a_cap = _a_cap; a_cost = _a_cost; if (G != NULL) { if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double)) xerror("glp_gridgen: v_rhs = %d; invalid offset\n", v_rhs); if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) xerror("glp_gridgen: a_cap = %d; invalid offset\n", a_cap); if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) xerror("glp_gridgen: a_cost = %d; invalid offset\n", a_cost) ; } /* Check the parameters for consistency. */ if (!(parm[1] == 0 || parm[1] == 1)) { ret = 1; goto done; } if (parm[2] < 1) { ret = 2; goto done; } if (!(10 <= parm[3] && parm[3] <= 40000)) { ret = 3; goto done; } if (!(1 <= parm[4] && parm[4] <= 40000)) { ret = 4; goto done; } if (!(parm[5] >= 0 && parm[6] >= 0 && parm[5] + parm[6] <= parm[3])) { ret = 5; goto done; } if (!(1 <= parm[7] && parm[7] <= parm[3])) { ret = 6; goto done; } if (parm[8] < 0) { ret = 7; goto done; } if (!(parm[9] == 1 || parm[9] == 2)) { ret = 8; goto done; } if (parm[9] == 1 && parm[10] > parm[11] || parm[9] == 2 && parm[10] < 1) { ret = 9; goto done; } if (!(parm[12] == 1 || parm[12] == 2)) { ret = 10; goto done; } if (parm[12] == 1 && !(0 <= parm[13] && parm[13] <= parm[14]) || parm[12] == 2 && parm[13] < 1) { ret = 11; goto done; } /* Initialize the graph object. */ if (G != NULL) { glp_erase_graph(G, G->v_size, G->a_size); glp_set_graph_name(G, "GRIDGEN"); } /* Copy the generator parameters. */ two_way = parm[1]; seed_original = seed = parm[2]; n_node = parm[3]; n = parm[4]; n_source = parm[5]; n_sink = parm[6]; avg_degree = parm[7]; t_supply = parm[8]; arc_costs.distribution = parm[9]; if (parm[9] == 1) { arc_costs.parameter[0] = parm[10]; arc_costs.parameter[1] = parm[11]; } else { arc_costs.parameter[0] = (double)parm[10] / 100.0; arc_costs.parameter[1] = 0.0; } capacities.distribution = parm[12]; if (parm[12] == 1) { capacities.parameter[0] = parm[13]; capacities.parameter[1] = parm[14]; } else { capacities.parameter[0] = (double)parm[13] / 100.0; capacities.parameter[1] = 0.0; } /* Calculate the edge lengths of the grid according to the input. */ if (n * n >= n_node) { n1 = n; n2 = (int)((double)n_node / (double)n + 0.5); } else { n2 = n; n1 = (int)((double)n_node / (double)n + 0.5); } /* Recalculate the total number of nodes and plus 1 for the super node. */ n_node = n1 * n2 + 1; n_arc = n_node * avg_degree; n_grid_arc = (two_way + 1) * ((n1 - 1) * n2 + (n2 - 1) * n1) + n_source + n_sink; if (n_grid_arc > n_arc) n_arc = n_grid_arc; arc_list = xcalloc(n_arc, sizeof(struct arcs)); source_list = xcalloc(n_source, sizeof(struct imbalance)); sink_list = xcalloc(n_sink, sizeof(struct imbalance)); /* Generate a random network. */ generate(csa); /* Output the network. */ output(csa); /* Free all allocated memory. */ xfree(arc_list); xfree(source_list); xfree(sink_list); /* The instance has been successfully generated. */ ret = 0; done: return ret; } #undef random static void assign_capacities(struct csa *csa) { /* Assign a capacity to each arc. */ struct arcs *arc_ptr = arc_list; int (*random)(struct csa *csa, double *); int i; /* Determine the random number generator to use. */ switch (arc_costs.distribution) { case UNIFORM: random = uniform; break; case EXPONENTIAL: random = exponential; break; default: xassert(csa != csa); } /* Assign capacities to grid arcs. */ for (i = n_source + n_sink; i < n_grid_arc; i++, arc_ptr++) arc_ptr->u = random(csa, capacities.parameter); i = i - n_source - n_sink; /* Assign capacities to arcs to/from supernode. */ for (; i < n_grid_arc; i++, arc_ptr++) arc_ptr->u = t_supply; /* Assign capacities to all other arcs. */ for (; i < n_arc; i++, arc_ptr++) arc_ptr->u = random(csa, capacities.parameter); return; } static void assign_costs(struct csa *csa) { /* Assign a cost to each arc. */ struct arcs *arc_ptr = arc_list; int (*random)(struct csa *csa, double *); int i; /* A high cost assigned to arcs to/from the supernode. */ int high_cost; /* The maximum cost assigned to arcs in the base grid. */ int max_cost = 0; /* Determine the random number generator to use. */ switch (arc_costs.distribution) { case UNIFORM: random = uniform; break; case EXPONENTIAL: random = exponential; break; default: xassert(csa != csa); } /* Assign costs to arcs in the base grid. */ for (i = n_source + n_sink; i < n_grid_arc; i++, arc_ptr++) { arc_ptr->cost = random(csa, arc_costs.parameter); if (max_cost < arc_ptr->cost) max_cost = arc_ptr->cost; } i = i - n_source - n_sink; /* Assign costs to arcs to/from the super node. */ high_cost = max_cost * 2; for (; i < n_grid_arc; i++, arc_ptr++) arc_ptr->cost = high_cost; /* Assign costs to all other arcs. */ for (; i < n_arc; i++, arc_ptr++) arc_ptr->cost = random(csa, arc_costs.parameter); return; } static void assign_imbalance(struct csa *csa) { /* Assign an imbalance to each node. */ int total, i; double avg; struct imbalance *ptr; /* assign the supply nodes */ avg = 2.0 * t_supply / n_source; do { for (i = 1, total = t_supply, ptr = source_list + 1; i < n_source; i++, ptr++) { ptr->supply = (int)(randy(csa) * avg + 0.5); total -= ptr->supply; } source_list->supply = total; } /* redo all if the assignment "overshooted" */ while (total <= 0); /* assign the demand nodes */ avg = -2.0 * t_supply / n_sink; do { for (i = 1, total = t_supply, ptr = sink_list + 1; i < n_sink; i++, ptr++) { ptr->supply = (int)(randy(csa) * avg - 0.5); total += ptr->supply; } sink_list->supply = - total; } while (total <= 0); return; } static int exponential(struct csa *csa, double lambda[1]) { /* Returns an "exponentially distributed" integer with parameter lambda. */ return ((int)(- lambda[0] * log((double)randy(csa)) + 0.5)); } static struct arcs *gen_additional_arcs(struct csa *csa, struct arcs *arc_ptr) { /* Generate an arc from each source to the supernode and from supernode to each sink. */ int i; for (i = 0; i < n_source; i++, arc_ptr++) { arc_ptr->from = source_list[i].node; arc_ptr->to = n_node; } for (i = 0; i < n_sink; i++, arc_ptr++) { arc_ptr->to = sink_list[i].node; arc_ptr->from = n_node; } return arc_ptr; } static struct arcs *gen_basic_grid(struct csa *csa, struct arcs *arc_ptr) { /* Generate the basic grid. */ int direction = 1, i, j, k; if (two_way) { /* Generate an arc in each direction. */ for (i = 1; i < n_node; i += n1) { for (j = i, k = j + n1 - 1; j < k; j++) { arc_ptr->from = j; arc_ptr->to = j + 1; arc_ptr++; arc_ptr->from = j + 1; arc_ptr->to = j; arc_ptr++; } } for (i = 1; i <= n1; i++) { for (j = i + n1; j < n_node; j += n1) { arc_ptr->from = j; arc_ptr->to = j - n1; arc_ptr++; arc_ptr->from = j - n1; arc_ptr->to = j; arc_ptr++; } } } else { /* Generate one arc in each direction. */ for (i = 1; i < n_node; i += n1) { if (direction == 1) j = i; else j = i + 1; for (k = j + n1 - 1; j < k; j++) { arc_ptr->from = j; arc_ptr->to = j + direction; arc_ptr++; } direction = - direction; } for (i = 1; i <= n1; i++) { j = i + n1; if (direction == 1) { for (; j < n_node; j += n1) { arc_ptr->from = j - n1; arc_ptr->to = j; arc_ptr++; } } else { for (; j < n_node; j += n1) { arc_ptr->from = j - n1; arc_ptr->to = j; arc_ptr++; } } direction = - direction; } } return arc_ptr; } static void gen_more_arcs(struct csa *csa, struct arcs *arc_ptr) { /* Generate random arcs to meet the specified density. */ int i; double ab[2]; ab[0] = 0.9; ab[1] = n_node - 0.99; /* upper limit is n_node-1 because the supernode cannot be selected */ for (i = n_grid_arc; i < n_arc; i++, arc_ptr++) { arc_ptr->from = uniform(csa, ab); arc_ptr->to = uniform(csa, ab); if (arc_ptr->from == arc_ptr->to) { arc_ptr--; i--; } } return; } static void generate(struct csa *csa) { /* Generate a random network. */ struct arcs *arc_ptr = arc_list; arc_ptr = gen_basic_grid(csa, arc_ptr); select_source_sinks(csa); arc_ptr = gen_additional_arcs(csa, arc_ptr); gen_more_arcs(csa, arc_ptr); assign_costs(csa); assign_capacities(csa); assign_imbalance(csa); return; } static void output(struct csa *csa) { /* Output the network in DIMACS format. */ struct arcs *arc_ptr; struct imbalance *imb_ptr; int i; if (G != NULL) goto skip; /* Output "c", "p" records. */ xprintf("c generated by GRIDGEN\n"); xprintf("c seed %d\n", seed_original); xprintf("c nodes %d\n", n_node); xprintf("c grid size %d X %d\n", n1, n2); xprintf("c sources %d sinks %d\n", n_source, n_sink); xprintf("c avg. degree %d\n", avg_degree); xprintf("c supply %d\n", t_supply); switch (arc_costs.distribution) { case UNIFORM: xprintf("c arc costs: UNIFORM distr. min %d max %d\n", (int)arc_costs.parameter[0], (int)arc_costs.parameter[1]); break; case EXPONENTIAL: xprintf("c arc costs: EXPONENTIAL distr. lambda %d\n", (int)arc_costs.parameter[0]); break; default: xassert(csa != csa); } switch (capacities.distribution) { case UNIFORM: xprintf("c arc caps : UNIFORM distr. min %d max %d\n", (int)capacities.parameter[0], (int)capacities.parameter[1]); break; case EXPONENTIAL: xprintf("c arc caps : EXPONENTIAL distr. %d lambda %d\n", (int)capacities.parameter[0]); break; default: xassert(csa != csa); } skip: if (G == NULL) xprintf("p min %d %d\n", n_node, n_arc); else { glp_add_vertices(G, n_node); if (v_rhs >= 0) { double zero = 0.0; for (i = 1; i <= n_node; i++) { glp_vertex *v = G->v[i]; memcpy((char *)v->data + v_rhs, &zero, sizeof(double)); } } } /* Output "n node supply". */ for (i = 0, imb_ptr = source_list; i < n_source; i++, imb_ptr++) { if (G == NULL) xprintf("n %d %d\n", imb_ptr->node, imb_ptr->supply); else { if (v_rhs >= 0) { double temp = (double)imb_ptr->supply; glp_vertex *v = G->v[imb_ptr->node]; memcpy((char *)v->data + v_rhs, &temp, sizeof(double)); } } } for (i = 0, imb_ptr = sink_list; i < n_sink; i++, imb_ptr++) { if (G == NULL) xprintf("n %d %d\n", imb_ptr->node, imb_ptr->supply); else { if (v_rhs >= 0) { double temp = (double)imb_ptr->supply; glp_vertex *v = G->v[imb_ptr->node]; memcpy((char *)v->data + v_rhs, &temp, sizeof(double)); } } } /* Output "a from to lowcap=0 hicap cost". */ for (i = 0, arc_ptr = arc_list; i < n_arc; i++, arc_ptr++) { if (G == NULL) xprintf("a %d %d 0 %d %d\n", arc_ptr->from, arc_ptr->to, arc_ptr->u, arc_ptr->cost); else { glp_arc *a = glp_add_arc(G, arc_ptr->from, arc_ptr->to); if (a_cap >= 0) { double temp = (double)arc_ptr->u; memcpy((char *)a->data + a_cap, &temp, sizeof(double)); } if (a_cost >= 0) { double temp = (double)arc_ptr->cost; memcpy((char *)a->data + a_cost, &temp, sizeof(double)); } } } return; } static double randy(struct csa *csa) { /* Returns a random number between 0.0 and 1.0. See Ward Cheney & David Kincaid, "Numerical Mathematics and Computing," 2Ed, pp. 335. */ seed = 16807 * seed % 2147483647; if (seed < 0) seed = - seed; return seed * 4.6566128752459e-10; } static void select_source_sinks(struct csa *csa) { /* Randomly select the source nodes and sink nodes. */ int i, *int_ptr; int *temp_list; /* a temporary list of nodes */ struct imbalance *ptr; double ab[2]; /* parameter for random number generator */ ab[0] = 0.9; ab[1] = n_node - 0.99; /* upper limit is n_node-1 because the supernode cannot be selected */ temp_list = xcalloc(n_node, sizeof(int)); for (i = 0, int_ptr = temp_list; i < n_node; i++, int_ptr++) *int_ptr = 0; /* Select the source nodes. */ for (i = 0, ptr = source_list; i < n_source; i++, ptr++) { ptr->node = uniform(csa, ab); if (temp_list[ptr->node] == 1) /* check for duplicates */ { ptr--; i--; } else temp_list[ptr->node] = 1; } /* Select the sink nodes. */ for (i = 0, ptr = sink_list; i < n_sink; i++, ptr++) { ptr->node = uniform(csa, ab); if (temp_list[ptr->node] == 1) { ptr--; i--; } else temp_list[ptr->node] = 1; } xfree(temp_list); return; } int uniform(struct csa *csa, double a[2]) { /* Generates an integer uniformly selected from [a[0],a[1]]. */ return (int)((a[1] - a[0]) * randy(csa) + a[0] + 0.5); } /**********************************************************************/ #if 0 int main(void) { int parm[1+14]; double temp; scanf("%d", &parm[1]); scanf("%d", &parm[2]); scanf("%d", &parm[3]); scanf("%d", &parm[4]); scanf("%d", &parm[5]); scanf("%d", &parm[6]); scanf("%d", &parm[7]); scanf("%d", &parm[8]); scanf("%d", &parm[9]); if (parm[9] == 1) { scanf("%d", &parm[10]); scanf("%d", &parm[11]); } else { scanf("%le", &temp); parm[10] = (int)(100.0 * temp + .5); parm[11] = 0; } scanf("%d", &parm[12]); if (parm[12] == 1) { scanf("%d", &parm[13]); scanf("%d", &parm[14]); } else { scanf("%le", &temp); parm[13] = (int)(100.0 * temp + .5); parm[14] = 0; } glp_gridgen(NULL, 0, 0, 0, parm); return 0; } #endif /* eof */ Rglpk/src/GLPK/keller.c0000644000176000001440000002230512245352174014336 0ustar ripleyusers/* keller.c (cover edges by cliques, Kellerman's heuristic) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2009, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpk.h" #include "env.h" #include "keller.h" /*********************************************************************** * NAME * * kellerman - cover edges by cliques with Kellerman's heuristic * * SYNOPSIS * * #include "keller.h" * int kellerman(int n, int (*func)(void *info, int i, int ind[]), * void *info, glp_graph *H); * * DESCRIPTION * * The routine kellerman implements Kellerman's heuristic algorithm * to find a minimal set of cliques which cover all edges of specified * graph G = (V, E). * * The parameter n specifies the number of vertices |V|, n >= 0. * * Formal routine func specifies the set of edges E in the following * way. Running the routine kellerman calls the routine func and passes * to it parameter i, which is the number of some vertex, 1 <= i <= n. * In response the routine func should store numbers of all vertices * adjacent to vertex i to locations ind[1], ind[2], ..., ind[len] and * return the value of len, which is the number of adjacent vertices, * 0 <= len <= n. Self-loops are allowed, but ignored. Multiple edges * are not allowed. * * The parameter info is a transit pointer (magic cookie) passed to the * formal routine func as its first parameter. * * The result provided by the routine kellerman is the bipartite graph * H = (V union C, F), which defines the covering found. (The program * object of type glp_graph specified by the parameter H should be * previously created with the routine glp_create_graph. On entry the * routine kellerman erases the content of this object with the routine * glp_erase_graph.) Vertices of first part V correspond to vertices of * the graph G and have the same ordinal numbers 1, 2, ..., n. Vertices * of second part C correspond to cliques and have ordinal numbers * n+1, n+2, ..., n+k, where k is the total number of cliques in the * edge covering found. Every edge f in F in the program object H is * represented as arc f = (i->j), where i in V and j in C, which means * that vertex i of the graph G is in clique C[j], 1 <= j <= k. (Thus, * if two vertices of the graph G are in the same clique, these vertices * are adjacent in G, and corresponding edge is covered by that clique.) * * RETURNS * * The routine Kellerman returns k, the total number of cliques in the * edge covering found. * * REFERENCE * * For more details see: glpk/doc/notes/keller.pdf (in Russian). */ struct set { /* set of vertices */ int size; /* size (cardinality) of the set, 0 <= card <= n */ int *list; /* int list[1+n]; */ /* the set contains vertices list[1,...,size] */ int *pos; /* int pos[1+n]; */ /* pos[i] > 0 means that vertex i is in the set and * list[pos[i]] = i; pos[i] = 0 means that vertex i is not in * the set */ }; int kellerman(int n, int (*func)(void *info, int i, int ind[]), void *info, void /* glp_graph */ *H_) { glp_graph *H = H_; struct set W_, *W = &W_, V_, *V = &V_; glp_arc *a; int i, j, k, m, t, len, card, best; xassert(n >= 0); /* H := (V, 0; 0), where V is the set of vertices of graph G */ glp_erase_graph(H, H->v_size, H->a_size); glp_add_vertices(H, n); /* W := 0 */ W->size = 0; W->list = xcalloc(1+n, sizeof(int)); W->pos = xcalloc(1+n, sizeof(int)); memset(&W->pos[1], 0, sizeof(int) * n); /* V := 0 */ V->size = 0; V->list = xcalloc(1+n, sizeof(int)); V->pos = xcalloc(1+n, sizeof(int)); memset(&V->pos[1], 0, sizeof(int) * n); /* main loop */ for (i = 1; i <= n; i++) { /* W must be empty */ xassert(W->size == 0); /* W := { j : i > j and (i,j) in E } */ len = func(info, i, W->list); xassert(0 <= len && len <= n); for (t = 1; t <= len; t++) { j = W->list[t]; xassert(1 <= j && j <= n); if (j >= i) continue; xassert(W->pos[j] == 0); W->list[++W->size] = j, W->pos[j] = W->size; } /* on i-th iteration we need to cover edges (i,j) for all * j in W */ /* if W is empty, it is a special case */ if (W->size == 0) { /* set k := k + 1 and create new clique C[k] = { i } */ k = glp_add_vertices(H, 1) - n; glp_add_arc(H, i, n + k); continue; } /* try to include vertex i into existing cliques */ /* V must be empty */ xassert(V->size == 0); /* k is the number of cliques found so far */ k = H->nv - n; for (m = 1; m <= k; m++) { /* do while V != W; since here V is within W, we can use * equivalent condition: do while |V| < |W| */ if (V->size == W->size) break; /* check if C[m] is within W */ for (a = H->v[n + m]->in; a != NULL; a = a->h_next) { j = a->tail->i; if (W->pos[j] == 0) break; } if (a != NULL) continue; /* C[m] is within W, expand clique C[m] with vertex i */ /* C[m] := C[m] union {i} */ glp_add_arc(H, i, n + m); /* V is a set of vertices whose incident edges are already * covered by existing cliques */ /* V := V union C[m] */ for (a = H->v[n + m]->in; a != NULL; a = a->h_next) { j = a->tail->i; if (V->pos[j] == 0) V->list[++V->size] = j, V->pos[j] = V->size; } } /* remove from set W the vertices whose incident edges are * already covered by existing cliques */ /* W := W \ V, V := 0 */ for (t = 1; t <= V->size; t++) { j = V->list[t], V->pos[j] = 0; if (W->pos[j] != 0) { /* remove vertex j from W */ if (W->pos[j] != W->size) { int jj = W->list[W->size]; W->list[W->pos[j]] = jj; W->pos[jj] = W->pos[j]; } W->size--, W->pos[j] = 0; } } V->size = 0; /* now set W contains only vertices whose incident edges are * still not covered by existing cliques; create new cliques * to cover remaining edges until set W becomes empty */ while (W->size > 0) { /* find clique C[m], 1 <= m <= k, which shares maximal * number of vertices with W; to break ties choose clique * having smallest number m */ m = 0, best = -1; k = H->nv - n; for (t = 1; t <= k; t++) { /* compute cardinality of intersection of W and C[t] */ card = 0; for (a = H->v[n + t]->in; a != NULL; a = a->h_next) { j = a->tail->i; if (W->pos[j] != 0) card++; } if (best < card) m = t, best = card; } xassert(m > 0); /* set k := k + 1 and create new clique: * C[k] := (W intersect C[m]) union { i }, which covers all * edges incident to vertices from (W intersect C[m]) */ k = glp_add_vertices(H, 1) - n; for (a = H->v[n + m]->in; a != NULL; a = a->h_next) { j = a->tail->i; if (W->pos[j] != 0) { /* vertex j is in both W and C[m]; include it in new * clique C[k] */ glp_add_arc(H, j, n + k); /* remove vertex j from W, since edge (i,j) will be * covered by new clique C[k] */ if (W->pos[j] != W->size) { int jj = W->list[W->size]; W->list[W->pos[j]] = jj; W->pos[jj] = W->pos[j]; } W->size--, W->pos[j] = 0; } } /* include vertex i to new clique C[k] to cover edges (i,j) * incident to all vertices j just removed from W */ glp_add_arc(H, i, n + k); } } /* free working arrays */ xfree(W->list); xfree(W->pos); xfree(V->list); xfree(V->pos); /* return the number of cliques in the edge covering found */ return H->nv - n; } /* eof */ Rglpk/src/GLPK/env2.h0000644000176000001440000000147012245352174013737 0ustar ripleyusers/* env2.h */ /* (reserved for copyright notice) */ #ifndef ENV2_H #define ENV2_H #include "env.h" typedef struct XFILE XFILE; #define XEOF (-1) #define lib_err_msg _glp_lib_err_msg void lib_err_msg(const char *msg); #define xerrmsg _glp_lib_xerrmsg const char *xerrmsg(void); #define xfopen _glp_lib_xfopen XFILE *xfopen(const char *fname, const char *mode); #define xferror _glp_lib_xferror int xferror(XFILE *file); #define xfeof _glp_lib_xfeof int xfeof(XFILE *file); #define xfgetc _glp_lib_xfgetc int xfgetc(XFILE *file); #define xfputc _glp_lib_xfputc int xfputc(int c, XFILE *file); #define xfflush _glp_lib_xfflush int xfflush(XFILE *fp); #define xfclose _glp_lib_xfclose int xfclose(XFILE *file); #define xfprintf _glp_lib_xfprintf int xfprintf(XFILE *file, const char *fmt, ...); #endif /* eof */ Rglpk/src/GLPK/rng.c0000644000176000001440000001414612245352174013652 0ustar ripleyusers/* rng.c (pseudo-random number generator) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * This code is a modified version of the module GB_FLIP, a portable * pseudo-random number generator. The original version of GB_FLIP is * a part of The Stanford GraphBase developed by Donald E. Knuth (see * http://www-cs-staff.stanford.edu/~knuth/sgb.html). * * Note that all changes concern only external names, so this modified * version produces exactly the same results as the original version. * * Changes were made by Andrew Makhorin . * * 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 . ***********************************************************************/ #include "env.h" #include "rng.h" #if 0 int A[56] = { -1 }; #else #define A (rand->A) #endif /* pseudo-random values */ #if 0 int *fptr = A; #else #define fptr (rand->fptr) #endif /* the next A value to be exported */ #define mod_diff(x, y) (((x) - (y)) & 0x7FFFFFFF) /* difference modulo 2^31 */ static int flip_cycle(RNG *rand) { /* this is an auxiliary routine to do 55 more steps of the basic * recurrence, at high speed, and to reset fptr */ int *ii, *jj; for (ii = &A[1], jj = &A[32]; jj <= &A[55]; ii++, jj++) *ii = mod_diff(*ii, *jj); for (jj = &A[1]; ii <= &A[55]; ii++, jj++) *ii = mod_diff(*ii, *jj); fptr = &A[54]; return A[55]; } /*********************************************************************** * NAME * * rng_create_rand - create pseudo-random number generator * * SYNOPSIS * * #include "rng.h" * RNG *rng_create_rand(void); * * DESCRIPTION * * The routine rng_create_rand creates and initializes a pseudo-random * number generator. * * RETURNS * * The routine returns a pointer to the generator created. */ RNG *rng_create_rand(void) { RNG *rand; int i; rand = talloc(1, RNG); A[0] = -1; for (i = 1; i <= 55; i++) A[i] = 0; fptr = A; rng_init_rand(rand, 1); return rand; } /*********************************************************************** * NAME * * rng_init_rand - initialize pseudo-random number generator * * SYNOPSIS * * #include "rng.h" * void rng_init_rand(RNG *rand, int seed); * * DESCRIPTION * * The routine rng_init_rand initializes the pseudo-random number * generator. The parameter seed may be any integer number. Note that * on creating the generator this routine is called with the parameter * seed equal to 1. */ void rng_init_rand(RNG *rand, int seed) { int i; int prev = seed, next = 1; seed = prev = mod_diff(prev, 0); A[55] = prev; for (i = 21; i; i = (i + 21) % 55) { A[i] = next; next = mod_diff(prev, next); if (seed & 1) seed = 0x40000000 + (seed >> 1); else seed >>= 1; next = mod_diff(next, seed); prev = A[i]; } flip_cycle(rand); flip_cycle(rand); flip_cycle(rand); flip_cycle(rand); flip_cycle(rand); return; } /*********************************************************************** * NAME * * rng_next_rand - obtain pseudo-random integer in the range [0, 2^31-1] * * SYNOPSIS * * #include "rng.h" * int rng_next_rand(RNG *rand); * * RETURNS * * The routine rng_next_rand returns a next pseudo-random integer which * is uniformly distributed between 0 and 2^31-1, inclusive. The period * length of the generated numbers is 2^85 - 2^30. The low order bits of * the generated numbers are just as random as the high-order bits. */ int rng_next_rand(RNG *rand) { return *fptr >= 0 ? *fptr-- : flip_cycle(rand); } /*********************************************************************** * NAME * * rng_unif_rand - obtain pseudo-random integer in the range [0, m-1] * * SYNOPSIS * * #include "rng.h" * int rng_unif_rand(RNG *rand, int m); * * RETURNS * * The routine rng_unif_rand returns a next pseudo-random integer which * is uniformly distributed between 0 and m-1, inclusive, where m is any * positive integer less than 2^31. */ #define two_to_the_31 ((unsigned int)0x80000000) int rng_unif_rand(RNG *rand, int m) { unsigned int t = two_to_the_31 - (two_to_the_31 % m); int r; xassert(m > 0); do { r = rng_next_rand(rand); } while (t <= (unsigned int)r); return r % m; } /*********************************************************************** * NAME * * rng_delete_rand - delete pseudo-random number generator * * SYNOPSIS * * #include "rng.h" * void rng_delete_rand(RNG *rand); * * DESCRIPTION * * The routine rng_delete_rand frees all the memory allocated to the * specified pseudo-random number generator. */ void rng_delete_rand(RNG *rand) { tfree(rand); return; } /**********************************************************************/ #ifdef GLP_TEST /* To be sure that this modified version produces the same results as * the original version, run this validation program. */ int main(void) { RNG *rand; int j; rand = rng_create_rand(); rng_init_rand(rand, -314159); if (rng_next_rand(rand) != 119318998) { fprintf(stderr, "Failure on the first try!\n"); return -1; } for (j = 1; j <= 133; j++) rng_next_rand(rand); if (rng_unif_rand(rand, 0x55555555) != 748103812) { fprintf(stderr, "Failure on the second try!\n"); return -2; } fprintf(stderr, "OK, the random-number generator routines seem to" " work!\n"); rng_delete_rand(rand); return 0; } #endif /* eof */ Rglpk/src/GLPK/glpscf.c0000644000176000001440000004760412245352174014347 0ustar ripleyusers/* glpscf.c (Schur complement factorization) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #include "glpscf.h" #define xfault xerror #define _GLPSCF_DEBUG 0 #define eps 1e-10 /*********************************************************************** * NAME * * scf_create_it - create Schur complement factorization * * SYNOPSIS * * #include "glpscf.h" * SCF *scf_create_it(int n_max); * * DESCRIPTION * * The routine scf_create_it creates the factorization of matrix C, * which initially has no rows and columns. * * The parameter n_max specifies the maximal order of matrix C to be * factorized, 1 <= n_max <= 32767. * * RETURNS * * The routine scf_create_it returns a pointer to the structure SCF, * which defines the factorization. */ SCF *scf_create_it(int n_max) { SCF *scf; #if _GLPSCF_DEBUG xprintf("scf_create_it: warning: debug mode enabled\n"); #endif if (!(1 <= n_max && n_max <= 32767)) xfault("scf_create_it: n_max = %d; invalid parameter\n", n_max); scf = xmalloc(sizeof(SCF)); scf->n_max = n_max; scf->n = 0; scf->f = xcalloc(1 + n_max * n_max, sizeof(double)); scf->u = xcalloc(1 + n_max * (n_max + 1) / 2, sizeof(double)); scf->p = xcalloc(1 + n_max, sizeof(int)); scf->t_opt = SCF_TBG; scf->rank = 0; #if _GLPSCF_DEBUG scf->c = xcalloc(1 + n_max * n_max, sizeof(double)); #else scf->c = NULL; #endif scf->w = xcalloc(1 + n_max, sizeof(double)); return scf; } /*********************************************************************** * The routine f_loc determines location of matrix element F[i,j] in * the one-dimensional array f. */ static int f_loc(SCF *scf, int i, int j) { int n_max = scf->n_max; int n = scf->n; xassert(1 <= i && i <= n); xassert(1 <= j && j <= n); return (i - 1) * n_max + j; } /*********************************************************************** * The routine u_loc determines location of matrix element U[i,j] in * the one-dimensional array u. */ static int u_loc(SCF *scf, int i, int j) { int n_max = scf->n_max; int n = scf->n; xassert(1 <= i && i <= n); xassert(i <= j && j <= n); return (i - 1) * n_max + j - i * (i - 1) / 2; } /*********************************************************************** * The routine bg_transform applies Bartels-Golub version of gaussian * elimination to restore triangular structure of matrix U. * * On entry matrix U has the following structure: * * 1 k n * 1 * * * * * * * * * * * . * * * * * * * * * * . . * * * * * * * * * . . . * * * * * * * * k . . . . * * * * * * * . . . . . * * * * * * . . . . . . * * * * * . . . . . . . * * * * . . . . . . . . * * * n . . . . # # # # # # * * where '#' is a row spike to be eliminated. * * Elements of n-th row are passed separately in locations un[k], ..., * un[n]. On exit the content of the array un is destroyed. * * REFERENCES * * R.H.Bartels, G.H.Golub, "The Simplex Method of Linear Programming * Using LU-decomposition", Comm. ACM, 12, pp. 266-68, 1969. */ static void bg_transform(SCF *scf, int k, double un[]) { int n = scf->n; double *f = scf->f; double *u = scf->u; int j, k1, kj, kk, n1, nj; double t; xassert(1 <= k && k <= n); /* main elimination loop */ for (k = k; k < n; k++) { /* determine location of U[k,k] */ kk = u_loc(scf, k, k); /* determine location of F[k,1] */ k1 = f_loc(scf, k, 1); /* determine location of F[n,1] */ n1 = f_loc(scf, n, 1); /* if |U[k,k]| < |U[n,k]|, interchange k-th and n-th rows to provide |U[k,k]| >= |U[n,k]| */ if (fabs(u[kk]) < fabs(un[k])) { /* interchange k-th and n-th rows of matrix U */ for (j = k, kj = kk; j <= n; j++, kj++) t = u[kj], u[kj] = un[j], un[j] = t; /* interchange k-th and n-th rows of matrix F to keep the main equality F * C = U * P */ for (j = 1, kj = k1, nj = n1; j <= n; j++, kj++, nj++) t = f[kj], f[kj] = f[nj], f[nj] = t; } /* now |U[k,k]| >= |U[n,k]| */ /* if U[k,k] is too small in the magnitude, replace U[k,k] and U[n,k] by exact zero */ if (fabs(u[kk]) < eps) u[kk] = un[k] = 0.0; /* if U[n,k] is already zero, elimination is not needed */ if (un[k] == 0.0) continue; /* compute gaussian multiplier t = U[n,k] / U[k,k] */ t = un[k] / u[kk]; /* apply gaussian elimination to nullify U[n,k] */ /* (n-th row of U) := (n-th row of U) - t * (k-th row of U) */ for (j = k+1, kj = kk+1; j <= n; j++, kj++) un[j] -= t * u[kj]; /* (n-th row of F) := (n-th row of F) - t * (k-th row of F) to keep the main equality F * C = U * P */ for (j = 1, kj = k1, nj = n1; j <= n; j++, kj++, nj++) f[nj] -= t * f[kj]; } /* if U[n,n] is too small in the magnitude, replace it by exact zero */ if (fabs(un[n]) < eps) un[n] = 0.0; /* store U[n,n] in a proper location */ u[u_loc(scf, n, n)] = un[n]; return; } /*********************************************************************** * The routine givens computes the parameters of Givens plane rotation * c = cos(teta) and s = sin(teta) such that: * * ( c -s ) ( a ) ( r ) * ( ) ( ) = ( ) , * ( s c ) ( b ) ( 0 ) * * where a and b are given scalars. * * REFERENCES * * G.H.Golub, C.F.Van Loan, "Matrix Computations", 2nd ed. */ static void givens(double a, double b, double *c, double *s) { double t; if (b == 0.0) (*c) = 1.0, (*s) = 0.0; else if (fabs(a) <= fabs(b)) t = - a / b, (*s) = 1.0 / sqrt(1.0 + t * t), (*c) = (*s) * t; else t = - b / a, (*c) = 1.0 / sqrt(1.0 + t * t), (*s) = (*c) * t; return; } /*---------------------------------------------------------------------- * The routine gr_transform applies Givens plane rotations to restore * triangular structure of matrix U. * * On entry matrix U has the following structure: * * 1 k n * 1 * * * * * * * * * * * . * * * * * * * * * * . . * * * * * * * * * . . . * * * * * * * * k . . . . * * * * * * * . . . . . * * * * * * . . . . . . * * * * * . . . . . . . * * * * . . . . . . . . * * * n . . . . # # # # # # * * where '#' is a row spike to be eliminated. * * Elements of n-th row are passed separately in locations un[k], ..., * un[n]. On exit the content of the array un is destroyed. * * REFERENCES * * R.H.Bartels, G.H.Golub, "The Simplex Method of Linear Programming * Using LU-decomposition", Comm. ACM, 12, pp. 266-68, 1969. */ static void gr_transform(SCF *scf, int k, double un[]) { int n = scf->n; double *f = scf->f; double *u = scf->u; int j, k1, kj, kk, n1, nj; double c, s; xassert(1 <= k && k <= n); /* main elimination loop */ for (k = k; k < n; k++) { /* determine location of U[k,k] */ kk = u_loc(scf, k, k); /* determine location of F[k,1] */ k1 = f_loc(scf, k, 1); /* determine location of F[n,1] */ n1 = f_loc(scf, n, 1); /* if both U[k,k] and U[n,k] are too small in the magnitude, replace them by exact zero */ if (fabs(u[kk]) < eps && fabs(un[k]) < eps) u[kk] = un[k] = 0.0; /* if U[n,k] is already zero, elimination is not needed */ if (un[k] == 0.0) continue; /* compute the parameters of Givens plane rotation */ givens(u[kk], un[k], &c, &s); /* apply Givens rotation to k-th and n-th rows of matrix U */ for (j = k, kj = kk; j <= n; j++, kj++) { double ukj = u[kj], unj = un[j]; u[kj] = c * ukj - s * unj; un[j] = s * ukj + c * unj; } /* apply Givens rotation to k-th and n-th rows of matrix F to keep the main equality F * C = U * P */ for (j = 1, kj = k1, nj = n1; j <= n; j++, kj++, nj++) { double fkj = f[kj], fnj = f[nj]; f[kj] = c * fkj - s * fnj; f[nj] = s * fkj + c * fnj; } } /* if U[n,n] is too small in the magnitude, replace it by exact zero */ if (fabs(un[n]) < eps) un[n] = 0.0; /* store U[n,n] in a proper location */ u[u_loc(scf, n, n)] = un[n]; return; } /*********************************************************************** * The routine transform restores triangular structure of matrix U. * It is a driver to the routines bg_transform and gr_transform (see * comments to these routines above). */ static void transform(SCF *scf, int k, double un[]) { switch (scf->t_opt) { case SCF_TBG: bg_transform(scf, k, un); break; case SCF_TGR: gr_transform(scf, k, un); break; default: xassert(scf != scf); } return; } /*********************************************************************** * The routine estimate_rank estimates the rank of matrix C. * * Since all transformations applied to matrix F are non-singular, * and F is assumed to be well conditioned, from the main equaility * F * C = U * P it follows that rank(C) = rank(U), where rank(U) is * estimated as the number of non-zero diagonal elements of U. */ static int estimate_rank(SCF *scf) { int n_max = scf->n_max; int n = scf->n; double *u = scf->u; int i, ii, inc, rank = 0; for (i = 1, ii = u_loc(scf, i, i), inc = n_max; i <= n; i++, ii += inc, inc--) if (u[ii] != 0.0) rank++; return rank; } #if _GLPSCF_DEBUG /*********************************************************************** * The routine check_error computes the maximal relative error between * left- and right-hand sides of the main equality F * C = U * P. (This * routine is intended only for debugging.) */ static void check_error(SCF *scf, const char *func) { int n = scf->n; double *f = scf->f; double *u = scf->u; int *p = scf->p; double *c = scf->c; int i, j, k; double d, dmax = 0.0, s, t; xassert(c != NULL); for (i = 1; i <= n; i++) { for (j = 1; j <= n; j++) { /* compute element (i,j) of product F * C */ s = 0.0; for (k = 1; k <= n; k++) s += f[f_loc(scf, i, k)] * c[f_loc(scf, k, j)]; /* compute element (i,j) of product U * P */ k = p[j]; t = (i <= k ? u[u_loc(scf, i, k)] : 0.0); /* compute the maximal relative error */ d = fabs(s - t) / (1.0 + fabs(t)); if (dmax < d) dmax = d; } } if (dmax > 1e-8) xprintf("%s: dmax = %g; relative error too large\n", func, dmax); return; } #endif /*********************************************************************** * NAME * * scf_update_exp - update factorization on expanding C * * SYNOPSIS * * #include "glpscf.h" * int scf_update_exp(SCF *scf, const double x[], const double y[], * double z); * * DESCRIPTION * * The routine scf_update_exp updates the factorization of matrix C on * expanding it by adding a new row and column as follows: * * ( C x ) * new C = ( ) * ( y' z ) * * where x[1,...,n] is a new column, y[1,...,n] is a new row, and z is * a new diagonal element. * * If on entry the factorization is empty, the parameters x and y can * be specified as NULL. * * RETURNS * * 0 The factorization has been successfully updated. * * SCF_ESING * The factorization has been successfully updated, however, new * matrix C is singular within working precision. Note that the new * factorization remains valid. * * SCF_ELIMIT * There is not enough room to expand the factorization, because * n = n_max. The factorization remains unchanged. * * ALGORITHM * * We can see that: * * ( F 0 ) ( C x ) ( FC Fx ) ( UP Fx ) * ( ) ( ) = ( ) = ( ) = * ( 0 1 ) ( y' z ) ( y' z ) ( y' z ) * * ( U Fx ) ( P 0 ) * = ( ) ( ), * ( y'P' z ) ( 0 1 ) * * therefore to keep the main equality F * C = U * P we can take: * * ( F 0 ) ( U Fx ) ( P 0 ) * new F = ( ), new U = ( ), new P = ( ), * ( 0 1 ) ( y'P' z ) ( 0 1 ) * * and eliminate the row spike y'P' in the last row of new U to restore * its upper triangular structure. */ int scf_update_exp(SCF *scf, const double x[], const double y[], double z) { int n_max = scf->n_max; int n = scf->n; double *f = scf->f; double *u = scf->u; int *p = scf->p; #if _GLPSCF_DEBUG double *c = scf->c; #endif double *un = scf->w; int i, ij, in, j, k, nj, ret = 0; double t; /* check if the factorization can be expanded */ if (n == n_max) { /* there is not enough room */ ret = SCF_ELIMIT; goto done; } /* increase the order of the factorization */ scf->n = ++n; /* fill new zero column of matrix F */ for (i = 1, in = f_loc(scf, i, n); i < n; i++, in += n_max) f[in] = 0.0; /* fill new zero row of matrix F */ for (j = 1, nj = f_loc(scf, n, j); j < n; j++, nj++) f[nj] = 0.0; /* fill new unity diagonal element of matrix F */ f[f_loc(scf, n, n)] = 1.0; /* compute new column of matrix U, which is (old F) * x */ for (i = 1; i < n; i++) { /* u[i,n] := (i-th row of old F) * x */ t = 0.0; for (j = 1, ij = f_loc(scf, i, 1); j < n; j++, ij++) t += f[ij] * x[j]; u[u_loc(scf, i, n)] = t; } /* compute new (spiked) row of matrix U, which is (old P) * y */ for (j = 1; j < n; j++) un[j] = y[p[j]]; /* store new diagonal element of matrix U, which is z */ un[n] = z; /* expand matrix P */ p[n] = n; #if _GLPSCF_DEBUG /* expand matrix C */ /* fill its new column, which is x */ for (i = 1, in = f_loc(scf, i, n); i < n; i++, in += n_max) c[in] = x[i]; /* fill its new row, which is y */ for (j = 1, nj = f_loc(scf, n, j); j < n; j++, nj++) c[nj] = y[j]; /* fill its new diagonal element, which is z */ c[f_loc(scf, n, n)] = z; #endif /* restore upper triangular structure of matrix U */ for (k = 1; k < n; k++) if (un[k] != 0.0) break; transform(scf, k, un); /* estimate the rank of matrices C and U */ scf->rank = estimate_rank(scf); if (scf->rank != n) ret = SCF_ESING; #if _GLPSCF_DEBUG /* check that the factorization is accurate enough */ check_error(scf, "scf_update_exp"); #endif done: return ret; } /*********************************************************************** * The routine solve solves the system C * x = b. * * From the main equation F * C = U * P it follows that: * * C * x = b => F * C * x = F * b => U * P * x = F * b => * * P * x = inv(U) * F * b => x = P' * inv(U) * F * b. * * On entry the array x contains right-hand side vector b. On exit this * array contains solution vector x. */ static void solve(SCF *scf, double x[]) { int n = scf->n; double *f = scf->f; double *u = scf->u; int *p = scf->p; double *y = scf->w; int i, j, ij; double t; /* y := F * b */ for (i = 1; i <= n; i++) { /* y[i] = (i-th row of F) * b */ t = 0.0; for (j = 1, ij = f_loc(scf, i, 1); j <= n; j++, ij++) t += f[ij] * x[j]; y[i] = t; } /* y := inv(U) * y */ for (i = n; i >= 1; i--) { t = y[i]; for (j = n, ij = u_loc(scf, i, n); j > i; j--, ij--) t -= u[ij] * y[j]; y[i] = t / u[ij]; } /* x := P' * y */ for (i = 1; i <= n; i++) x[p[i]] = y[i]; return; } /*********************************************************************** * The routine tsolve solves the transposed system C' * x = b. * * From the main equation F * C = U * P it follows that: * * C' * F' = P' * U', * * therefore: * * C' * x = b => C' * F' * inv(F') * x = b => * * P' * U' * inv(F') * x = b => U' * inv(F') * x = P * b => * * inv(F') * x = inv(U') * P * b => x = F' * inv(U') * P * b. * * On entry the array x contains right-hand side vector b. On exit this * array contains solution vector x. */ static void tsolve(SCF *scf, double x[]) { int n = scf->n; double *f = scf->f; double *u = scf->u; int *p = scf->p; double *y = scf->w; int i, j, ij; double t; /* y := P * b */ for (i = 1; i <= n; i++) y[i] = x[p[i]]; /* y := inv(U') * y */ for (i = 1; i <= n; i++) { /* compute y[i] */ ij = u_loc(scf, i, i); t = (y[i] /= u[ij]); /* substitute y[i] in other equations */ for (j = i+1, ij++; j <= n; j++, ij++) y[j] -= u[ij] * t; } /* x := F' * y (computed as linear combination of rows of F) */ for (j = 1; j <= n; j++) x[j] = 0.0; for (i = 1; i <= n; i++) { t = y[i]; /* coefficient of linear combination */ for (j = 1, ij = f_loc(scf, i, 1); j <= n; j++, ij++) x[j] += f[ij] * t; } return; } /*********************************************************************** * NAME * * scf_solve_it - solve either system C * x = b or C' * x = b * * SYNOPSIS * * #include "glpscf.h" * void scf_solve_it(SCF *scf, int tr, double x[]); * * DESCRIPTION * * The routine scf_solve_it solves either the system C * x = b (if tr * is zero) or the system C' * x = b, where C' is a matrix transposed * to C (if tr is non-zero). C is assumed to be non-singular. * * On entry the array x should contain the right-hand side vector b in * locations x[1], ..., x[n], where n is the order of matrix C. On exit * the array x contains the solution vector x in the same locations. */ void scf_solve_it(SCF *scf, int tr, double x[]) { if (scf->rank < scf->n) xfault("scf_solve_it: singular matrix\n"); if (!tr) solve(scf, x); else tsolve(scf, x); return; } void scf_reset_it(SCF *scf) { /* reset factorization for empty matrix C */ scf->n = scf->rank = 0; return; } /*********************************************************************** * NAME * * scf_delete_it - delete Schur complement factorization * * SYNOPSIS * * #include "glpscf.h" * void scf_delete_it(SCF *scf); * * DESCRIPTION * * The routine scf_delete_it deletes the specified factorization and * frees all the memory allocated to this object. */ void scf_delete_it(SCF *scf) { xfree(scf->f); xfree(scf->u); xfree(scf->p); #if _GLPSCF_DEBUG xfree(scf->c); #endif xfree(scf->w); xfree(scf); return; } /* eof */ Rglpk/src/GLPK/wclique1.c0000644000176000001440000002574412245352174014624 0ustar ripleyusers/* wclique1.c (maximum weight clique, greedy heuristic) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #include "wclique1.h" /*********************************************************************** * NAME * * wclique1 - find maximum weight clique with greedy heuristic * * SYNOPSIS * * #include "wclique1.h" * int wclique1(int n, const double w[], * int (*func)(void *info, int i, int ind[]), void *info, int c[]); * * DESCRIPTION * * The routine wclique1 implements a sequential greedy heuristic to * find maximum weight clique in a given (undirected) graph G = (V, E). * * The parameter n specifies the number of vertices |V| in the graph, * n >= 0. * * The array w specifies vertex weights in locations w[i], i = 1,...,n. * All weights must be non-negative. * * The formal routine func specifies the graph. For a given vertex i, * 1 <= i <= n, it stores indices of all vertices adjacent to vertex i * in locations ind[1], ..., ind[deg], where deg is the degree of * vertex i, 0 <= deg < n, returned on exit. Note that self-loops and * multiple edges are not allowed. * * The parameter info is a cookie passed to the routine func. * * On exit the routine wclique1 stores vertex indices included in * the clique found to locations c[1], ..., c[size], where size is the * clique size returned by the routine, 0 <= size <= n. * * RETURNS * * The routine wclique1 returns the size of the clique found. */ struct vertex { int i; double cw; }; static int fcmp(const void *xx, const void *yy) { const struct vertex *x = xx, *y = yy; if (x->cw > y->cw) return -1; if (x->cw < y->cw) return +1; return 0; } int wclique1(int n, const double w[], int (*func)(void *info, int i, int ind[]), void *info, int c[]) { struct vertex *v_list; int deg, c_size, d_size, i, j, k, kk, l, *ind, *c_list, *d_list, size = 0; double c_wght, d_wght, *sw, best = 0.0; char *d_flag, *skip; /* perform sanity checks */ xassert(n >= 0); for (i = 1; i <= n; i++) xassert(w[i] >= 0.0); /* if the graph is empty, nothing to do */ if (n == 0) goto done; /* allocate working arrays */ ind = xcalloc(1+n, sizeof(int)); v_list = xcalloc(1+n, sizeof(struct vertex)); c_list = xcalloc(1+n, sizeof(int)); d_list = xcalloc(1+n, sizeof(int)); d_flag = xcalloc(1+n, sizeof(char)); skip = xcalloc(1+n, sizeof(char)); sw = xcalloc(1+n, sizeof(double)); /* build the vertex list */ for (i = 1; i <= n; i++) { v_list[i].i = i; /* compute the cumulative weight of each vertex i, which is * cw[i] = w[i] + sum{j : (i,j) in E} w[j] */ v_list[i].cw = w[i]; deg = func(info, i, ind); xassert(0 <= deg && deg < n); for (k = 1; k <= deg; k++) { j = ind[k]; xassert(1 <= j && j <= n && j != i); v_list[i].cw += w[j]; } } /* sort the vertex list to access vertices in descending order of * cumulative weights */ qsort(&v_list[1], n, sizeof(struct vertex), fcmp); /* initially all vertices are unmarked */ memset(&skip[1], 0, sizeof(char) * n); /* clear flags of all vertices */ memset(&d_flag[1], 0, sizeof(char) * n); /* look through all vertices of the graph */ for (l = 1; l <= n; l++) { /* take vertex i */ i = v_list[l].i; /* if this vertex was already included in one of previosuly * constructed cliques, skip it */ if (skip[i]) continue; /* use vertex i as the initial clique vertex */ c_size = 1; /* size of current clique */ c_list[1] = i; /* list of vertices in current clique */ c_wght = w[i]; /* weight of current clique */ /* determine the candidate set D = { j : (i,j) in E } */ d_size = func(info, i, d_list); xassert(0 <= d_size && d_size < n); d_wght = 0.0; /* weight of set D */ for (k = 1; k <= d_size; k++) { j = d_list[k]; xassert(1 <= j && j <= n && j != i); xassert(!d_flag[j]); d_flag[j] = 1; d_wght += w[j]; } /* check an upper bound to the final clique weight */ if (c_wght + d_wght < best + 1e-5 * (1.0 + fabs(best))) { /* skip constructing the current clique */ goto next; } /* compute the summary weight of each vertex i in D, which is * sw[i] = w[i] + sum{j in D and (i,j) in E} w[j] */ for (k = 1; k <= d_size; k++) { i = d_list[k]; sw[i] = w[i]; /* consider vertices adjacent to vertex i */ deg = func(info, i, ind); xassert(0 <= deg && deg < n); for (kk = 1; kk <= deg; kk++) { j = ind[kk]; xassert(1 <= j && j <= n && j != i); if (d_flag[j]) sw[i] += w[j]; } } /* grow the current clique by adding vertices from D */ while (d_size > 0) { /* check an upper bound to the final clique weight */ if (c_wght + d_wght < best + 1e-5 * (1.0 + fabs(best))) { /* skip constructing the current clique */ goto next; } /* choose vertex i in D having maximal summary weight */ i = d_list[1]; for (k = 2; k <= d_size; k++) { j = d_list[k]; if (sw[i] < sw[j]) i = j; } /* include vertex i in the current clique */ c_size++; c_list[c_size] = i; c_wght += w[i]; /* remove all vertices not adjacent to vertex i, including * vertex i itself, from the candidate set D */ deg = func(info, i, ind); xassert(0 <= deg && deg < n); for (k = 1; k <= deg; k++) { j = ind[k]; xassert(1 <= j && j <= n && j != i); /* vertex j is adjacent to vertex i */ if (d_flag[j]) { xassert(d_flag[j] == 1); /* mark vertex j to keep it in D */ d_flag[j] = 2; } } kk = d_size, d_size = 0; for (k = 1; k <= kk; k++) { j = d_list[k]; if (d_flag[j] == 1) { /* remove vertex j from D */ d_flag[j] = 0; d_wght -= w[j]; } else if (d_flag[j] == 2) { /* keep vertex j in D */ d_list[++d_size] = j; d_flag[j] = 1; } else xassert(d_flag != d_flag); } } /* the current clique has been completely constructed */ if (best < c_wght) { best = c_wght; size = c_size; xassert(1 <= size && size <= n); memcpy(&c[1], &c_list[1], size * sizeof(int)); } next: /* mark the current clique vertices in order not to use them * as initial vertices anymore */ for (k = 1; k <= c_size; k++) skip[c_list[k]] = 1; /* set D can be non-empty, so clean up vertex flags */ for (k = 1; k <= d_size; k++) d_flag[d_list[k]] = 0; } /* free working arrays */ xfree(ind); xfree(v_list); xfree(c_list); xfree(d_list); xfree(d_flag); xfree(skip); xfree(sw); done: /* return to the calling program */ return size; } /**********************************************************************/ #ifdef GLP_TEST #include "glpk.h" #include "rng.h" typedef struct { double w; } v_data; #define weight(v) (((v_data *)((v)->data))->w) glp_graph *G; char *flag; int func(void *info, int i, int ind[]) { glp_arc *e; int j, k, deg = 0; xassert(info == NULL); xassert(1 <= i && i <= G->nv); /* look through incoming arcs */ for (e = G->v[i]->in; e != NULL; e = e->h_next) { j = e->tail->i; /* j->i */ if (j != i && !flag[j]) ind[++deg] = j, flag[j] = 1; } /* look through outgoing arcs */ for (e = G->v[i]->out; e != NULL; e = e->t_next) { j = e->head->i; /* i->j */ if (j != i && !flag[j]) ind[++deg] = j, flag[j] = 1; } /* clear the flag array */ xassert(deg < G->nv); for (k = 1; k <= deg; k++) flag[ind[k]] = 0; return deg; } int main(int argc, char *argv[]) { RNG *rand; int i, k, kk, size, *c, *ind, deg; double *w, sum, t; /* read graph in DIMACS format */ G = glp_create_graph(sizeof(v_data), 0); xassert(argc == 2); xassert(glp_read_ccdata(G, offsetof(v_data, w), argv[1]) == 0); /* print the number of connected components */ xprintf("nc = %d\n", glp_weak_comp(G, -1)); /* assign random weights unformly distributed in [1,100] */ w = xcalloc(1+G->nv, sizeof(double)); rand = rng_create_rand(); for (i = 1; i <= G->nv; i++) #if 0 w[i] = weight(G->v[i]) = 1.0; #else w[i] = weight(G->v[i]) = rng_unif_rand(rand, 100) + 1; #endif /* write graph in DIMACS format */ xassert(glp_write_ccdata(G, offsetof(v_data, w), "graph") == 0); /* find maximum weight clique */ c = xcalloc(1+G->nv, sizeof(int)); flag = xcalloc(1+G->nv, sizeof(char)); memset(&flag[1], 0, G->nv); t = xtime(); size = wclique1(G->nv, w, func, NULL, c); xprintf("Time used: %.1f s\n", xdifftime(xtime(), t)); /* check the clique found */ ind = xcalloc(1+G->nv, sizeof(int)); for (k = 1; k <= size; k++) { i = c[k]; deg = func(NULL, i, ind); for (kk = 1; kk <= size; kk++) flag[c[kk]] = 1; flag[i] = 0; for (kk = 1; kk <= deg; kk++) flag[ind[kk]] = 0; for (kk = 1; kk <= size; kk++) xassert(flag[c[kk]] == 0); } /* compute the clique weight */ sum = 0.0; for (i = 1; i <= size; i++) sum += w[c[i]]; xprintf("size = %d; sum = %g\n", size, sum); return 0; } #endif /* eof */ Rglpk/src/GLPK/glpbfx.c0000644000176000001440000000514412245352174014344 0ustar ripleyusers/* glpbfx.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ typedef struct BFX BFX; #define GLPBFX_DEFINED #include "glpbfx.h" #include "env.h" #include "glplux.h" struct BFX { int valid; LUX *lux; }; BFX *bfx_create_binv(void) { /* create factorization of the basis matrix */ BFX *bfx; bfx = xmalloc(sizeof(BFX)); bfx->valid = 0; bfx->lux = NULL; return bfx; } int bfx_factorize(BFX *binv, int m, int (*col)(void *info, int j, int ind[], mpq_t val[]), void *info) { /* compute factorization of the basis matrix */ int ret; xassert(m > 0); if (binv->lux != NULL && binv->lux->n != m) { lux_delete(binv->lux); binv->lux = NULL; } if (binv->lux == NULL) binv->lux = lux_create(m); ret = lux_decomp(binv->lux, col, info); binv->valid = (ret == 0); return ret; } void bfx_ftran(BFX *binv, mpq_t x[], int save) { /* perform forward transformation (FTRAN) */ xassert(binv->valid); lux_solve(binv->lux, 0, x); xassert(save == save); return; } void bfx_btran(BFX *binv, mpq_t x[]) { /* perform backward transformation (BTRAN) */ xassert(binv->valid); lux_solve(binv->lux, 1, x); return; } int bfx_update(BFX *binv, int j) { /* update factorization of the basis matrix */ xassert(binv->valid); xassert(1 <= j && j <= binv->lux->n); return 1; } void bfx_delete_binv(BFX *binv) { /* delete factorization of the basis matrix */ if (binv->lux != NULL) lux_delete(binv->lux); xfree(binv); return; } /* eof */ Rglpk/src/GLPK/env.c0000644000176000001440000001573612245352174013662 0ustar ripleyusers/* env.c (GLPK environment initialization/termination) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpk.h" #include "env.h" /*********************************************************************** * NAME * * glp_init_env - initialize GLPK environment * * SYNOPSIS * * int glp_init_env(void); * * DESCRIPTION * * The routine glp_init_env initializes the GLPK environment. Normally * the application program does not need to call this routine, because * it is called automatically on the first call to any API routine. * * RETURNS * * The routine glp_init_env returns one of the following codes: * * 0 - initialization successful; * 1 - environment has been already initialized; * 2 - initialization failed (insufficient memory); * 3 - initialization failed (unsupported programming model). */ int glp_init_env(void) { ENV *env; int ok; /* check if the programming model is supported */ ok = (CHAR_BIT == 8 && sizeof(char) == 1 && sizeof(short) == 2 && sizeof(int) == 4 && (sizeof(void *) == 4 || sizeof(void *) == 8)); if (!ok) return 3; /* check if the environment is already initialized */ if (tls_get_ptr() != NULL) return 1; /* allocate and initialize the environment block */ env = malloc(sizeof(ENV)); if (env == NULL) return 2; memset(env, 0, sizeof(ENV)); sprintf(env->version, "%d.%d", GLP_MAJOR_VERSION, GLP_MINOR_VERSION); env->self = env; env->term_buf = malloc(TBUF_SIZE); if (env->term_buf == NULL) { free(env); return 2; } env->term_out = GLP_ON; env->term_hook = NULL; env->term_info = NULL; env->tee_file = NULL; env->err_file = NULL; env->err_line = 0; env->err_hook = NULL; env->err_info = NULL; env->mem_limit = SIZE_T_MAX; env->mem_ptr = NULL; env->mem_count = env->mem_cpeak = 0; env->mem_total = env->mem_tpeak = 0; env->h_odbc = env->h_mysql = NULL; /* save pointer to the environment block */ tls_set_ptr(env); /* initialization successful */ return 0; } /*********************************************************************** * NAME * * get_env_ptr - retrieve pointer to environment block * * SYNOPSIS * * #include "env.h" * ENV *get_env_ptr(void); * * DESCRIPTION * * The routine get_env_ptr retrieves and returns a pointer to the GLPK * environment block. * * If the GLPK environment has not been initialized yet, the routine * performs initialization. If initialization fails, the routine prints * an error message to stderr and terminates the program. * * RETURNS * * The routine returns a pointer to the environment block. */ ENV *get_env_ptr(void) { ENV *env = tls_get_ptr(); /* check if the environment has been initialized */ if (env == NULL) { /* not initialized yet; perform initialization */ if (glp_init_env() != 0) { /* initialization failed; display an error message */ fprintf(stderr, "GLPK initialization failed\n"); fflush(stderr); /* and abnormally terminate the program */ abort(); } /* initialization successful; retrieve the pointer */ env = tls_get_ptr(); } /* check if the environment block is valid */ if (env->self != env) { fprintf(stderr, "Invalid GLPK environment\n"); fflush(stderr); abort(); } return env; } /*********************************************************************** * NAME * * glp_version - determine library version * * SYNOPSIS * * const char *glp_version(void); * * RETURNS * * The routine glp_version returns a pointer to a null-terminated * character string, which specifies the version of the GLPK library in * the form "X.Y", where X is the major version number, and Y is the * minor version number, for example, "4.16". */ const char *glp_version(void) { ENV *env = get_env_ptr(); return env->version; } /*********************************************************************** * NAME * * glp_free_env - free GLPK environment * * SYNOPSIS * * int glp_free_env(void); * * DESCRIPTION * * The routine glp_free_env frees all resources used by GLPK routines * (memory blocks, etc.) which are currently still in use. * * Normally the application program does not need to call this routine, * because GLPK routines always free all unused resources. However, if * the application program even has deleted all problem objects, there * will be several memory blocks still allocated for the library needs. * For some reasons the application program may want GLPK to free this * memory, in which case it should call glp_free_env. * * Note that a call to glp_free_env invalidates all problem objects as * if no GLPK routine were called. * * RETURNS * * 0 - termination successful; * 1 - environment is inactive (was not initialized). */ int glp_free_env(void) { ENV *env = tls_get_ptr(); MBD *desc; /* check if the environment is active */ if (env == NULL) return 1; /* check if the environment block is valid */ if (env->self != env) { fprintf(stderr, "Invalid GLPK environment\n"); fflush(stderr); abort(); } /* close handles to shared libraries */ if (env->h_odbc != NULL) xdlclose(env->h_odbc); if (env->h_mysql != NULL) xdlclose(env->h_mysql); /* free memory blocks which are still allocated */ while (env->mem_ptr != NULL) { desc = env->mem_ptr; env->mem_ptr = desc->next; free(desc); } /* close text file used for copying terminal output */ if (env->tee_file != NULL) fclose(env->tee_file); /* invalidate the environment block */ env->self = NULL; /* free memory allocated to the environment block */ free(env->term_buf); free(env); /* reset a pointer to the environment block */ tls_set_ptr(NULL); /* termination successful */ return 0; } /* eof */ Rglpk/src/GLPK/wclique.c0000644000176000001440000001653012245352174014534 0ustar ripleyusers/* wclique.c (maximum weight clique, Ostergard's algorithm) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Two subroutines sub() and wclique() below are intended to find a * maximum weight clique in a given undirected graph. These subroutines * are slightly modified version of the program WCLIQUE developed by * Patric Ostergard and based * on ideas from the article "P. R. J. Ostergard, A new algorithm for * the maximum-weight clique problem, submitted for publication", which * in turn is a generalization of the algorithm for unweighted graphs * presented in "P. R. J. Ostergard, A fast algorithm for the maximum * clique problem, submitted for publication". * * USED WITH PERMISSION OF THE AUTHOR OF THE ORIGINAL CODE. * * Changes were made by Andrew Makhorin . * * 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 . ***********************************************************************/ #include "env.h" #include "wclique.h" /*********************************************************************** * NAME * * wclique - find maximum weight clique with Ostergard's algorithm * * SYNOPSIS * * #include "wclique.h" * int wclique(int n, const int w[], const unsigned char a[], * int ind[]); * * DESCRIPTION * * The routine wclique finds a maximum weight clique in an undirected * graph with Ostergard's algorithm. * * INPUT PARAMETERS * * n is the number of vertices, n > 0. * * w[i], i = 1,...,n, is a weight of vertex i. * * a[*] is the strict (without main diagonal) lower triangle of the * graph adjacency matrix in packed format. * * OUTPUT PARAMETER * * ind[k], k = 1,...,size, is the number of a vertex included in the * clique found, 1 <= ind[k] <= n, where size is the number of vertices * in the clique returned on exit. * * RETURNS * * The routine returns the clique size, i.e. the number of vertices in * the clique. */ struct csa { /* common storage area */ int n; /* number of vertices */ const int *wt; /* int wt[0:n-1]; */ /* weights */ const unsigned char *a; /* adjacency matrix (packed lower triangle without main diag.) */ int record; /* weight of best clique */ int rec_level; /* number of vertices in best clique */ int *rec; /* int rec[0:n-1]; */ /* best clique so far */ int *clique; /* int clique[0:n-1]; */ /* table for pruning */ int *set; /* int set[0:n-1]; */ /* current clique */ }; #define n (csa->n) #define wt (csa->wt) #define a (csa->a) #define record (csa->record) #define rec_level (csa->rec_level) #define rec (csa->rec) #define clique (csa->clique) #define set (csa->set) #if 0 static int is_edge(struct csa *csa, int i, int j) { /* if there is arc (i,j), the routine returns true; otherwise * false; 0 <= i, j < n */ int k; xassert(0 <= i && i < n); xassert(0 <= j && j < n); if (i == j) return 0; if (i < j) k = i, i = j, j = k; k = (i * (i - 1)) / 2 + j; return a[k / CHAR_BIT] & (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT)); } #else #define is_edge(csa, i, j) ((i) == (j) ? 0 : \ (i) > (j) ? is_edge1(i, j) : is_edge1(j, i)) #define is_edge1(i, j) is_edge2(((i) * ((i) - 1)) / 2 + (j)) #define is_edge2(k) (a[(k) / CHAR_BIT] & \ (unsigned char)(1 << ((CHAR_BIT - 1) - (k) % CHAR_BIT))) #endif static void sub(struct csa *csa, int ct, int table[], int level, int weight, int l_weight) { int i, j, k, curr_weight, left_weight, *p1, *p2, *newtable; newtable = xcalloc(n, sizeof(int)); if (ct <= 0) { /* 0 or 1 elements left; include these */ if (ct == 0) { set[level++] = table[0]; weight += l_weight; } if (weight > record) { record = weight; rec_level = level; for (i = 0; i < level; i++) rec[i] = set[i]; } goto done; } for (i = ct; i >= 0; i--) { if ((level == 0) && (i < ct)) goto done; k = table[i]; if ((level > 0) && (clique[k] <= (record - weight))) goto done; /* prune */ set[level] = k; curr_weight = weight + wt[k]; l_weight -= wt[k]; if (l_weight <= (record - curr_weight)) goto done; /* prune */ p1 = newtable; p2 = table; left_weight = 0; while (p2 < table + i) { j = *p2++; if (is_edge(csa, j, k)) { *p1++ = j; left_weight += wt[j]; } } if (left_weight <= (record - curr_weight)) continue; sub(csa, p1 - newtable - 1, newtable, level + 1, curr_weight, left_weight); } done: xfree(newtable); return; } int wclique(int n_, const int w[], const unsigned char a_[], int ind[]) { struct csa csa_, *csa = &csa_; int i, j, p, max_wt, max_nwt, wth, *used, *nwt, *pos; double timer; n = n_; xassert(n > 0); wt = &w[1]; a = a_; record = 0; rec_level = 0; rec = &ind[1]; clique = xcalloc(n, sizeof(int)); set = xcalloc(n, sizeof(int)); used = xcalloc(n, sizeof(int)); nwt = xcalloc(n, sizeof(int)); pos = xcalloc(n, sizeof(int)); /* start timer */ timer = xtime(); /* order vertices */ for (i = 0; i < n; i++) { nwt[i] = 0; for (j = 0; j < n; j++) if (is_edge(csa, i, j)) nwt[i] += wt[j]; } for (i = 0; i < n; i++) used[i] = 0; for (i = n-1; i >= 0; i--) { max_wt = -1; max_nwt = -1; for (j = 0; j < n; j++) { if ((!used[j]) && ((wt[j] > max_wt) || (wt[j] == max_wt && nwt[j] > max_nwt))) { max_wt = wt[j]; max_nwt = nwt[j]; p = j; } } pos[i] = p; used[p] = 1; for (j = 0; j < n; j++) if ((!used[j]) && (j != p) && (is_edge(csa, p, j))) nwt[j] -= wt[p]; } /* main routine */ wth = 0; for (i = 0; i < n; i++) { wth += wt[pos[i]]; sub(csa, i, pos, 0, 0, wth); clique[pos[i]] = record; if (xdifftime(xtime(), timer) >= 5.0 - 0.001) { /* print current record and reset timer */ xprintf("level = %d (%d); best = %d\n", i+1, n, record); timer = xtime(); } } xfree(clique); xfree(set); xfree(used); xfree(nwt); xfree(pos); /* return the solution found */ for (i = 1; i <= rec_level; i++) ind[i]++; return rec_level; } #undef n #undef wt #undef a #undef record #undef rec_level #undef rec #undef clique #undef set /* eof */ Rglpk/src/GLPK/glpini02.c0000644000176000001440000002145512245352174014511 0ustar ripleyusers/* glpini02.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpapi.h" struct var { /* structural variable */ int j; /* ordinal number */ double q; /* penalty value */ }; static int fcmp(const void *ptr1, const void *ptr2) { /* this routine is passed to the qsort() function */ struct var *col1 = (void *)ptr1, *col2 = (void *)ptr2; if (col1->q < col2->q) return -1; if (col1->q > col2->q) return +1; return 0; } static int get_column(glp_prob *lp, int j, int ind[], double val[]) { /* Bixby's algorithm assumes that the constraint matrix is scaled such that the maximum absolute value in every non-zero row and column is 1 */ int k, len; double big; len = glp_get_mat_col(lp, j, ind, val); big = 0.0; for (k = 1; k <= len; k++) if (big < fabs(val[k])) big = fabs(val[k]); if (big == 0.0) big = 1.0; for (k = 1; k <= len; k++) val[k] /= big; return len; } static void cpx_basis(glp_prob *lp) { /* main routine */ struct var *C, *C2, *C3, *C4; int m, n, i, j, jk, k, l, ll, t, n2, n3, n4, type, len, *I, *r, *ind; double alpha, gamma, cmax, temp, *v, *val; xprintf("Constructing initial basis...\n"); /* determine the number of rows and columns */ m = glp_get_num_rows(lp); n = glp_get_num_cols(lp); /* allocate working arrays */ C = xcalloc(1+n, sizeof(struct var)); I = xcalloc(1+m, sizeof(int)); r = xcalloc(1+m, sizeof(int)); v = xcalloc(1+m, sizeof(double)); ind = xcalloc(1+m, sizeof(int)); val = xcalloc(1+m, sizeof(double)); /* make all auxiliary variables non-basic */ for (i = 1; i <= m; i++) { if (glp_get_row_type(lp, i) != GLP_DB) glp_set_row_stat(lp, i, GLP_NS); else if (fabs(glp_get_row_lb(lp, i)) <= fabs(glp_get_row_ub(lp, i))) glp_set_row_stat(lp, i, GLP_NL); else glp_set_row_stat(lp, i, GLP_NU); } /* make all structural variables non-basic */ for (j = 1; j <= n; j++) { if (glp_get_col_type(lp, j) != GLP_DB) glp_set_col_stat(lp, j, GLP_NS); else if (fabs(glp_get_col_lb(lp, j)) <= fabs(glp_get_col_ub(lp, j))) glp_set_col_stat(lp, j, GLP_NL); else glp_set_col_stat(lp, j, GLP_NU); } /* C2 is a set of free structural variables */ n2 = 0, C2 = C + 0; for (j = 1; j <= n; j++) { type = glp_get_col_type(lp, j); if (type == GLP_FR) { n2++; C2[n2].j = j; C2[n2].q = 0.0; } } /* C3 is a set of structural variables having excatly one (lower or upper) bound */ n3 = 0, C3 = C2 + n2; for (j = 1; j <= n; j++) { type = glp_get_col_type(lp, j); if (type == GLP_LO) { n3++; C3[n3].j = j; C3[n3].q = + glp_get_col_lb(lp, j); } else if (type == GLP_UP) { n3++; C3[n3].j = j; C3[n3].q = - glp_get_col_ub(lp, j); } } /* C4 is a set of structural variables having both (lower and upper) bounds */ n4 = 0, C4 = C3 + n3; for (j = 1; j <= n; j++) { type = glp_get_col_type(lp, j); if (type == GLP_DB) { n4++; C4[n4].j = j; C4[n4].q = glp_get_col_lb(lp, j) - glp_get_col_ub(lp, j); } } /* compute gamma = max{|c[j]|: 1 <= j <= n} */ gamma = 0.0; for (j = 1; j <= n; j++) { temp = fabs(glp_get_obj_coef(lp, j)); if (gamma < temp) gamma = temp; } /* compute cmax */ cmax = (gamma == 0.0 ? 1.0 : 1000.0 * gamma); /* compute final penalty for all structural variables within sets C2, C3, and C4 */ switch (glp_get_obj_dir(lp)) { case GLP_MIN: temp = +1.0; break; case GLP_MAX: temp = -1.0; break; default: xassert(lp != lp); } for (k = 1; k <= n2+n3+n4; k++) { j = C[k].j; C[k].q += (temp * glp_get_obj_coef(lp, j)) / cmax; } /* sort structural variables within C2, C3, and C4 in ascending order of penalty value */ qsort(C2+1, n2, sizeof(struct var), fcmp); for (k = 1; k < n2; k++) xassert(C2[k].q <= C2[k+1].q); qsort(C3+1, n3, sizeof(struct var), fcmp); for (k = 1; k < n3; k++) xassert(C3[k].q <= C3[k+1].q); qsort(C4+1, n4, sizeof(struct var), fcmp); for (k = 1; k < n4; k++) xassert(C4[k].q <= C4[k+1].q); /*** STEP 1 ***/ for (i = 1; i <= m; i++) { type = glp_get_row_type(lp, i); if (type != GLP_FX) { /* row i is either free or inequality constraint */ glp_set_row_stat(lp, i, GLP_BS); I[i] = 1; r[i] = 1; } else { /* row i is equality constraint */ I[i] = 0; r[i] = 0; } v[i] = +DBL_MAX; } /*** STEP 2 ***/ for (k = 1; k <= n2+n3+n4; k++) { jk = C[k].j; len = get_column(lp, jk, ind, val); /* let alpha = max{|A[l,jk]|: r[l] = 0} and let l' be such that alpha = |A[l',jk]| */ alpha = 0.0, ll = 0; for (t = 1; t <= len; t++) { l = ind[t]; if (r[l] == 0 && alpha < fabs(val[t])) alpha = fabs(val[t]), ll = l; } if (alpha >= 0.99) { /* B := B union {jk} */ glp_set_col_stat(lp, jk, GLP_BS); I[ll] = 1; v[ll] = alpha; /* r[l] := r[l] + 1 for all l such that |A[l,jk]| != 0 */ for (t = 1; t <= len; t++) { l = ind[t]; if (val[t] != 0.0) r[l]++; } /* continue to the next k */ continue; } /* if |A[l,jk]| > 0.01 * v[l] for some l, continue to the next k */ for (t = 1; t <= len; t++) { l = ind[t]; if (fabs(val[t]) > 0.01 * v[l]) break; } if (t <= len) continue; /* otherwise, let alpha = max{|A[l,jk]|: I[l] = 0} and let l' be such that alpha = |A[l',jk]| */ alpha = 0.0, ll = 0; for (t = 1; t <= len; t++) { l = ind[t]; if (I[l] == 0 && alpha < fabs(val[t])) alpha = fabs(val[t]), ll = l; } /* if alpha = 0, continue to the next k */ if (alpha == 0.0) continue; /* B := B union {jk} */ glp_set_col_stat(lp, jk, GLP_BS); I[ll] = 1; v[ll] = alpha; /* r[l] := r[l] + 1 for all l such that |A[l,jk]| != 0 */ for (t = 1; t <= len; t++) { l = ind[t]; if (val[t] != 0.0) r[l]++; } } /*** STEP 3 ***/ /* add an artificial variable (auxiliary variable for equality constraint) to cover each remaining uncovered row */ for (i = 1; i <= m; i++) if (I[i] == 0) glp_set_row_stat(lp, i, GLP_BS); /* free working arrays */ xfree(C); xfree(I); xfree(r); xfree(v); xfree(ind); xfree(val); return; } /*********************************************************************** * NAME * * glp_cpx_basis - construct Bixby's initial LP basis * * SYNOPSIS * * void glp_cpx_basis(glp_prob *lp); * * DESCRIPTION * * The routine glp_cpx_basis constructs an advanced initial basis for * the specified problem object. * * The routine is based on Bixby's algorithm described in the paper: * * Robert E. Bixby. Implementing the Simplex Method: The Initial Basis. * ORSA Journal on Computing, Vol. 4, No. 3, 1992, pp. 267-84. */ void glp_cpx_basis(glp_prob *lp) { if (lp->m == 0 || lp->n == 0) glp_std_basis(lp); else cpx_basis(lp); return; } /* eof */ Rglpk/src/GLPK/glpmpl.h0000644000176000001440000025744712245352174014401 0ustar ripleyusers/* glpmpl.h (GNU MathProg translator) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPMPL_H #define GLPMPL_H #if 1 /* 11/VI-2013 */ #include "env2.h" #endif #include "glpavl.h" #include "glplib.h" #include "rng.h" #if 0 /* 22/I-2013 */ typedef struct MPL MPL; #else typedef struct glp_tran MPL; #endif typedef char STRING; typedef struct SYMBOL SYMBOL; typedef struct TUPLE TUPLE; typedef struct ARRAY ELEMSET; typedef struct ELEMVAR ELEMVAR; typedef struct FORMULA FORMULA; typedef struct ELEMCON ELEMCON; typedef union VALUE VALUE; typedef struct ARRAY ARRAY; typedef struct MEMBER MEMBER; #if 1 /* many C compilers have DOMAIN declared in :( */ #undef DOMAIN #define DOMAIN DOMAIN1 #endif typedef struct DOMAIN DOMAIN; typedef struct DOMAIN_BLOCK DOMAIN_BLOCK; typedef struct DOMAIN_SLOT DOMAIN_SLOT; typedef struct SET SET; typedef struct WITHIN WITHIN; typedef struct GADGET GADGET; typedef struct PARAMETER PARAMETER; typedef struct CONDITION CONDITION; typedef struct VARIABLE VARIABLE; typedef struct CONSTRAINT CONSTRAINT; typedef struct TABLE TABLE; typedef struct TABARG TABARG; typedef struct TABFLD TABFLD; typedef struct TABIN TABIN; typedef struct TABOUT TABOUT; typedef struct TABDCA TABDCA; typedef union OPERANDS OPERANDS; typedef struct ARG_LIST ARG_LIST; typedef struct CODE CODE; typedef struct CHECK CHECK; typedef struct DISPLAY DISPLAY; typedef struct DISPLAY1 DISPLAY1; typedef struct PRINTF PRINTF; typedef struct PRINTF1 PRINTF1; typedef struct FOR FOR; typedef struct STATEMENT STATEMENT; typedef struct TUPLE SLICE; /**********************************************************************/ /* * * TRANSLATOR DATABASE * * */ /**********************************************************************/ #define A_BINARY 101 /* something binary */ #define A_CHECK 102 /* check statement */ #define A_CONSTRAINT 103 /* model constraint */ #define A_DISPLAY 104 /* display statement */ #define A_ELEMCON 105 /* elemental constraint/objective */ #define A_ELEMSET 106 /* elemental set */ #define A_ELEMVAR 107 /* elemental variable */ #define A_EXPRESSION 108 /* expression */ #define A_FOR 109 /* for statement */ #define A_FORMULA 110 /* formula */ #define A_INDEX 111 /* dummy index */ #define A_INPUT 112 /* input table */ #define A_INTEGER 113 /* something integer */ #define A_LOGICAL 114 /* something logical */ #define A_MAXIMIZE 115 /* objective has to be maximized */ #define A_MINIMIZE 116 /* objective has to be minimized */ #define A_NONE 117 /* nothing */ #define A_NUMERIC 118 /* something numeric */ #define A_OUTPUT 119 /* output table */ #define A_PARAMETER 120 /* model parameter */ #define A_PRINTF 121 /* printf statement */ #define A_SET 122 /* model set */ #define A_SOLVE 123 /* solve statement */ #define A_SYMBOLIC 124 /* something symbolic */ #define A_TABLE 125 /* data table */ #define A_TUPLE 126 /* n-tuple */ #define A_VARIABLE 127 /* model variable */ #define MAX_LENGTH 100 /* maximal length of any symbolic value (this includes symbolic names, numeric and string literals, and all symbolic values that may appear during the evaluation phase) */ #define CONTEXT_SIZE 60 /* size of the context queue, in characters */ #define OUTBUF_SIZE 1024 /* size of the output buffer, in characters */ #if 0 /* 22/I-2013 */ struct MPL #else struct glp_tran #endif { /* translator database */ /*--------------------------------------------------------------*/ /* scanning segment */ int line; /* number of the current text line */ int c; /* the current character or EOF */ int token; /* the current token: */ #define T_EOF 201 /* end of file */ #define T_NAME 202 /* symbolic name (model section only) */ #define T_SYMBOL 203 /* symbol (data section only) */ #define T_NUMBER 204 /* numeric literal */ #define T_STRING 205 /* string literal */ #define T_AND 206 /* and && */ #define T_BY 207 /* by */ #define T_CROSS 208 /* cross */ #define T_DIFF 209 /* diff */ #define T_DIV 210 /* div */ #define T_ELSE 211 /* else */ #define T_IF 212 /* if */ #define T_IN 213 /* in */ #define T_INFINITY 214 /* Infinity */ #define T_INTER 215 /* inter */ #define T_LESS 216 /* less */ #define T_MOD 217 /* mod */ #define T_NOT 218 /* not ! */ #define T_OR 219 /* or || */ #define T_SPTP 220 /* s.t. */ #define T_SYMDIFF 221 /* symdiff */ #define T_THEN 222 /* then */ #define T_UNION 223 /* union */ #define T_WITHIN 224 /* within */ #define T_PLUS 225 /* + */ #define T_MINUS 226 /* - */ #define T_ASTERISK 227 /* * */ #define T_SLASH 228 /* / */ #define T_POWER 229 /* ^ ** */ #define T_LT 230 /* < */ #define T_LE 231 /* <= */ #define T_EQ 232 /* = == */ #define T_GE 233 /* >= */ #define T_GT 234 /* > */ #define T_NE 235 /* <> != */ #define T_CONCAT 236 /* & */ #define T_BAR 237 /* | */ #define T_POINT 238 /* . */ #define T_COMMA 239 /* , */ #define T_COLON 240 /* : */ #define T_SEMICOLON 241 /* ; */ #define T_ASSIGN 242 /* := */ #define T_DOTS 243 /* .. */ #define T_LEFT 244 /* ( */ #define T_RIGHT 245 /* ) */ #define T_LBRACKET 246 /* [ */ #define T_RBRACKET 247 /* ] */ #define T_LBRACE 248 /* { */ #define T_RBRACE 249 /* } */ #define T_APPEND 250 /* >> */ #define T_TILDE 251 /* ~ */ #define T_INPUT 252 /* <- */ int imlen; /* length of the current token */ char *image; /* char image[MAX_LENGTH+1]; */ /* image of the current token */ double value; /* value of the current token (for T_NUMBER only) */ int b_token; /* the previous token */ int b_imlen; /* length of the previous token */ char *b_image; /* char b_image[MAX_LENGTH+1]; */ /* image of the previous token */ double b_value; /* value of the previous token (if token is T_NUMBER) */ int f_dots; /* if this flag is set, the next token should be recognized as T_DOTS, not as T_POINT */ int f_scan; /* if this flag is set, the next token is already scanned */ int f_token; /* the next token */ int f_imlen; /* length of the next token */ char *f_image; /* char f_image[MAX_LENGTH+1]; */ /* image of the next token */ double f_value; /* value of the next token (if token is T_NUMBER) */ char *context; /* char context[CONTEXT_SIZE]; */ /* context circular queue (not null-terminated!) */ int c_ptr; /* pointer to the current position in the context queue */ int flag_d; /* if this flag is set, the data section is being processed */ /*--------------------------------------------------------------*/ /* translating segment */ DMP *pool; /* memory pool used to allocate all data instances created during the translation phase */ AVL *tree; /* symbolic name table: node.type = A_INDEX => node.link -> DOMAIN_SLOT node.type = A_SET => node.link -> SET node.type = A_PARAMETER => node.link -> PARAMETER node.type = A_VARIABLE => node.link -> VARIABLE node.type = A_CONSTRANT => node.link -> CONSTRAINT */ STATEMENT *model; /* linked list of model statements in the original order */ int flag_x; /* if this flag is set, the current token being left parenthesis begins a slice that allows recognizing any undeclared symbolic names as dummy indices; this flag is automatically reset once the next token has been scanned */ int as_within; /* the warning "in understood as within" has been issued */ int as_in; /* the warning "within understood as in" has been issued */ int as_binary; /* the warning "logical understood as binary" has been issued */ int flag_s; /* if this flag is set, the solve statement has been parsed */ /*--------------------------------------------------------------*/ /* common segment */ DMP *strings; /* memory pool to allocate STRING data structures */ DMP *symbols; /* memory pool to allocate SYMBOL data structures */ DMP *tuples; /* memory pool to allocate TUPLE data structures */ DMP *arrays; /* memory pool to allocate ARRAY data structures */ DMP *members; /* memory pool to allocate MEMBER data structures */ DMP *elemvars; /* memory pool to allocate ELEMVAR data structures */ DMP *formulae; /* memory pool to allocate FORMULA data structures */ DMP *elemcons; /* memory pool to allocate ELEMCON data structures */ ARRAY *a_list; /* linked list of all arrays in the database */ char *sym_buf; /* char sym_buf[255+1]; */ /* working buffer used by the routine format_symbol */ char *tup_buf; /* char tup_buf[255+1]; */ /* working buffer used by the routine format_tuple */ /*--------------------------------------------------------------*/ /* generating/postsolving segment */ RNG *rand; /* pseudo-random number generator */ int flag_p; /* if this flag is set, the postsolving phase is in effect */ STATEMENT *stmt; /* model statement being currently executed */ TABDCA *dca; /* pointer to table driver communication area for table statement currently executed */ int m; /* number of rows in the problem, m >= 0 */ int n; /* number of columns in the problem, n >= 0 */ ELEMCON **row; /* ELEMCON *row[1+m]; */ /* row[0] is not used; row[i] is elemental constraint or objective, which corresponds to i-th row of the problem, 1 <= i <= m */ ELEMVAR **col; /* ELEMVAR *col[1+n]; */ /* col[0] is not used; col[j] is elemental variable, which corresponds to j-th column of the problem, 1 <= j <= n */ /*--------------------------------------------------------------*/ /* input/output segment */ XFILE *in_fp; /* stream assigned to the input text file */ char *in_file; /* name of the input text file */ XFILE *out_fp; /* stream assigned to the output text file used to write all data produced by display and printf statements; NULL means the data should be sent to stdout via the routine xprintf */ char *out_file; /* name of the output text file */ #if 0 /* 08/XI-2009 */ char *out_buf; /* char out_buf[OUTBUF_SIZE] */ /* buffer to accumulate output data */ int out_cnt; /* count of data bytes stored in the output buffer */ #endif XFILE *prt_fp; /* stream assigned to the print text file; may be NULL */ char *prt_file; /* name of the output print file */ /*--------------------------------------------------------------*/ /* solver interface segment */ jmp_buf jump; /* jump address for non-local go to in case of error */ int phase; /* phase of processing: 0 - database is being or has been initialized 1 - model section is being or has been read 2 - data section is being or has been read 3 - model is being or has been generated/postsolved 4 - model processing error has occurred */ char *mod_file; /* name of the input text file, which contains model section */ char *mpl_buf; /* char mpl_buf[255+1]; */ /* working buffer used by some interface routines */ }; /**********************************************************************/ /* * * PROCESSING MODEL SECTION * * */ /**********************************************************************/ #define alloc(type) ((type *)dmp_get_atomv(mpl->pool, sizeof(type))) /* allocate atom of given type */ #define enter_context _glp_mpl_enter_context void enter_context(MPL *mpl); /* enter current token into context queue */ #define print_context _glp_mpl_print_context void print_context(MPL *mpl); /* print current content of context queue */ #define get_char _glp_mpl_get_char void get_char(MPL *mpl); /* scan next character from input text file */ #define append_char _glp_mpl_append_char void append_char(MPL *mpl); /* append character to current token */ #define get_token _glp_mpl_get_token void get_token(MPL *mpl); /* scan next token from input text file */ #define unget_token _glp_mpl_unget_token void unget_token(MPL *mpl); /* return current token back to input stream */ #define is_keyword _glp_mpl_is_keyword int is_keyword(MPL *mpl, char *keyword); /* check if current token is given non-reserved keyword */ #define is_reserved _glp_mpl_is_reserved int is_reserved(MPL *mpl); /* check if current token is reserved keyword */ #define make_code _glp_mpl_make_code CODE *make_code(MPL *mpl, int op, OPERANDS *arg, int type, int dim); /* generate pseudo-code (basic routine) */ #define make_unary _glp_mpl_make_unary CODE *make_unary(MPL *mpl, int op, CODE *x, int type, int dim); /* generate pseudo-code for unary operation */ #define make_binary _glp_mpl_make_binary CODE *make_binary(MPL *mpl, int op, CODE *x, CODE *y, int type, int dim); /* generate pseudo-code for binary operation */ #define make_ternary _glp_mpl_make_ternary CODE *make_ternary(MPL *mpl, int op, CODE *x, CODE *y, CODE *z, int type, int dim); /* generate pseudo-code for ternary operation */ #define numeric_literal _glp_mpl_numeric_literal CODE *numeric_literal(MPL *mpl); /* parse reference to numeric literal */ #define string_literal _glp_mpl_string_literal CODE *string_literal(MPL *mpl); /* parse reference to string literal */ #define create_arg_list _glp_mpl_create_arg_list ARG_LIST *create_arg_list(MPL *mpl); /* create empty operands list */ #define expand_arg_list _glp_mpl_expand_arg_list ARG_LIST *expand_arg_list(MPL *mpl, ARG_LIST *list, CODE *x); /* append operand to operands list */ #define arg_list_len _glp_mpl_arg_list_len int arg_list_len(MPL *mpl, ARG_LIST *list); /* determine length of operands list */ #define subscript_list _glp_mpl_subscript_list ARG_LIST *subscript_list(MPL *mpl); /* parse subscript list */ #define object_reference _glp_mpl_object_reference CODE *object_reference(MPL *mpl); /* parse reference to named object */ #define numeric_argument _glp_mpl_numeric_argument CODE *numeric_argument(MPL *mpl, char *func); /* parse argument passed to built-in function */ #define symbolic_argument _glp_mpl_symbolic_argument CODE *symbolic_argument(MPL *mpl, char *func); #define elemset_argument _glp_mpl_elemset_argument CODE *elemset_argument(MPL *mpl, char *func); #define function_reference _glp_mpl_function_reference CODE *function_reference(MPL *mpl); /* parse reference to built-in function */ #define create_domain _glp_mpl_create_domain DOMAIN *create_domain(MPL *mpl); /* create empty domain */ #define create_block _glp_mpl_create_block DOMAIN_BLOCK *create_block(MPL *mpl); /* create empty domain block */ #define append_block _glp_mpl_append_block void append_block(MPL *mpl, DOMAIN *domain, DOMAIN_BLOCK *block); /* append domain block to specified domain */ #define append_slot _glp_mpl_append_slot DOMAIN_SLOT *append_slot(MPL *mpl, DOMAIN_BLOCK *block, char *name, CODE *code); /* create and append new slot to domain block */ #define expression_list _glp_mpl_expression_list CODE *expression_list(MPL *mpl); /* parse expression list */ #define literal_set _glp_mpl_literal_set CODE *literal_set(MPL *mpl, CODE *code); /* parse literal set */ #define indexing_expression _glp_mpl_indexing_expression DOMAIN *indexing_expression(MPL *mpl); /* parse indexing expression */ #define close_scope _glp_mpl_close_scope void close_scope(MPL *mpl, DOMAIN *domain); /* close scope of indexing expression */ #define iterated_expression _glp_mpl_iterated_expression CODE *iterated_expression(MPL *mpl); /* parse iterated expression */ #define domain_arity _glp_mpl_domain_arity int domain_arity(MPL *mpl, DOMAIN *domain); /* determine arity of domain */ #define set_expression _glp_mpl_set_expression CODE *set_expression(MPL *mpl); /* parse set expression */ #define branched_expression _glp_mpl_branched_expression CODE *branched_expression(MPL *mpl); /* parse conditional expression */ #define primary_expression _glp_mpl_primary_expression CODE *primary_expression(MPL *mpl); /* parse primary expression */ #define error_preceding _glp_mpl_error_preceding void error_preceding(MPL *mpl, char *opstr); /* raise error if preceding operand has wrong type */ #define error_following _glp_mpl_error_following void error_following(MPL *mpl, char *opstr); /* raise error if following operand has wrong type */ #define error_dimension _glp_mpl_error_dimension void error_dimension(MPL *mpl, char *opstr, int dim1, int dim2); /* raise error if operands have different dimension */ #define expression_0 _glp_mpl_expression_0 CODE *expression_0(MPL *mpl); /* parse expression of level 0 */ #define expression_1 _glp_mpl_expression_1 CODE *expression_1(MPL *mpl); /* parse expression of level 1 */ #define expression_2 _glp_mpl_expression_2 CODE *expression_2(MPL *mpl); /* parse expression of level 2 */ #define expression_3 _glp_mpl_expression_3 CODE *expression_3(MPL *mpl); /* parse expression of level 3 */ #define expression_4 _glp_mpl_expression_4 CODE *expression_4(MPL *mpl); /* parse expression of level 4 */ #define expression_5 _glp_mpl_expression_5 CODE *expression_5(MPL *mpl); /* parse expression of level 5 */ #define expression_6 _glp_mpl_expression_6 CODE *expression_6(MPL *mpl); /* parse expression of level 6 */ #define expression_7 _glp_mpl_expression_7 CODE *expression_7(MPL *mpl); /* parse expression of level 7 */ #define expression_8 _glp_mpl_expression_8 CODE *expression_8(MPL *mpl); /* parse expression of level 8 */ #define expression_9 _glp_mpl_expression_9 CODE *expression_9(MPL *mpl); /* parse expression of level 9 */ #define expression_10 _glp_mpl_expression_10 CODE *expression_10(MPL *mpl); /* parse expression of level 10 */ #define expression_11 _glp_mpl_expression_11 CODE *expression_11(MPL *mpl); /* parse expression of level 11 */ #define expression_12 _glp_mpl_expression_12 CODE *expression_12(MPL *mpl); /* parse expression of level 12 */ #define expression_13 _glp_mpl_expression_13 CODE *expression_13(MPL *mpl); /* parse expression of level 13 */ #define set_statement _glp_mpl_set_statement SET *set_statement(MPL *mpl); /* parse set statement */ #define parameter_statement _glp_mpl_parameter_statement PARAMETER *parameter_statement(MPL *mpl); /* parse parameter statement */ #define variable_statement _glp_mpl_variable_statement VARIABLE *variable_statement(MPL *mpl); /* parse variable statement */ #define constraint_statement _glp_mpl_constraint_statement CONSTRAINT *constraint_statement(MPL *mpl); /* parse constraint statement */ #define objective_statement _glp_mpl_objective_statement CONSTRAINT *objective_statement(MPL *mpl); /* parse objective statement */ #define table_statement _glp_mpl_table_statement TABLE *table_statement(MPL *mpl); /* parse table statement */ #define solve_statement _glp_mpl_solve_statement void *solve_statement(MPL *mpl); /* parse solve statement */ #define check_statement _glp_mpl_check_statement CHECK *check_statement(MPL *mpl); /* parse check statement */ #define display_statement _glp_mpl_display_statement DISPLAY *display_statement(MPL *mpl); /* parse display statement */ #define printf_statement _glp_mpl_printf_statement PRINTF *printf_statement(MPL *mpl); /* parse printf statement */ #define for_statement _glp_mpl_for_statement FOR *for_statement(MPL *mpl); /* parse for statement */ #define end_statement _glp_mpl_end_statement void end_statement(MPL *mpl); /* parse end statement */ #define simple_statement _glp_mpl_simple_statement STATEMENT *simple_statement(MPL *mpl, int spec); /* parse simple statement */ #define model_section _glp_mpl_model_section void model_section(MPL *mpl); /* parse model section */ /**********************************************************************/ /* * * PROCESSING DATA SECTION * * */ /**********************************************************************/ #if 2 + 2 == 5 struct SLICE /* see TUPLE */ { /* component of slice; the slice itself is associated with its first component; slices are similar to n-tuples with exception that some slice components (which are indicated by asterisks) don't refer to any symbols */ SYMBOL *sym; /* symbol, which this component refers to; can be NULL */ SLICE *next; /* the next component of slice */ }; #endif #define create_slice _glp_mpl_create_slice SLICE *create_slice(MPL *mpl); /* create slice */ #define expand_slice _glp_mpl_expand_slice SLICE *expand_slice ( MPL *mpl, SLICE *slice, /* destroyed */ SYMBOL *sym /* destroyed */ ); /* append new component to slice */ #define slice_dimen _glp_mpl_slice_dimen int slice_dimen ( MPL *mpl, SLICE *slice /* not changed */ ); /* determine dimension of slice */ #define slice_arity _glp_mpl_slice_arity int slice_arity ( MPL *mpl, SLICE *slice /* not changed */ ); /* determine arity of slice */ #define fake_slice _glp_mpl_fake_slice SLICE *fake_slice(MPL *mpl, int dim); /* create fake slice of all asterisks */ #define delete_slice _glp_mpl_delete_slice void delete_slice ( MPL *mpl, SLICE *slice /* destroyed */ ); /* delete slice */ #define is_number _glp_mpl_is_number int is_number(MPL *mpl); /* check if current token is number */ #define is_symbol _glp_mpl_is_symbol int is_symbol(MPL *mpl); /* check if current token is symbol */ #define is_literal _glp_mpl_is_literal int is_literal(MPL *mpl, char *literal); /* check if current token is given symbolic literal */ #define read_number _glp_mpl_read_number double read_number(MPL *mpl); /* read number */ #define read_symbol _glp_mpl_read_symbol SYMBOL *read_symbol(MPL *mpl); /* read symbol */ #define read_slice _glp_mpl_read_slice SLICE *read_slice ( MPL *mpl, char *name, /* not changed */ int dim ); /* read slice */ #define select_set _glp_mpl_select_set SET *select_set ( MPL *mpl, char *name /* not changed */ ); /* select set to saturate it with elemental sets */ #define simple_format _glp_mpl_simple_format void simple_format ( MPL *mpl, SET *set, /* not changed */ MEMBER *memb, /* modified */ SLICE *slice /* not changed */ ); /* read set data block in simple format */ #define matrix_format _glp_mpl_matrix_format void matrix_format ( MPL *mpl, SET *set, /* not changed */ MEMBER *memb, /* modified */ SLICE *slice, /* not changed */ int tr ); /* read set data block in matrix format */ #define set_data _glp_mpl_set_data void set_data(MPL *mpl); /* read set data */ #define select_parameter _glp_mpl_select_parameter PARAMETER *select_parameter ( MPL *mpl, char *name /* not changed */ ); /* select parameter to saturate it with data */ #define set_default _glp_mpl_set_default void set_default ( MPL *mpl, PARAMETER *par, /* not changed */ SYMBOL *altval /* destroyed */ ); /* set default parameter value */ #define read_value _glp_mpl_read_value MEMBER *read_value ( MPL *mpl, PARAMETER *par, /* not changed */ TUPLE *tuple /* destroyed */ ); /* read value and assign it to parameter member */ #define plain_format _glp_mpl_plain_format void plain_format ( MPL *mpl, PARAMETER *par, /* not changed */ SLICE *slice /* not changed */ ); /* read parameter data block in plain format */ #define tabular_format _glp_mpl_tabular_format void tabular_format ( MPL *mpl, PARAMETER *par, /* not changed */ SLICE *slice, /* not changed */ int tr ); /* read parameter data block in tabular format */ #define tabbing_format _glp_mpl_tabbing_format void tabbing_format ( MPL *mpl, SYMBOL *altval /* not changed */ ); /* read parameter data block in tabbing format */ #define parameter_data _glp_mpl_parameter_data void parameter_data(MPL *mpl); /* read parameter data */ #define data_section _glp_mpl_data_section void data_section(MPL *mpl); /* read data section */ /**********************************************************************/ /* * * FLOATING-POINT NUMBERS * * */ /**********************************************************************/ #define fp_add _glp_mpl_fp_add double fp_add(MPL *mpl, double x, double y); /* floating-point addition */ #define fp_sub _glp_mpl_fp_sub double fp_sub(MPL *mpl, double x, double y); /* floating-point subtraction */ #define fp_less _glp_mpl_fp_less double fp_less(MPL *mpl, double x, double y); /* floating-point non-negative subtraction */ #define fp_mul _glp_mpl_fp_mul double fp_mul(MPL *mpl, double x, double y); /* floating-point multiplication */ #define fp_div _glp_mpl_fp_div double fp_div(MPL *mpl, double x, double y); /* floating-point division */ #define fp_idiv _glp_mpl_fp_idiv double fp_idiv(MPL *mpl, double x, double y); /* floating-point quotient of exact division */ #define fp_mod _glp_mpl_fp_mod double fp_mod(MPL *mpl, double x, double y); /* floating-point remainder of exact division */ #define fp_power _glp_mpl_fp_power double fp_power(MPL *mpl, double x, double y); /* floating-point exponentiation (raise to power) */ #define fp_exp _glp_mpl_fp_exp double fp_exp(MPL *mpl, double x); /* floating-point base-e exponential */ #define fp_log _glp_mpl_fp_log double fp_log(MPL *mpl, double x); /* floating-point natural logarithm */ #define fp_log10 _glp_mpl_fp_log10 double fp_log10(MPL *mpl, double x); /* floating-point common (decimal) logarithm */ #define fp_sqrt _glp_mpl_fp_sqrt double fp_sqrt(MPL *mpl, double x); /* floating-point square root */ #define fp_sin _glp_mpl_fp_sin double fp_sin(MPL *mpl, double x); /* floating-point trigonometric sine */ #define fp_cos _glp_mpl_fp_cos double fp_cos(MPL *mpl, double x); /* floating-point trigonometric cosine */ #define fp_atan _glp_mpl_fp_atan double fp_atan(MPL *mpl, double x); /* floating-point trigonometric arctangent */ #define fp_atan2 _glp_mpl_fp_atan2 double fp_atan2(MPL *mpl, double y, double x); /* floating-point trigonometric arctangent */ #define fp_round _glp_mpl_fp_round double fp_round(MPL *mpl, double x, double n); /* round floating-point value to n fractional digits */ #define fp_trunc _glp_mpl_fp_trunc double fp_trunc(MPL *mpl, double x, double n); /* truncate floating-point value to n fractional digits */ /**********************************************************************/ /* * * PSEUDO-RANDOM NUMBER GENERATORS * * */ /**********************************************************************/ #define fp_irand224 _glp_mpl_fp_irand224 double fp_irand224(MPL *mpl); /* pseudo-random integer in the range [0, 2^24) */ #define fp_uniform01 _glp_mpl_fp_uniform01 double fp_uniform01(MPL *mpl); /* pseudo-random number in the range [0, 1) */ #define fp_uniform _glp_mpl_uniform double fp_uniform(MPL *mpl, double a, double b); /* pseudo-random number in the range [a, b) */ #define fp_normal01 _glp_mpl_fp_normal01 double fp_normal01(MPL *mpl); /* Gaussian random variate with mu = 0 and sigma = 1 */ #define fp_normal _glp_mpl_fp_normal double fp_normal(MPL *mpl, double mu, double sigma); /* Gaussian random variate with specified mu and sigma */ /**********************************************************************/ /* * * DATE/TIME * * */ /**********************************************************************/ #define fn_gmtime _glp_mpl_fn_gmtime double fn_gmtime(MPL *mpl); /* obtain the current calendar time (UTC) */ #define fn_str2time _glp_mpl_fn_str2time double fn_str2time(MPL *mpl, const char *str, const char *fmt); /* convert character string to the calendar time */ #define fn_time2str _glp_mpl_fn_time2str void fn_time2str(MPL *mpl, char *str, double t, const char *fmt); /* convert the calendar time to character string */ /**********************************************************************/ /* * * CHARACTER STRINGS * * */ /**********************************************************************/ #define create_string _glp_mpl_create_string STRING *create_string ( MPL *mpl, char buf[MAX_LENGTH+1] /* not changed */ ); /* create character string */ #define copy_string _glp_mpl_copy_string STRING *copy_string ( MPL *mpl, STRING *str /* not changed */ ); /* make copy of character string */ #define compare_strings _glp_mpl_compare_strings int compare_strings ( MPL *mpl, STRING *str1, /* not changed */ STRING *str2 /* not changed */ ); /* compare one character string with another */ #define fetch_string _glp_mpl_fetch_string char *fetch_string ( MPL *mpl, STRING *str, /* not changed */ char buf[MAX_LENGTH+1] /* modified */ ); /* extract content of character string */ #define delete_string _glp_mpl_delete_string void delete_string ( MPL *mpl, STRING *str /* destroyed */ ); /* delete character string */ /**********************************************************************/ /* * * SYMBOLS * * */ /**********************************************************************/ struct SYMBOL { /* symbol (numeric or abstract quantity) */ double num; /* numeric value of symbol (used only if str == NULL) */ STRING *str; /* abstract value of symbol (used only if str != NULL) */ }; #define create_symbol_num _glp_mpl_create_symbol_num SYMBOL *create_symbol_num(MPL *mpl, double num); /* create symbol of numeric type */ #define create_symbol_str _glp_mpl_create_symbol_str SYMBOL *create_symbol_str ( MPL *mpl, STRING *str /* destroyed */ ); /* create symbol of abstract type */ #define copy_symbol _glp_mpl_copy_symbol SYMBOL *copy_symbol ( MPL *mpl, SYMBOL *sym /* not changed */ ); /* make copy of symbol */ #define compare_symbols _glp_mpl_compare_symbols int compare_symbols ( MPL *mpl, SYMBOL *sym1, /* not changed */ SYMBOL *sym2 /* not changed */ ); /* compare one symbol with another */ #define delete_symbol _glp_mpl_delete_symbol void delete_symbol ( MPL *mpl, SYMBOL *sym /* destroyed */ ); /* delete symbol */ #define format_symbol _glp_mpl_format_symbol char *format_symbol ( MPL *mpl, SYMBOL *sym /* not changed */ ); /* format symbol for displaying or printing */ #define concat_symbols _glp_mpl_concat_symbols SYMBOL *concat_symbols ( MPL *mpl, SYMBOL *sym1, /* destroyed */ SYMBOL *sym2 /* destroyed */ ); /* concatenate one symbol with another */ /**********************************************************************/ /* * * N-TUPLES * * */ /**********************************************************************/ struct TUPLE { /* component of n-tuple; the n-tuple itself is associated with its first component; (note that 0-tuple has no components) */ SYMBOL *sym; /* symbol, which the component refers to; cannot be NULL */ TUPLE *next; /* the next component of n-tuple */ }; #define create_tuple _glp_mpl_create_tuple TUPLE *create_tuple(MPL *mpl); /* create n-tuple */ #define expand_tuple _glp_mpl_expand_tuple TUPLE *expand_tuple ( MPL *mpl, TUPLE *tuple, /* destroyed */ SYMBOL *sym /* destroyed */ ); /* append symbol to n-tuple */ #define tuple_dimen _glp_mpl_tuple_dimen int tuple_dimen ( MPL *mpl, TUPLE *tuple /* not changed */ ); /* determine dimension of n-tuple */ #define copy_tuple _glp_mpl_copy_tuple TUPLE *copy_tuple ( MPL *mpl, TUPLE *tuple /* not changed */ ); /* make copy of n-tuple */ #define compare_tuples _glp_mpl_compare_tuples int compare_tuples ( MPL *mpl, TUPLE *tuple1, /* not changed */ TUPLE *tuple2 /* not changed */ ); /* compare one n-tuple with another */ #define build_subtuple _glp_mpl_build_subtuple TUPLE *build_subtuple ( MPL *mpl, TUPLE *tuple, /* not changed */ int dim ); /* build subtuple of given n-tuple */ #define delete_tuple _glp_mpl_delete_tuple void delete_tuple ( MPL *mpl, TUPLE *tuple /* destroyed */ ); /* delete n-tuple */ #define format_tuple _glp_mpl_format_tuple char *format_tuple ( MPL *mpl, int c, TUPLE *tuple /* not changed */ ); /* format n-tuple for displaying or printing */ /**********************************************************************/ /* * * ELEMENTAL SETS * * */ /**********************************************************************/ #if 2 + 2 == 5 struct ELEMSET /* see ARRAY */ { /* elemental set of n-tuples; formally it is a "value" assigned to members of model sets (like numbers and symbols, which are values assigned to members of model parameters); note that a simple model set is not an elemental set, it is 0-dimensional array, the only member of which (if it exists) is assigned an elemental set */ #endif #define create_elemset _glp_mpl_create_elemset ELEMSET *create_elemset(MPL *mpl, int dim); /* create elemental set */ #define find_tuple _glp_mpl_find_tuple MEMBER *find_tuple ( MPL *mpl, ELEMSET *set, /* not changed */ TUPLE *tuple /* not changed */ ); /* check if elemental set contains given n-tuple */ #define add_tuple _glp_mpl_add_tuple MEMBER *add_tuple ( MPL *mpl, ELEMSET *set, /* modified */ TUPLE *tuple /* destroyed */ ); /* add new n-tuple to elemental set */ #define check_then_add _glp_mpl_check_then_add MEMBER *check_then_add ( MPL *mpl, ELEMSET *set, /* modified */ TUPLE *tuple /* destroyed */ ); /* check and add new n-tuple to elemental set */ #define copy_elemset _glp_mpl_copy_elemset ELEMSET *copy_elemset ( MPL *mpl, ELEMSET *set /* not changed */ ); /* make copy of elemental set */ #define delete_elemset _glp_mpl_delete_elemset void delete_elemset ( MPL *mpl, ELEMSET *set /* destroyed */ ); /* delete elemental set */ #define arelset_size _glp_mpl_arelset_size int arelset_size(MPL *mpl, double t0, double tf, double dt); /* compute size of "arithmetic" elemental set */ #define arelset_member _glp_mpl_arelset_member double arelset_member(MPL *mpl, double t0, double tf, double dt, int j); /* compute member of "arithmetic" elemental set */ #define create_arelset _glp_mpl_create_arelset ELEMSET *create_arelset(MPL *mpl, double t0, double tf, double dt); /* create "arithmetic" elemental set */ #define set_union _glp_mpl_set_union ELEMSET *set_union ( MPL *mpl, ELEMSET *X, /* destroyed */ ELEMSET *Y /* destroyed */ ); /* union of two elemental sets */ #define set_diff _glp_mpl_set_diff ELEMSET *set_diff ( MPL *mpl, ELEMSET *X, /* destroyed */ ELEMSET *Y /* destroyed */ ); /* difference between two elemental sets */ #define set_symdiff _glp_mpl_set_symdiff ELEMSET *set_symdiff ( MPL *mpl, ELEMSET *X, /* destroyed */ ELEMSET *Y /* destroyed */ ); /* symmetric difference between two elemental sets */ #define set_inter _glp_mpl_set_inter ELEMSET *set_inter ( MPL *mpl, ELEMSET *X, /* destroyed */ ELEMSET *Y /* destroyed */ ); /* intersection of two elemental sets */ #define set_cross _glp_mpl_set_cross ELEMSET *set_cross ( MPL *mpl, ELEMSET *X, /* destroyed */ ELEMSET *Y /* destroyed */ ); /* cross (Cartesian) product of two elemental sets */ /**********************************************************************/ /* * * ELEMENTAL VARIABLES * * */ /**********************************************************************/ struct ELEMVAR { /* elemental variable; formally it is a "value" assigned to members of model variables (like numbers and symbols, which are values assigned to members of model parameters) */ int j; /* LP column number assigned to this elemental variable */ VARIABLE *var; /* model variable, which contains this elemental variable */ MEMBER *memb; /* array member, which is assigned this elemental variable */ double lbnd; /* lower bound */ double ubnd; /* upper bound */ double temp; /* working quantity used in operations on linear forms; normally it contains floating-point zero */ #if 1 /* 15/V-2010 */ int stat; double prim, dual; /* solution components provided by the solver */ #endif }; /**********************************************************************/ /* * * LINEAR FORMS * * */ /**********************************************************************/ struct FORMULA { /* term of linear form c * x, where c is a coefficient, x is an elemental variable; the linear form itself is the sum of terms and is associated with its first term; (note that the linear form may be empty that means the sum is equal to zero) */ double coef; /* coefficient at elemental variable or constant term */ ELEMVAR *var; /* reference to elemental variable; NULL means constant term */ FORMULA *next; /* the next term of linear form */ }; #define constant_term _glp_mpl_constant_term FORMULA *constant_term(MPL *mpl, double coef); /* create constant term */ #define single_variable _glp_mpl_single_variable FORMULA *single_variable ( MPL *mpl, ELEMVAR *var /* referenced */ ); /* create single variable */ #define copy_formula _glp_mpl_copy_formula FORMULA *copy_formula ( MPL *mpl, FORMULA *form /* not changed */ ); /* make copy of linear form */ #define delete_formula _glp_mpl_delete_formula void delete_formula ( MPL *mpl, FORMULA *form /* destroyed */ ); /* delete linear form */ #define linear_comb _glp_mpl_linear_comb FORMULA *linear_comb ( MPL *mpl, double a, FORMULA *fx, /* destroyed */ double b, FORMULA *fy /* destroyed */ ); /* linear combination of two linear forms */ #define remove_constant _glp_mpl_remove_constant FORMULA *remove_constant ( MPL *mpl, FORMULA *form, /* destroyed */ double *coef /* modified */ ); /* remove constant term from linear form */ #define reduce_terms _glp_mpl_reduce_terms FORMULA *reduce_terms ( MPL *mpl, FORMULA *form /* destroyed */ ); /* reduce identical terms in linear form */ /**********************************************************************/ /* * * ELEMENTAL CONSTRAINTS * * */ /**********************************************************************/ struct ELEMCON { /* elemental constraint; formally it is a "value" assigned to members of model constraints (like numbers or symbols, which are values assigned to members of model parameters) */ int i; /* LP row number assigned to this elemental constraint */ CONSTRAINT *con; /* model constraint, which contains this elemental constraint */ MEMBER *memb; /* array member, which is assigned this elemental constraint */ FORMULA *form; /* linear form */ double lbnd; /* lower bound */ double ubnd; /* upper bound */ #if 1 /* 15/V-2010 */ int stat; double prim, dual; /* solution components provided by the solver */ #endif }; /**********************************************************************/ /* * * GENERIC VALUES * * */ /**********************************************************************/ union VALUE { /* generic value, which can be assigned to object member or be a result of evaluation of expression */ /* indicator that specifies the particular type of generic value is stored in the corresponding array or pseudo-code descriptor and can be one of the following: A_NONE - no value A_NUMERIC - floating-point number A_SYMBOLIC - symbol A_LOGICAL - logical value A_TUPLE - n-tuple A_ELEMSET - elemental set A_ELEMVAR - elemental variable A_FORMULA - linear form A_ELEMCON - elemental constraint */ void *none; /* null */ double num; /* value */ SYMBOL *sym; /* value */ int bit; /* value */ TUPLE *tuple; /* value */ ELEMSET *set; /* value */ ELEMVAR *var; /* reference */ FORMULA *form; /* value */ ELEMCON *con; /* reference */ }; #define delete_value _glp_mpl_delete_value void delete_value ( MPL *mpl, int type, VALUE *value /* content destroyed */ ); /* delete generic value */ /**********************************************************************/ /* * * SYMBOLICALLY INDEXED ARRAYS * * */ /**********************************************************************/ struct ARRAY { /* multi-dimensional array, a set of members indexed over simple or compound sets of symbols; arrays are used to represent the contents of model objects (i.e. sets, parameters, variables, constraints, and objectives); arrays also are used as "values" that are assigned to members of set objects, in which case the array itself represents an elemental set */ int type; /* type of generic values assigned to the array members: A_NONE - none (members have no assigned values) A_NUMERIC - floating-point numbers A_SYMBOLIC - symbols A_ELEMSET - elemental sets A_ELEMVAR - elemental variables A_ELEMCON - elemental constraints */ int dim; /* dimension of the array that determines number of components in n-tuples for all members of the array, dim >= 0; dim = 0 means the array is 0-dimensional */ int size; /* size of the array, i.e. number of its members */ MEMBER *head; /* the first array member; NULL means the array is empty */ MEMBER *tail; /* the last array member; NULL means the array is empty */ AVL *tree; /* the search tree intended to find array members for logarithmic time; NULL means the search tree doesn't exist */ ARRAY *prev; /* the previous array in the translator database */ ARRAY *next; /* the next array in the translator database */ }; struct MEMBER { /* array member */ TUPLE *tuple; /* n-tuple, which identifies the member; number of its components is the same for all members within the array and determined by the array dimension; duplicate members are not allowed */ MEMBER *next; /* the next array member */ VALUE value; /* generic value assigned to the member */ }; #define create_array _glp_mpl_create_array ARRAY *create_array(MPL *mpl, int type, int dim); /* create array */ #define find_member _glp_mpl_find_member MEMBER *find_member ( MPL *mpl, ARRAY *array, /* not changed */ TUPLE *tuple /* not changed */ ); /* find array member with given n-tuple */ #define add_member _glp_mpl_add_member MEMBER *add_member ( MPL *mpl, ARRAY *array, /* modified */ TUPLE *tuple /* destroyed */ ); /* add new member to array */ #define delete_array _glp_mpl_delete_array void delete_array ( MPL *mpl, ARRAY *array /* destroyed */ ); /* delete array */ /**********************************************************************/ /* * * DOMAINS AND DUMMY INDICES * * */ /**********************************************************************/ struct DOMAIN { /* domain (a simple or compound set); syntactically domain looks like '{ i in I, (j,k) in S, t in T : }'; domains are used to define sets, over which model objects are indexed, and also as constituents of iterated operators */ DOMAIN_BLOCK *list; /* linked list of domain blocks (in the example above such blocks are 'i in I', '(j,k) in S', and 't in T'); this list cannot be empty */ CODE *code; /* pseudo-code for computing the logical predicate, which follows the colon; NULL means no predicate is specified */ }; struct DOMAIN_BLOCK { /* domain block; syntactically domain blocks look like 'i in I', '(j,k) in S', and 't in T' in the example above (in the sequel sets like I, S, and T are called basic sets) */ DOMAIN_SLOT *list; /* linked list of domain slots (i.e. indexing positions); number of slots in this list is the same as dimension of n-tuples in the basic set; this list cannot be empty */ CODE *code; /* pseudo-code for computing basic set; cannot be NULL */ TUPLE *backup; /* if this n-tuple is not empty, current values of dummy indices in the domain block are the same as components of this n-tuple (note that this n-tuple may have larger dimension than number of dummy indices in this block, in which case extra components are ignored); this n-tuple is used to restore former values of dummy indices, if they were changed due to recursive calls to the domain block */ DOMAIN_BLOCK *next; /* the next block in the same domain */ }; struct DOMAIN_SLOT { /* domain slot; it specifies an individual indexing position and defines the corresponding dummy index */ char *name; /* symbolic name of the dummy index; null pointer means the dummy index is not explicitly specified */ CODE *code; /* pseudo-code for computing symbolic value, at which the dummy index is bound; NULL means the dummy index is free within the domain scope */ SYMBOL *value; /* current value assigned to the dummy index; NULL means no value is assigned at the moment */ CODE *list; /* linked list of pseudo-codes with operation O_INDEX referring to this slot; this linked list is used to invalidate resultant values of the operation, which depend on this dummy index */ DOMAIN_SLOT *next; /* the next slot in the same domain block */ }; #define assign_dummy_index _glp_mpl_assign_dummy_index void assign_dummy_index ( MPL *mpl, DOMAIN_SLOT *slot, /* modified */ SYMBOL *value /* not changed */ ); /* assign new value to dummy index */ #define update_dummy_indices _glp_mpl_update_dummy_indices void update_dummy_indices ( MPL *mpl, DOMAIN_BLOCK *block /* not changed */ ); /* update current values of dummy indices */ #define enter_domain_block _glp_mpl_enter_domain_block int enter_domain_block ( MPL *mpl, DOMAIN_BLOCK *block, /* not changed */ TUPLE *tuple, /* not changed */ void *info, void (*func)(MPL *mpl, void *info) ); /* enter domain block */ #define eval_within_domain _glp_mpl_eval_within_domain int eval_within_domain ( MPL *mpl, DOMAIN *domain, /* not changed */ TUPLE *tuple, /* not changed */ void *info, void (*func)(MPL *mpl, void *info) ); /* perform evaluation within domain scope */ #define loop_within_domain _glp_mpl_loop_within_domain void loop_within_domain ( MPL *mpl, DOMAIN *domain, /* not changed */ void *info, int (*func)(MPL *mpl, void *info) ); /* perform iterations within domain scope */ #define out_of_domain _glp_mpl_out_of_domain void out_of_domain ( MPL *mpl, char *name, /* not changed */ TUPLE *tuple /* not changed */ ); /* raise domain exception */ #define get_domain_tuple _glp_mpl_get_domain_tuple TUPLE *get_domain_tuple ( MPL *mpl, DOMAIN *domain /* not changed */ ); /* obtain current n-tuple from domain */ #define clean_domain _glp_mpl_clean_domain void clean_domain(MPL *mpl, DOMAIN *domain); /* clean domain */ /**********************************************************************/ /* * * MODEL SETS * * */ /**********************************************************************/ struct SET { /* model set */ char *name; /* symbolic name; cannot be NULL */ char *alias; /* alias; NULL means alias is not specified */ int dim; /* aka arity */ /* dimension (number of subscripts); dim = 0 means 0-dimensional (unsubscripted) set, dim > 0 means set of sets */ DOMAIN *domain; /* subscript domain; NULL for 0-dimensional set */ int dimen; /* dimension of n-tuples, which members of this set consist of (note that the model set itself is an array of elemental sets, which are its members; so, don't confuse this dimension with dimension of the model set); always non-zero */ WITHIN *within; /* list of supersets, which restrict each member of the set to be in every superset from this list; this list can be empty */ CODE *assign; /* pseudo-code for computing assigned value; can be NULL */ CODE *option; /* pseudo-code for computing default value; can be NULL */ GADGET *gadget; /* plain set used to initialize the array of sets; can be NULL */ int data; /* data status flag: 0 - no data are provided in the data section 1 - data are provided, but not checked yet 2 - data are provided and have been checked */ ARRAY *array; /* array of members, which are assigned elemental sets */ }; struct WITHIN { /* restricting superset list entry */ CODE *code; /* pseudo-code for computing the superset; cannot be NULL */ WITHIN *next; /* the next entry for the same set or parameter */ }; struct GADGET { /* plain set used to initialize the array of sets with data */ SET *set; /* pointer to plain set; cannot be NULL */ int ind[20]; /* ind[dim+dimen]; */ /* permutation of integers 1, 2, ..., dim+dimen */ }; #define check_elem_set _glp_mpl_check_elem_set void check_elem_set ( MPL *mpl, SET *set, /* not changed */ TUPLE *tuple, /* not changed */ ELEMSET *refer /* not changed */ ); /* check elemental set assigned to set member */ #define take_member_set _glp_mpl_take_member_set ELEMSET *take_member_set /* returns reference, not value */ ( MPL *mpl, SET *set, /* not changed */ TUPLE *tuple /* not changed */ ); /* obtain elemental set assigned to set member */ #define eval_member_set _glp_mpl_eval_member_set ELEMSET *eval_member_set /* returns reference, not value */ ( MPL *mpl, SET *set, /* not changed */ TUPLE *tuple /* not changed */ ); /* evaluate elemental set assigned to set member */ #define eval_whole_set _glp_mpl_eval_whole_set void eval_whole_set(MPL *mpl, SET *set); /* evaluate model set over entire domain */ #define clean_set _glp_mpl_clean_set void clean_set(MPL *mpl, SET *set); /* clean model set */ /**********************************************************************/ /* * * MODEL PARAMETERS * * */ /**********************************************************************/ struct PARAMETER { /* model parameter */ char *name; /* symbolic name; cannot be NULL */ char *alias; /* alias; NULL means alias is not specified */ int dim; /* aka arity */ /* dimension (number of subscripts); dim = 0 means 0-dimensional (unsubscripted) parameter */ DOMAIN *domain; /* subscript domain; NULL for 0-dimensional parameter */ int type; /* parameter type: A_NUMERIC - numeric A_INTEGER - integer A_BINARY - binary A_SYMBOLIC - symbolic */ CONDITION *cond; /* list of conditions, which restrict each parameter member to satisfy to every condition from this list; this list is used only for numeric parameters and can be empty */ WITHIN *in; /* list of supersets, which restrict each parameter member to be in every superset from this list; this list is used only for symbolic parameters and can be empty */ CODE *assign; /* pseudo-code for computing assigned value; can be NULL */ CODE *option; /* pseudo-code for computing default value; can be NULL */ int data; /* data status flag: 0 - no data are provided in the data section 1 - data are provided, but not checked yet 2 - data are provided and have been checked */ SYMBOL *defval; /* default value provided in the data section; can be NULL */ ARRAY *array; /* array of members, which are assigned numbers or symbols */ }; struct CONDITION { /* restricting condition list entry */ int rho; /* flag that specifies the form of the condition: O_LT - less than O_LE - less than or equal to O_EQ - equal to O_GE - greater than or equal to O_GT - greater than O_NE - not equal to */ CODE *code; /* pseudo-code for computing the reference value */ CONDITION *next; /* the next entry for the same parameter */ }; #define check_value_num _glp_mpl_check_value_num void check_value_num ( MPL *mpl, PARAMETER *par, /* not changed */ TUPLE *tuple, /* not changed */ double value ); /* check numeric value assigned to parameter member */ #define take_member_num _glp_mpl_take_member_num double take_member_num ( MPL *mpl, PARAMETER *par, /* not changed */ TUPLE *tuple /* not changed */ ); /* obtain numeric value assigned to parameter member */ #define eval_member_num _glp_mpl_eval_member_num double eval_member_num ( MPL *mpl, PARAMETER *par, /* not changed */ TUPLE *tuple /* not changed */ ); /* evaluate numeric value assigned to parameter member */ #define check_value_sym _glp_mpl_check_value_sym void check_value_sym ( MPL *mpl, PARAMETER *par, /* not changed */ TUPLE *tuple, /* not changed */ SYMBOL *value /* not changed */ ); /* check symbolic value assigned to parameter member */ #define take_member_sym _glp_mpl_take_member_sym SYMBOL *take_member_sym /* returns value, not reference */ ( MPL *mpl, PARAMETER *par, /* not changed */ TUPLE *tuple /* not changed */ ); /* obtain symbolic value assigned to parameter member */ #define eval_member_sym _glp_mpl_eval_member_sym SYMBOL *eval_member_sym /* returns value, not reference */ ( MPL *mpl, PARAMETER *par, /* not changed */ TUPLE *tuple /* not changed */ ); /* evaluate symbolic value assigned to parameter member */ #define eval_whole_par _glp_mpl_eval_whole_par void eval_whole_par(MPL *mpl, PARAMETER *par); /* evaluate model parameter over entire domain */ #define clean_parameter _glp_mpl_clean_parameter void clean_parameter(MPL *mpl, PARAMETER *par); /* clean model parameter */ /**********************************************************************/ /* * * MODEL VARIABLES * * */ /**********************************************************************/ struct VARIABLE { /* model variable */ char *name; /* symbolic name; cannot be NULL */ char *alias; /* alias; NULL means alias is not specified */ int dim; /* aka arity */ /* dimension (number of subscripts); dim = 0 means 0-dimensional (unsubscripted) variable */ DOMAIN *domain; /* subscript domain; NULL for 0-dimensional variable */ int type; /* variable type: A_NUMERIC - continuous A_INTEGER - integer A_BINARY - binary */ CODE *lbnd; /* pseudo-code for computing lower bound; NULL means lower bound is not specified */ CODE *ubnd; /* pseudo-code for computing upper bound; NULL means upper bound is not specified */ /* if both the pointers lbnd and ubnd refer to the same code, the variable is fixed at the corresponding value */ ARRAY *array; /* array of members, which are assigned elemental variables */ }; #define take_member_var _glp_mpl_take_member_var ELEMVAR *take_member_var /* returns reference */ ( MPL *mpl, VARIABLE *var, /* not changed */ TUPLE *tuple /* not changed */ ); /* obtain reference to elemental variable */ #define eval_member_var _glp_mpl_eval_member_var ELEMVAR *eval_member_var /* returns reference */ ( MPL *mpl, VARIABLE *var, /* not changed */ TUPLE *tuple /* not changed */ ); /* evaluate reference to elemental variable */ #define eval_whole_var _glp_mpl_eval_whole_var void eval_whole_var(MPL *mpl, VARIABLE *var); /* evaluate model variable over entire domain */ #define clean_variable _glp_mpl_clean_variable void clean_variable(MPL *mpl, VARIABLE *var); /* clean model variable */ /**********************************************************************/ /* * * MODEL CONSTRAINTS AND OBJECTIVES * * */ /**********************************************************************/ struct CONSTRAINT { /* model constraint or objective */ char *name; /* symbolic name; cannot be NULL */ char *alias; /* alias; NULL means alias is not specified */ int dim; /* aka arity */ /* dimension (number of subscripts); dim = 0 means 0-dimensional (unsubscripted) constraint */ DOMAIN *domain; /* subscript domain; NULL for 0-dimensional constraint */ int type; /* constraint type: A_CONSTRAINT - constraint A_MINIMIZE - objective (minimization) A_MAXIMIZE - objective (maximization) */ CODE *code; /* pseudo-code for computing main linear form; cannot be NULL */ CODE *lbnd; /* pseudo-code for computing lower bound; NULL means lower bound is not specified */ CODE *ubnd; /* pseudo-code for computing upper bound; NULL means upper bound is not specified */ /* if both the pointers lbnd and ubnd refer to the same code, the constraint has the form of equation */ ARRAY *array; /* array of members, which are assigned elemental constraints */ }; #define take_member_con _glp_mpl_take_member_con ELEMCON *take_member_con /* returns reference */ ( MPL *mpl, CONSTRAINT *con, /* not changed */ TUPLE *tuple /* not changed */ ); /* obtain reference to elemental constraint */ #define eval_member_con _glp_mpl_eval_member_con ELEMCON *eval_member_con /* returns reference */ ( MPL *mpl, CONSTRAINT *con, /* not changed */ TUPLE *tuple /* not changed */ ); /* evaluate reference to elemental constraint */ #define eval_whole_con _glp_mpl_eval_whole_con void eval_whole_con(MPL *mpl, CONSTRAINT *con); /* evaluate model constraint over entire domain */ #define clean_constraint _glp_mpl_clean_constraint void clean_constraint(MPL *mpl, CONSTRAINT *con); /* clean model constraint */ /**********************************************************************/ /* * * DATA TABLES * * */ /**********************************************************************/ struct TABLE { /* data table */ char *name; /* symbolic name; cannot be NULL */ char *alias; /* alias; NULL means alias is not specified */ int type; /* table type: A_INPUT - input table A_OUTPUT - output table */ TABARG *arg; /* argument list; cannot be empty */ union { struct { SET *set; /* input set; NULL means the set is not specified */ TABFLD *fld; /* field list; cannot be empty */ TABIN *list; /* input list; can be empty */ } in; struct { DOMAIN *domain; /* subscript domain; cannot be NULL */ TABOUT *list; /* output list; cannot be empty */ } out; } u; }; struct TABARG { /* table argument list entry */ CODE *code; /* pseudo-code for computing the argument */ TABARG *next; /* next entry for the same table */ }; struct TABFLD { /* table field list entry */ char *name; /* field name; cannot be NULL */ TABFLD *next; /* next entry for the same table */ }; struct TABIN { /* table input list entry */ PARAMETER *par; /* parameter to be read; cannot be NULL */ char *name; /* column name; cannot be NULL */ TABIN *next; /* next entry for the same table */ }; struct TABOUT { /* table output list entry */ CODE *code; /* pseudo-code for computing the value to be written */ char *name; /* column name; cannot be NULL */ TABOUT *next; /* next entry for the same table */ }; struct TABDCA { /* table driver communication area */ int id; /* driver identifier (set by mpl_tab_drv_open) */ void *link; /* driver link pointer (set by mpl_tab_drv_open) */ int na; /* number of arguments */ char **arg; /* char *arg[1+ns]; */ /* arg[k], 1 <= k <= ns, is pointer to k-th argument */ int nf; /* number of fields */ char **name; /* char *name[1+nc]; */ /* name[k], 1 <= k <= nc, is name of k-th field */ int *type; /* int type[1+nc]; */ /* type[k], 1 <= k <= nc, is type of k-th field: '?' - value not assigned 'N' - number 'S' - character string */ double *num; /* double num[1+nc]; */ /* num[k], 1 <= k <= nc, is numeric value of k-th field */ char **str; /* str[k], 1 <= k <= nc, is string value of k-th field */ }; #define mpl_tab_num_args _glp_mpl_tab_num_args int mpl_tab_num_args(TABDCA *dca); #define mpl_tab_get_arg _glp_mpl_tab_get_arg const char *mpl_tab_get_arg(TABDCA *dca, int k); #define mpl_tab_num_flds _glp_mpl_tab_num_flds int mpl_tab_num_flds(TABDCA *dca); #define mpl_tab_get_name _glp_mpl_tab_get_name const char *mpl_tab_get_name(TABDCA *dca, int k); #define mpl_tab_get_type _glp_mpl_tab_get_type int mpl_tab_get_type(TABDCA *dca, int k); #define mpl_tab_get_num _glp_mpl_tab_get_num double mpl_tab_get_num(TABDCA *dca, int k); #define mpl_tab_get_str _glp_mpl_tab_get_str const char *mpl_tab_get_str(TABDCA *dca, int k); #define mpl_tab_set_num _glp_mpl_tab_set_num void mpl_tab_set_num(TABDCA *dca, int k, double num); #define mpl_tab_set_str _glp_mpl_tab_set_str void mpl_tab_set_str(TABDCA *dca, int k, const char *str); #define mpl_tab_drv_open _glp_mpl_tab_drv_open void mpl_tab_drv_open(MPL *mpl, int mode); #define mpl_tab_drv_read _glp_mpl_tab_drv_read int mpl_tab_drv_read(MPL *mpl); #define mpl_tab_drv_write _glp_mpl_tab_drv_write void mpl_tab_drv_write(MPL *mpl); #define mpl_tab_drv_close _glp_mpl_tab_drv_close void mpl_tab_drv_close(MPL *mpl); /**********************************************************************/ /* * * PSEUDO-CODE * * */ /**********************************************************************/ union OPERANDS { /* operands that participate in pseudo-code operation (choice of particular operands depends on the operation code) */ /*--------------------------------------------------------------*/ double num; /* O_NUMBER */ /* floaing-point number to be taken */ /*--------------------------------------------------------------*/ char *str; /* O_STRING */ /* character string to be taken */ /*--------------------------------------------------------------*/ struct /* O_INDEX */ { DOMAIN_SLOT *slot; /* domain slot, which contains dummy index to be taken */ CODE *next; /* the next pseudo-code with op = O_INDEX, which refers to the same slot as this one; pointer to the beginning of this list is stored in the corresponding domain slot */ } index; /*--------------------------------------------------------------*/ struct /* O_MEMNUM, O_MEMSYM */ { PARAMETER *par; /* model parameter, which contains member to be taken */ ARG_LIST *list; /* list of subscripts; NULL for 0-dimensional parameter */ } par; /*--------------------------------------------------------------*/ struct /* O_MEMSET */ { SET *set; /* model set, which contains member to be taken */ ARG_LIST *list; /* list of subscripts; NULL for 0-dimensional set */ } set; /*--------------------------------------------------------------*/ struct /* O_MEMVAR */ { VARIABLE *var; /* model variable, which contains member to be taken */ ARG_LIST *list; /* list of subscripts; NULL for 0-dimensional variable */ #if 1 /* 15/V-2010 */ int suff; /* suffix specified: */ #define DOT_NONE 0x00 /* none (means variable itself) */ #define DOT_LB 0x01 /* .lb (lower bound) */ #define DOT_UB 0x02 /* .ub (upper bound) */ #define DOT_STATUS 0x03 /* .status (status) */ #define DOT_VAL 0x04 /* .val (primal value) */ #define DOT_DUAL 0x05 /* .dual (dual value) */ #endif } var; #if 1 /* 15/V-2010 */ /*--------------------------------------------------------------*/ struct /* O_MEMCON */ { CONSTRAINT *con; /* model constraint, which contains member to be taken */ ARG_LIST *list; /* list of subscripys; NULL for 0-dimensional constraint */ int suff; /* suffix specified (see O_MEMVAR above) */ } con; #endif /*--------------------------------------------------------------*/ ARG_LIST *list; /* O_TUPLE, O_MAKE, n-ary operations */ /* list of operands */ /*--------------------------------------------------------------*/ DOMAIN_BLOCK *slice; /* O_SLICE */ /* domain block, which specifies slice (i.e. n-tuple that contains free dummy indices); this operation is never evaluated */ /*--------------------------------------------------------------*/ struct /* unary, binary, ternary operations */ { CODE *x; /* pseudo-code for computing first operand */ CODE *y; /* pseudo-code for computing second operand */ CODE *z; /* pseudo-code for computing third operand */ } arg; /*--------------------------------------------------------------*/ struct /* iterated operations */ { DOMAIN *domain; /* domain, over which the operation is performed */ CODE *x; /* pseudo-code for computing "integrand" */ } loop; /*--------------------------------------------------------------*/ }; struct ARG_LIST { /* operands list entry */ CODE *x; /* pseudo-code for computing operand */ ARG_LIST *next; /* the next operand of the same operation */ }; struct CODE { /* pseudo-code (internal form of expressions) */ int op; /* operation code: */ #define O_NUMBER 301 /* take floating-point number */ #define O_STRING 302 /* take character string */ #define O_INDEX 303 /* take dummy index */ #define O_MEMNUM 304 /* take member of numeric parameter */ #define O_MEMSYM 305 /* take member of symbolic parameter */ #define O_MEMSET 306 /* take member of set */ #define O_MEMVAR 307 /* take member of variable */ #define O_MEMCON 308 /* take member of constraint */ #define O_TUPLE 309 /* make n-tuple */ #define O_MAKE 310 /* make elemental set of n-tuples */ #define O_SLICE 311 /* define domain block (dummy op) */ /* 0-ary operations --------------------*/ #define O_IRAND224 312 /* pseudo-random in [0, 2^24-1] */ #define O_UNIFORM01 313 /* pseudo-random in [0, 1) */ #define O_NORMAL01 314 /* gaussian random, mu = 0, sigma = 1 */ #define O_GMTIME 315 /* current calendar time (UTC) */ /* unary operations --------------------*/ #define O_CVTNUM 316 /* conversion to numeric */ #define O_CVTSYM 317 /* conversion to symbolic */ #define O_CVTLOG 318 /* conversion to logical */ #define O_CVTTUP 319 /* conversion to 1-tuple */ #define O_CVTLFM 320 /* conversion to linear form */ #define O_PLUS 321 /* unary plus */ #define O_MINUS 322 /* unary minus */ #define O_NOT 323 /* negation (logical "not") */ #define O_ABS 324 /* absolute value */ #define O_CEIL 325 /* round upward ("ceiling of x") */ #define O_FLOOR 326 /* round downward ("floor of x") */ #define O_EXP 327 /* base-e exponential */ #define O_LOG 328 /* natural logarithm */ #define O_LOG10 329 /* common (decimal) logarithm */ #define O_SQRT 330 /* square root */ #define O_SIN 331 /* trigonometric sine */ #define O_COS 332 /* trigonometric cosine */ #define O_ATAN 333 /* trigonometric arctangent */ #define O_ROUND 334 /* round to nearest integer */ #define O_TRUNC 335 /* truncate to nearest integer */ #define O_CARD 336 /* cardinality of set */ #define O_LENGTH 337 /* length of symbolic value */ /* binary operations -------------------*/ #define O_ADD 338 /* addition */ #define O_SUB 339 /* subtraction */ #define O_LESS 340 /* non-negative subtraction */ #define O_MUL 341 /* multiplication */ #define O_DIV 342 /* division */ #define O_IDIV 343 /* quotient of exact division */ #define O_MOD 344 /* remainder of exact division */ #define O_POWER 345 /* exponentiation (raise to power) */ #define O_ATAN2 346 /* trigonometric arctangent */ #define O_ROUND2 347 /* round to n fractional digits */ #define O_TRUNC2 348 /* truncate to n fractional digits */ #define O_UNIFORM 349 /* pseudo-random in [a, b) */ #define O_NORMAL 350 /* gaussian random, given mu and sigma */ #define O_CONCAT 351 /* concatenation */ #define O_LT 352 /* comparison on 'less than' */ #define O_LE 353 /* comparison on 'not greater than' */ #define O_EQ 354 /* comparison on 'equal to' */ #define O_GE 355 /* comparison on 'not less than' */ #define O_GT 356 /* comparison on 'greater than' */ #define O_NE 357 /* comparison on 'not equal to' */ #define O_AND 358 /* conjunction (logical "and") */ #define O_OR 359 /* disjunction (logical "or") */ #define O_UNION 360 /* union */ #define O_DIFF 361 /* difference */ #define O_SYMDIFF 362 /* symmetric difference */ #define O_INTER 363 /* intersection */ #define O_CROSS 364 /* cross (Cartesian) product */ #define O_IN 365 /* test on 'x in Y' */ #define O_NOTIN 366 /* test on 'x not in Y' */ #define O_WITHIN 367 /* test on 'X within Y' */ #define O_NOTWITHIN 368 /* test on 'X not within Y' */ #define O_SUBSTR 369 /* substring */ #define O_STR2TIME 370 /* convert string to time */ #define O_TIME2STR 371 /* convert time to string */ /* ternary operations ------------------*/ #define O_DOTS 372 /* build "arithmetic" set */ #define O_FORK 373 /* if-then-else */ #define O_SUBSTR3 374 /* substring */ /* n-ary operations --------------------*/ #define O_MIN 375 /* minimal value (n-ary) */ #define O_MAX 376 /* maximal value (n-ary) */ /* iterated operations -----------------*/ #define O_SUM 377 /* summation */ #define O_PROD 378 /* multiplication */ #define O_MINIMUM 379 /* minimum */ #define O_MAXIMUM 380 /* maximum */ #define O_FORALL 381 /* conjunction (A-quantification) */ #define O_EXISTS 382 /* disjunction (E-quantification) */ #define O_SETOF 383 /* compute elemental set */ #define O_BUILD 384 /* build elemental set */ OPERANDS arg; /* operands that participate in the operation */ int type; /* type of the resultant value: A_NUMERIC - numeric A_SYMBOLIC - symbolic A_LOGICAL - logical A_TUPLE - n-tuple A_ELEMSET - elemental set A_FORMULA - linear form */ int dim; /* dimension of the resultant value; for A_TUPLE and A_ELEMSET it is the dimension of the corresponding n-tuple(s) and cannot be zero; for other resultant types it is always zero */ CODE *up; /* parent pseudo-code, which refers to this pseudo-code as to its operand; NULL means this pseudo-code has no parent and defines an expression, which is not contained in another expression */ int vflag; /* volatile flag; being set this flag means that this operation has a side effect; for primary expressions this flag is set directly by corresponding parsing routines (for example, if primary expression is a reference to a function that generates pseudo-random numbers); in other cases this flag is inherited from operands */ int valid; /* if this flag is set, the resultant value, which is a temporary result of evaluating this operation on particular values of operands, is valid; if this flag is clear, the resultant value doesn't exist and therefore not valid; having been evaluated the resultant value is stored here and not destroyed until the dummy indices, which this value depends on, have been changed (and if it doesn't depend on dummy indices at all, it is never destroyed); thus, if the resultant value is valid, evaluating routine can immediately take its copy not computing the result from scratch; this mechanism is similar to moving invariants out of loops and allows improving efficiency at the expense of some extra memory needed to keep temporary results */ /* however, if the volatile flag (see above) is set, even if the resultant value is valid, evaluating routine computes it as if it were not valid, i.e. caching is not used in this case */ VALUE value; /* resultant value in generic format */ }; #define eval_numeric _glp_mpl_eval_numeric double eval_numeric(MPL *mpl, CODE *code); /* evaluate pseudo-code to determine numeric value */ #define eval_symbolic _glp_mpl_eval_symbolic SYMBOL *eval_symbolic(MPL *mpl, CODE *code); /* evaluate pseudo-code to determine symbolic value */ #define eval_logical _glp_mpl_eval_logical int eval_logical(MPL *mpl, CODE *code); /* evaluate pseudo-code to determine logical value */ #define eval_tuple _glp_mpl_eval_tuple TUPLE *eval_tuple(MPL *mpl, CODE *code); /* evaluate pseudo-code to construct n-tuple */ #define eval_elemset _glp_mpl_eval_elemset ELEMSET *eval_elemset(MPL *mpl, CODE *code); /* evaluate pseudo-code to construct elemental set */ #define is_member _glp_mpl_is_member int is_member(MPL *mpl, CODE *code, TUPLE *tuple); /* check if n-tuple is in set specified by pseudo-code */ #define eval_formula _glp_mpl_eval_formula FORMULA *eval_formula(MPL *mpl, CODE *code); /* evaluate pseudo-code to construct linear form */ #define clean_code _glp_mpl_clean_code void clean_code(MPL *mpl, CODE *code); /* clean pseudo-code */ /**********************************************************************/ /* * * MODEL STATEMENTS * * */ /**********************************************************************/ struct CHECK { /* check statement */ DOMAIN *domain; /* subscript domain; NULL means domain is not used */ CODE *code; /* code for computing the predicate to be checked */ }; struct DISPLAY { /* display statement */ DOMAIN *domain; /* subscript domain; NULL means domain is not used */ DISPLAY1 *list; /* display list; cannot be empty */ }; struct DISPLAY1 { /* display list entry */ int type; /* item type: A_INDEX - dummy index A_SET - model set A_PARAMETER - model parameter A_VARIABLE - model variable A_CONSTRAINT - model constraint/objective A_EXPRESSION - expression */ union { DOMAIN_SLOT *slot; SET *set; PARAMETER *par; VARIABLE *var; CONSTRAINT *con; CODE *code; } u; /* item to be displayed */ #if 0 /* 15/V-2010 */ ARG_LIST *list; /* optional subscript list (for constraint/objective only) */ #endif DISPLAY1 *next; /* the next entry for the same statement */ }; struct PRINTF { /* printf statement */ DOMAIN *domain; /* subscript domain; NULL means domain is not used */ CODE *fmt; /* pseudo-code for computing format string */ PRINTF1 *list; /* printf list; can be empty */ CODE *fname; /* pseudo-code for computing filename to redirect the output; NULL means the output goes to stdout */ int app; /* if this flag is set, the output is appended */ }; struct PRINTF1 { /* printf list entry */ CODE *code; /* pseudo-code for computing value to be printed */ PRINTF1 *next; /* the next entry for the same statement */ }; struct FOR { /* for statement */ DOMAIN *domain; /* subscript domain; cannot be NULL */ STATEMENT *list; /* linked list of model statements within this for statement in the original order */ }; struct STATEMENT { /* model statement */ int line; /* number of source text line, where statement begins */ int type; /* statement type: A_SET - set statement A_PARAMETER - parameter statement A_VARIABLE - variable statement A_CONSTRAINT - constraint/objective statement A_TABLE - table statement A_SOLVE - solve statement A_CHECK - check statement A_DISPLAY - display statement A_PRINTF - printf statement A_FOR - for statement */ union { SET *set; PARAMETER *par; VARIABLE *var; CONSTRAINT *con; TABLE *tab; void *slv; /* currently not used (set to NULL) */ CHECK *chk; DISPLAY *dpy; PRINTF *prt; FOR *fur; } u; /* specific part of statement */ STATEMENT *next; /* the next statement; in this list statements follow in the same order as they appear in the model section */ }; #define execute_table _glp_mpl_execute_table void execute_table(MPL *mpl, TABLE *tab); /* execute table statement */ #define free_dca _glp_mpl_free_dca void free_dca(MPL *mpl); /* free table driver communucation area */ #define clean_table _glp_mpl_clean_table void clean_table(MPL *mpl, TABLE *tab); /* clean table statement */ #define execute_check _glp_mpl_execute_check void execute_check(MPL *mpl, CHECK *chk); /* execute check statement */ #define clean_check _glp_mpl_clean_check void clean_check(MPL *mpl, CHECK *chk); /* clean check statement */ #define execute_display _glp_mpl_execute_display void execute_display(MPL *mpl, DISPLAY *dpy); /* execute display statement */ #define clean_display _glp_mpl_clean_display void clean_display(MPL *mpl, DISPLAY *dpy); /* clean display statement */ #define execute_printf _glp_mpl_execute_printf void execute_printf(MPL *mpl, PRINTF *prt); /* execute printf statement */ #define clean_printf _glp_mpl_clean_printf void clean_printf(MPL *mpl, PRINTF *prt); /* clean printf statement */ #define execute_for _glp_mpl_execute_for void execute_for(MPL *mpl, FOR *fur); /* execute for statement */ #define clean_for _glp_mpl_clean_for void clean_for(MPL *mpl, FOR *fur); /* clean for statement */ #define execute_statement _glp_mpl_execute_statement void execute_statement(MPL *mpl, STATEMENT *stmt); /* execute specified model statement */ #define clean_statement _glp_mpl_clean_statement void clean_statement(MPL *mpl, STATEMENT *stmt); /* clean specified model statement */ /**********************************************************************/ /* * * GENERATING AND POSTSOLVING MODEL * * */ /**********************************************************************/ #define alloc_content _glp_mpl_alloc_content void alloc_content(MPL *mpl); /* allocate content arrays for all model objects */ #define generate_model _glp_mpl_generate_model void generate_model(MPL *mpl); /* generate model */ #define build_problem _glp_mpl_build_problem void build_problem(MPL *mpl); /* build problem instance */ #define postsolve_model _glp_mpl_postsolve_model void postsolve_model(MPL *mpl); /* postsolve model */ #define clean_model _glp_mpl_clean_model void clean_model(MPL *mpl); /* clean model content */ /**********************************************************************/ /* * * INPUT/OUTPUT * * */ /**********************************************************************/ #define open_input _glp_mpl_open_input void open_input(MPL *mpl, char *file); /* open input text file */ #define read_char _glp_mpl_read_char int read_char(MPL *mpl); /* read next character from input text file */ #define close_input _glp_mpl_close_input void close_input(MPL *mpl); /* close input text file */ #define open_output _glp_mpl_open_output void open_output(MPL *mpl, char *file); /* open output text file */ #define write_char _glp_mpl_write_char void write_char(MPL *mpl, int c); /* write next character to output text file */ #define write_text _glp_mpl_write_text void write_text(MPL *mpl, char *fmt, ...); /* format and write text to output text file */ #define flush_output _glp_mpl_flush_output void flush_output(MPL *mpl); /* finalize writing data to output text file */ /**********************************************************************/ /* * * SOLVER INTERFACE * * */ /**********************************************************************/ #define MPL_FR 401 /* free (unbounded) */ #define MPL_LO 402 /* lower bound */ #define MPL_UP 403 /* upper bound */ #define MPL_DB 404 /* both lower and upper bounds */ #define MPL_FX 405 /* fixed */ #define MPL_ST 411 /* constraint */ #define MPL_MIN 412 /* objective (minimization) */ #define MPL_MAX 413 /* objective (maximization) */ #define MPL_NUM 421 /* continuous */ #define MPL_INT 422 /* integer */ #define MPL_BIN 423 /* binary */ #define error _glp_mpl_error void error(MPL *mpl, char *fmt, ...); /* print error message and terminate model processing */ #define warning _glp_mpl_warning void warning(MPL *mpl, char *fmt, ...); /* print warning message and continue model processing */ #define mpl_initialize _glp_mpl_initialize MPL *mpl_initialize(void); /* create and initialize translator database */ #define mpl_read_model _glp_mpl_read_model int mpl_read_model(MPL *mpl, char *file, int skip_data); /* read model section and optional data section */ #define mpl_read_data _glp_mpl_read_data int mpl_read_data(MPL *mpl, char *file); /* read data section */ #define mpl_generate _glp_mpl_generate int mpl_generate(MPL *mpl, char *file); /* generate model */ #define mpl_get_prob_name _glp_mpl_get_prob_name char *mpl_get_prob_name(MPL *mpl); /* obtain problem (model) name */ #define mpl_get_num_rows _glp_mpl_get_num_rows int mpl_get_num_rows(MPL *mpl); /* determine number of rows */ #define mpl_get_num_cols _glp_mpl_get_num_cols int mpl_get_num_cols(MPL *mpl); /* determine number of columns */ #define mpl_get_row_name _glp_mpl_get_row_name char *mpl_get_row_name(MPL *mpl, int i); /* obtain row name */ #define mpl_get_row_kind _glp_mpl_get_row_kind int mpl_get_row_kind(MPL *mpl, int i); /* determine row kind */ #define mpl_get_row_bnds _glp_mpl_get_row_bnds int mpl_get_row_bnds(MPL *mpl, int i, double *lb, double *ub); /* obtain row bounds */ #define mpl_get_mat_row _glp_mpl_get_mat_row int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[]); /* obtain row of the constraint matrix */ #define mpl_get_row_c0 _glp_mpl_get_row_c0 double mpl_get_row_c0(MPL *mpl, int i); /* obtain constant term of free row */ #define mpl_get_col_name _glp_mpl_get_col_name char *mpl_get_col_name(MPL *mpl, int j); /* obtain column name */ #define mpl_get_col_kind _glp_mpl_get_col_kind int mpl_get_col_kind(MPL *mpl, int j); /* determine column kind */ #define mpl_get_col_bnds _glp_mpl_get_col_bnds int mpl_get_col_bnds(MPL *mpl, int j, double *lb, double *ub); /* obtain column bounds */ #define mpl_has_solve_stmt _glp_mpl_has_solve_stmt int mpl_has_solve_stmt(MPL *mpl); /* check if model has solve statement */ #if 1 /* 15/V-2010 */ #define mpl_put_row_soln _glp_mpl_put_row_soln void mpl_put_row_soln(MPL *mpl, int i, int stat, double prim, double dual); /* store row (constraint/objective) solution components */ #endif #if 1 /* 15/V-2010 */ #define mpl_put_col_soln _glp_mpl_put_col_soln void mpl_put_col_soln(MPL *mpl, int j, int stat, double prim, double dual); /* store column (variable) solution components */ #endif #if 0 /* 15/V-2010 */ #define mpl_put_col_value _glp_mpl_put_col_value void mpl_put_col_value(MPL *mpl, int j, double val); /* store column value */ #endif #define mpl_postsolve _glp_mpl_postsolve int mpl_postsolve(MPL *mpl); /* postsolve model */ #define mpl_terminate _glp_mpl_terminate void mpl_terminate(MPL *mpl); /* free all resources used by translator */ #endif /* eof */ Rglpk/src/GLPK/mc21a.c0000644000176000001440000002335212245352174013766 0ustar ripleyusers/* mc21a.c (permutations for zero-free diagonal) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * This code is the result of translation of the Fortran subroutines * MC21A and MC21B associated with the following paper: * * I.S.Duff, Algorithm 575: Permutations for zero-free diagonal, ACM * Trans. on Math. Softw. 7 (1981), 387-390. * * Use of ACM Algorithms is subject to the ACM Software Copyright and * License Agreement. See . * * The translation was made by Andrew Makhorin . * * 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 . ***********************************************************************/ #include "mc21a.h" /*********************************************************************** * NAME * * mc21a - permutations for zero-free diagonal * * SYNOPSIS * * #include "mc21a.h" * int mc21a(int n, const int icn[], const int ip[], const int lenr[], * int iperm[], int pr[], int arp[], int cv[], int out[]); * * DESCRIPTION * * Given the pattern of nonzeros of a sparse matrix, the routine mc21a * attempts to find a permutation of its rows that makes the matrix have * no zeros on its diagonal. * * INPUT PARAMETERS * * n order of matrix. * * icn array containing the column indices of the non-zeros. Those * belonging to a single row must be contiguous but the ordering * of column indices within each row is unimportant and wasted * space between rows is permitted. * * ip ip[i], i = 1,2,...,n, is the position in array icn of the * first column index of a non-zero in row i. * * lenr lenr[i], i = 1,2,...,n, is the number of non-zeros in row i. * * OUTPUT PARAMETER * * iperm contains permutation to make diagonal have the smallest * number of zeros on it. Elements (iperm[i], i), i = 1,2,...,n, * are non-zero at the end of the algorithm unless the matrix is * structurally singular. In this case, (iperm[i], i) will be * zero for n - numnz entries. * * WORKING ARRAYS * * pr working array of length [1+n], where pr[0] is not used. * pr[i] is the previous row to i in the depth first search. * * arp working array of length [1+n], where arp[0] is not used. * arp[i] is one less than the number of non-zeros in row i which * have not been scanned when looking for a cheap assignment. * * cv working array of length [1+n], where cv[0] is not used. * cv[i] is the most recent row extension at which column i was * visited. * * out working array of length [1+n], where out[0] is not used. * out[i] is one less than the number of non-zeros in row i * which have not been scanned during one pass through the main * loop. * * RETURNS * * The routine mc21a returns numnz, the number of non-zeros on diagonal * of permuted matrix. */ int mc21a(int n, const int icn[], const int ip[], const int lenr[], int iperm[], int pr[], int arp[], int cv[], int out[]) { int i, ii, in1, in2, j, j1, jord, k, kk, numnz; /* Initialization of arrays. */ for (i = 1; i <= n; i++) { arp[i] = lenr[i] - 1; cv[i] = iperm[i] = 0; } numnz = 0; /* Main loop. */ /* Each pass round this loop either results in a new assignment * or gives a row with no assignment. */ for (jord = 1; jord <= n; jord++) { j = jord; pr[j] = -1; for (k = 1; k <= jord; k++) { /* Look for a cheap assignment. */ in1 = arp[j]; if (in1 >= 0) { in2 = ip[j] + lenr[j] - 1; in1 = in2 - in1; for (ii = in1; ii <= in2; ii++) { i = icn[ii]; if (iperm[i] == 0) goto L110; } /* No cheap assignment in row. */ arp[j] = -1; } /* Begin looking for assignment chain starting with row j.*/ out[j] = lenr[j] - 1; /* Inner loop. Extends chain by one or backtracks. */ for (kk = 1; kk <= jord; kk++) { in1 = out[j]; if (in1 >= 0) { in2 = ip[j] + lenr[j] - 1; in1 = in2 - in1; /* Forward scan. */ for (ii = in1; ii <= in2; ii++) { i = icn[ii]; if (cv[i] != jord) { /* Column i has not yet been accessed during * this pass. */ j1 = j; j = iperm[i]; cv[i] = jord; pr[j] = j1; out[j1] = in2 - ii - 1; goto L100; } } } /* Backtracking step. */ j = pr[j]; if (j == -1) goto L130; } L100: ; } L110: /* New assignment is made. */ iperm[i] = j; arp[j] = in2 - ii - 1; numnz++; for (k = 1; k <= jord; k++) { j = pr[j]; if (j == -1) break; ii = ip[j] + lenr[j] - out[j] - 2; i = icn[ii]; iperm[i] = j; } L130: ; } /* If matrix is structurally singular, we now complete the * permutation iperm. */ if (numnz < n) { for (i = 1; i <= n; i++) arp[i] = 0; k = 0; for (i = 1; i <= n; i++) { if (iperm[i] == 0) out[++k] = i; else arp[iperm[i]] = i; } k = 0; for (i = 1; i <= n; i++) { if (arp[i] == 0) iperm[out[++k]] = i; } } return numnz; } /**********************************************************************/ #ifdef GLP_TEST #include "env.h" int sing; void ranmat(int m, int n, int icn[], int iptr[], int nnnp1, int *knum, int iw[]); void fa01bs(int max, int *nrand); int main(void) { /* test program for the routine mc21a */ /* these runs on random matrices cause all possible statements in * mc21a to be executed */ int i, iold, j, j1, j2, jj, knum, l, licn, n, nov4, num, numnz; int ip[1+21], icn[1+1000], iperm[1+20], lenr[1+20], iw1[1+80]; licn = 1000; /* run on random matrices of orders 1 through 20 */ for (n = 1; n <= 20; n++) { nov4 = n / 4; if (nov4 < 1) nov4 = 1; L10: fa01bs(nov4, &l); knum = l * n; /* knum is requested number of non-zeros in random matrix */ if (knum > licn) goto L10; /* if sing is false, matrix is guaranteed structurally * non-singular */ sing = ((n / 2) * 2 == n); /* call to subroutine to generate random matrix */ ranmat(n, n, icn, ip, n+1, &knum, iw1); /* knum is now actual number of non-zeros in random matrix */ if (knum > licn) goto L10; xprintf("n = %2d; nz = %4d; sing = %d\n", n, knum, sing); /* set up array of row lengths */ for (i = 1; i <= n; i++) lenr[i] = ip[i+1] - ip[i]; /* call to mc21a */ numnz = mc21a(n, icn, ip, lenr, iperm, &iw1[0], &iw1[n], &iw1[n+n], &iw1[n+n+n]); /* testing to see if there are numnz non-zeros on the diagonal * of the permuted matrix. */ num = 0; for (i = 1; i <= n; i++) { iold = iperm[i]; j1 = ip[iold]; j2 = j1 + lenr[iold] - 1; if (j2 < j1) continue; for (jj = j1; jj <= j2; jj++) { j = icn[jj]; if (j == i) { num++; break; } } } if (num != numnz) xprintf("Failure in mc21a, numnz = %d instead of %d\n", numnz, num); } return 0; } void ranmat(int m, int n, int icn[], int iptr[], int nnnp1, int *knum, int iw[]) { /* subroutine to generate random matrix */ int i, ii, inum, j, lrow, matnum; inum = (*knum / n) * 2; if (inum > n-1) inum = n-1; matnum = 1; /* each pass through this loop generates a row of the matrix */ for (j = 1; j <= m; j++) { iptr[j] = matnum; if (!(sing || j > n)) icn[matnum++] = j; if (n == 1) continue; for (i = 1; i <= n; i++) iw[i] = 0; if (!sing) iw[j] = 1; fa01bs(inum, &lrow); lrow--; if (lrow == 0) continue; /* lrow off-diagonal non-zeros in row j of the matrix */ for (ii = 1; ii <= lrow; ii++) { for (;;) { fa01bs(n, &i); if (iw[i] != 1) break; } iw[i] = 1; icn[matnum++] = i; } } for (i = m+1; i <= nnnp1; i++) iptr[i] = matnum; *knum = matnum - 1; return; } double g = 1431655765.0; double fa01as(int i) { /* random number generator */ g = fmod(g * 9228907.0, 4294967296.0); if (i >= 0) return g / 4294967296.0; else return 2.0 * g / 4294967296.0 - 1.0; } void fa01bs(int max, int *nrand) { *nrand = (int)(fa01as(1) * (double)max) + 1; return; } #endif /* eof */ Rglpk/src/GLPK/Makefile.am0000644000176000001440000000452712175147600014754 0ustar ripleyusers## Process this file with automake to produce Makefile.in ## include_HEADERS = glpk.h lib_LTLIBRARIES = libglpk.la libglpk_la_CPPFLAGS = \ -I$(srcdir) \ -I$(srcdir)/amd \ -I$(srcdir)/bflib \ -I$(srcdir)/cglib \ -I$(srcdir)/colamd \ -I$(srcdir)/env \ -I$(srcdir)/minisat \ -I$(srcdir)/misc \ -I$(srcdir)/proxy \ -I$(srcdir)/zlib libglpk_la_LDFLAGS = \ -version-info 36:1:0 \ -export-symbols-regex '^glp_*' libglpk_la_SOURCES = \ glpapi01.c \ glpapi02.c \ glpapi03.c \ glpapi04.c \ glpapi05.c \ glpapi06.c \ glpapi07.c \ glpapi08.c \ glpapi09.c \ glpapi10.c \ glpapi11.c \ glpapi12.c \ glpapi13.c \ glpapi14.c \ glpapi15.c \ glpapi16.c \ glpapi17.c \ glpapi18.c \ glpapi19.c \ glpapi20.c \ glpapi21.c \ glpavl.c \ glpbfd.c \ glpbfx.c \ glpcpx.c \ glpdmx.c \ glpenv07.c \ glpenv08.c \ glpgmp.c \ glphbm.c \ glpini01.c \ glpini02.c \ glpios01.c \ glpios02.c \ glpios03.c \ glpios04.c \ glpios05.c \ glpios06.c \ glpios07.c \ glpios08.c \ glpios09.c \ glpios10.c \ glpios11.c \ glpios12.c \ glpipm.c \ glplib03.c \ glplpf.c \ glplpx01.c \ glplpx02.c \ glplpx03.c \ glplux.c \ glpmat.c \ glpmpl01.c \ glpmpl02.c \ glpmpl03.c \ glpmpl04.c \ glpmpl05.c \ glpmpl06.c \ glpmps.c \ glpnet03.c \ glpnet04.c \ glpnet05.c \ glpnpp01.c \ glpnpp02.c \ glpnpp03.c \ glpnpp04.c \ glpnpp05.c \ glpnpp06.c \ glprgr.c \ glpscf.c \ glpscl.c \ glpsdf.c \ glpspm.c \ glpspx01.c \ glpspx02.c \ glpsql.c \ glpssx01.c \ glpssx02.c \ glptsp.c \ amd/amd_1.c \ amd/amd_2.c \ amd/amd_aat.c \ amd/amd_control.c \ amd/amd_defaults.c \ amd/amd_dump.c \ amd/amd_info.c \ amd/amd_order.c \ amd/amd_post_tree.c \ amd/amd_postorder.c \ amd/amd_preprocess.c \ amd/amd_valid.c \ bflib/fhv.c \ bflib/fhvint.c \ bflib/luf.c \ bflib/lufint.c \ bflib/sgf.c \ bflib/sva.c \ cglib/cfg.c \ cglib/cfg1.c \ colamd/colamd.c \ env/alloc.c \ env/env.c \ env/error.c \ env/stdout.c \ env/time.c \ env/tls.c \ minisat/minisat.c \ misc/bignum.c \ misc/dmp.c \ misc/ffalg.c \ misc/jd.c \ misc/keller.c \ misc/mc13d.c \ misc/mc21a.c \ misc/okalg.c \ misc/qmd.c \ misc/relax4.c \ misc/rng.c \ misc/rng1.c \ misc/triang.c \ misc/wclique.c \ misc/wclique1.c \ proxy/proxy.c \ proxy/proxy1.c \ zlib/adler32.c \ zlib/compress.c \ zlib/crc32.c \ zlib/deflate.c \ zlib/gzclose.c \ zlib/gzlib.c \ zlib/gzread.c \ zlib/gzwrite.c \ zlib/inffast.c \ zlib/inflate.c \ zlib/inftrees.c \ zlib/trees.c \ zlib/uncompr.c \ zlib/zio.c \ zlib/zutil.c ## eof ## Rglpk/src/GLPK/glplpx.h0000644000176000001440000005760012245352174014401 0ustar ripleyusers/* glplpx.h (obsolete API routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPLPX_H #define GLPLPX_H #define LPX glp_prob /* problem class: */ #define LPX_LP 100 /* linear programming (LP) */ #define LPX_MIP 101 /* mixed integer programming (MIP) */ /* type of auxiliary/structural variable: */ #define LPX_FR 110 /* free variable */ #define LPX_LO 111 /* variable with lower bound */ #define LPX_UP 112 /* variable with upper bound */ #define LPX_DB 113 /* double-bounded variable */ #define LPX_FX 114 /* fixed variable */ /* optimization direction flag: */ #define LPX_MIN 120 /* minimization */ #define LPX_MAX 121 /* maximization */ /* status of primal basic solution: */ #define LPX_P_UNDEF 132 /* primal solution is undefined */ #define LPX_P_FEAS 133 /* solution is primal feasible */ #define LPX_P_INFEAS 134 /* solution is primal infeasible */ #define LPX_P_NOFEAS 135 /* no primal feasible solution exists */ /* status of dual basic solution: */ #define LPX_D_UNDEF 136 /* dual solution is undefined */ #define LPX_D_FEAS 137 /* solution is dual feasible */ #define LPX_D_INFEAS 138 /* solution is dual infeasible */ #define LPX_D_NOFEAS 139 /* no dual feasible solution exists */ /* status of auxiliary/structural variable: */ #define LPX_BS 140 /* basic variable */ #define LPX_NL 141 /* non-basic variable on lower bound */ #define LPX_NU 142 /* non-basic variable on upper bound */ #define LPX_NF 143 /* non-basic free variable */ #define LPX_NS 144 /* non-basic fixed variable */ /* status of interior-point solution: */ #define LPX_T_UNDEF 150 /* interior solution is undefined */ #define LPX_T_OPT 151 /* interior solution is optimal */ /* kind of structural variable: */ #define LPX_CV 160 /* continuous variable */ #define LPX_IV 161 /* integer variable */ /* status of integer solution: */ #define LPX_I_UNDEF 170 /* integer solution is undefined */ #define LPX_I_OPT 171 /* integer solution is optimal */ #define LPX_I_FEAS 172 /* integer solution is feasible */ #define LPX_I_NOFEAS 173 /* no integer solution exists */ /* status codes reported by the routine lpx_get_status: */ #define LPX_OPT 180 /* optimal */ #define LPX_FEAS 181 /* feasible */ #define LPX_INFEAS 182 /* infeasible */ #define LPX_NOFEAS 183 /* no feasible */ #define LPX_UNBND 184 /* unbounded */ #define LPX_UNDEF 185 /* undefined */ /* exit codes returned by solver routines: */ #define LPX_E_OK 200 /* success */ #define LPX_E_EMPTY 201 /* empty problem */ #define LPX_E_BADB 202 /* invalid initial basis */ #define LPX_E_INFEAS 203 /* infeasible initial solution */ #define LPX_E_FAULT 204 /* unable to start the search */ #define LPX_E_OBJLL 205 /* objective lower limit reached */ #define LPX_E_OBJUL 206 /* objective upper limit reached */ #define LPX_E_ITLIM 207 /* iterations limit exhausted */ #define LPX_E_TMLIM 208 /* time limit exhausted */ #define LPX_E_NOFEAS 209 /* no feasible solution */ #define LPX_E_INSTAB 210 /* numerical instability */ #define LPX_E_SING 211 /* problems with basis matrix */ #define LPX_E_NOCONV 212 /* no convergence (interior) */ #define LPX_E_NOPFS 213 /* no primal feas. sol. (LP presolver) */ #define LPX_E_NODFS 214 /* no dual feas. sol. (LP presolver) */ #define LPX_E_MIPGAP 215 /* relative mip gap tolerance reached */ /* control parameter identifiers: */ #define LPX_K_MSGLEV 300 /* lp->msg_lev */ #define LPX_K_SCALE 301 /* lp->scale */ #define LPX_K_DUAL 302 /* lp->dual */ #define LPX_K_PRICE 303 /* lp->price */ #define LPX_K_RELAX 304 /* lp->relax */ #define LPX_K_TOLBND 305 /* lp->tol_bnd */ #define LPX_K_TOLDJ 306 /* lp->tol_dj */ #define LPX_K_TOLPIV 307 /* lp->tol_piv */ #define LPX_K_ROUND 308 /* lp->round */ #define LPX_K_OBJLL 309 /* lp->obj_ll */ #define LPX_K_OBJUL 310 /* lp->obj_ul */ #define LPX_K_ITLIM 311 /* lp->it_lim */ #define LPX_K_ITCNT 312 /* lp->it_cnt */ #define LPX_K_TMLIM 313 /* lp->tm_lim */ #define LPX_K_OUTFRQ 314 /* lp->out_frq */ #define LPX_K_OUTDLY 315 /* lp->out_dly */ #define LPX_K_BRANCH 316 /* lp->branch */ #define LPX_K_BTRACK 317 /* lp->btrack */ #define LPX_K_TOLINT 318 /* lp->tol_int */ #define LPX_K_TOLOBJ 319 /* lp->tol_obj */ #define LPX_K_MPSINFO 320 /* lp->mps_info */ #define LPX_K_MPSOBJ 321 /* lp->mps_obj */ #define LPX_K_MPSORIG 322 /* lp->mps_orig */ #define LPX_K_MPSWIDE 323 /* lp->mps_wide */ #define LPX_K_MPSFREE 324 /* lp->mps_free */ #define LPX_K_MPSSKIP 325 /* lp->mps_skip */ #define LPX_K_LPTORIG 326 /* lp->lpt_orig */ #define LPX_K_PRESOL 327 /* lp->presol */ #define LPX_K_BINARIZE 328 /* lp->binarize */ #define LPX_K_USECUTS 329 /* lp->use_cuts */ #define LPX_K_BFTYPE 330 /* lp->bfcp->type */ #define LPX_K_MIPGAP 331 /* lp->mip_gap */ #define LPX_C_COVER 0x01 /* mixed cover cuts */ #define LPX_C_CLIQUE 0x02 /* clique cuts */ #define LPX_C_GOMORY 0x04 /* Gomory's mixed integer cuts */ #define LPX_C_MIR 0x08 /* mixed integer rounding cuts */ #define LPX_C_ALL 0xFF /* all cuts */ typedef struct { /* this structure contains results reported by the routines which checks Karush-Kuhn-Tucker conditions (for details see comments to those routines) */ /*--------------------------------------------------------------*/ /* xR - A * xS = 0 (KKT.PE) */ double pe_ae_max; /* largest absolute error */ int pe_ae_row; /* number of row with largest absolute error */ double pe_re_max; /* largest relative error */ int pe_re_row; /* number of row with largest relative error */ int pe_quality; /* quality of primal solution: 'H' - high 'M' - medium 'L' - low '?' - primal solution is wrong */ /*--------------------------------------------------------------*/ /* l[k] <= x[k] <= u[k] (KKT.PB) */ double pb_ae_max; /* largest absolute error */ int pb_ae_ind; /* number of variable with largest absolute error */ double pb_re_max; /* largest relative error */ int pb_re_ind; /* number of variable with largest relative error */ int pb_quality; /* quality of primal feasibility: 'H' - high 'M' - medium 'L' - low '?' - primal solution is infeasible */ /*--------------------------------------------------------------*/ /* A' * (dR - cR) + (dS - cS) = 0 (KKT.DE) */ double de_ae_max; /* largest absolute error */ int de_ae_col; /* number of column with largest absolute error */ double de_re_max; /* largest relative error */ int de_re_col; /* number of column with largest relative error */ int de_quality; /* quality of dual solution: 'H' - high 'M' - medium 'L' - low '?' - dual solution is wrong */ /*--------------------------------------------------------------*/ /* d[k] >= 0 or d[k] <= 0 (KKT.DB) */ double db_ae_max; /* largest absolute error */ int db_ae_ind; /* number of variable with largest absolute error */ double db_re_max; /* largest relative error */ int db_re_ind; /* number of variable with largest relative error */ int db_quality; /* quality of dual feasibility: 'H' - high 'M' - medium 'L' - low '?' - dual solution is infeasible */ /*--------------------------------------------------------------*/ /* (x[k] - bound of x[k]) * d[k] = 0 (KKT.CS) */ double cs_ae_max; /* largest absolute error */ int cs_ae_ind; /* number of variable with largest absolute error */ double cs_re_max; /* largest relative error */ int cs_re_ind; /* number of variable with largest relative error */ int cs_quality; /* quality of complementary slackness: 'H' - high 'M' - medium 'L' - low '?' - primal and dual solutions are not complementary */ } LPXKKT; #define lpx_create_prob _glp_lpx_create_prob LPX *lpx_create_prob(void); /* create problem object */ #define lpx_set_prob_name _glp_lpx_set_prob_name void lpx_set_prob_name(LPX *lp, const char *name); /* assign (change) problem name */ #define lpx_set_obj_name _glp_lpx_set_obj_name void lpx_set_obj_name(LPX *lp, const char *name); /* assign (change) objective function name */ #define lpx_set_obj_dir _glp_lpx_set_obj_dir void lpx_set_obj_dir(LPX *lp, int dir); /* set (change) optimization direction flag */ #define lpx_add_rows _glp_lpx_add_rows int lpx_add_rows(LPX *lp, int nrs); /* add new rows to problem object */ #define lpx_add_cols _glp_lpx_add_cols int lpx_add_cols(LPX *lp, int ncs); /* add new columns to problem object */ #define lpx_set_row_name _glp_lpx_set_row_name void lpx_set_row_name(LPX *lp, int i, const char *name); /* assign (change) row name */ #define lpx_set_col_name _glp_lpx_set_col_name void lpx_set_col_name(LPX *lp, int j, const char *name); /* assign (change) column name */ #define lpx_set_row_bnds _glp_lpx_set_row_bnds void lpx_set_row_bnds(LPX *lp, int i, int type, double lb, double ub); /* set (change) row bounds */ #define lpx_set_col_bnds _glp_lpx_set_col_bnds void lpx_set_col_bnds(LPX *lp, int j, int type, double lb, double ub); /* set (change) column bounds */ #define lpx_set_obj_coef _glp_lpx_set_obj_coef void lpx_set_obj_coef(glp_prob *lp, int j, double coef); /* set (change) obj. coefficient or constant term */ #define lpx_set_mat_row _glp_lpx_set_mat_row void lpx_set_mat_row(LPX *lp, int i, int len, const int ind[], const double val[]); /* set (replace) row of the constraint matrix */ #define lpx_set_mat_col _glp_lpx_set_mat_col void lpx_set_mat_col(LPX *lp, int j, int len, const int ind[], const double val[]); /* set (replace) column of the constraint matrix */ #define lpx_load_matrix _glp_lpx_load_matrix void lpx_load_matrix(LPX *lp, int ne, const int ia[], const int ja[], const double ar[]); /* load (replace) the whole constraint matrix */ #define lpx_del_rows _glp_lpx_del_rows void lpx_del_rows(LPX *lp, int nrs, const int num[]); /* delete specified rows from problem object */ #define lpx_del_cols _glp_lpx_del_cols void lpx_del_cols(LPX *lp, int ncs, const int num[]); /* delete specified columns from problem object */ #define lpx_delete_prob _glp_lpx_delete_prob void lpx_delete_prob(LPX *lp); /* delete problem object */ #define lpx_get_prob_name _glp_lpx_get_prob_name const char *lpx_get_prob_name(LPX *lp); /* retrieve problem name */ #define lpx_get_obj_name _glp_lpx_get_obj_name const char *lpx_get_obj_name(LPX *lp); /* retrieve objective function name */ #define lpx_get_obj_dir _glp_lpx_get_obj_dir int lpx_get_obj_dir(LPX *lp); /* retrieve optimization direction flag */ #define lpx_get_num_rows _glp_lpx_get_num_rows int lpx_get_num_rows(LPX *lp); /* retrieve number of rows */ #define lpx_get_num_cols _glp_lpx_get_num_cols int lpx_get_num_cols(LPX *lp); /* retrieve number of columns */ #define lpx_get_row_name _glp_lpx_get_row_name const char *lpx_get_row_name(LPX *lp, int i); /* retrieve row name */ #define lpx_get_col_name _glp_lpx_get_col_name const char *lpx_get_col_name(LPX *lp, int j); /* retrieve column name */ #define lpx_get_row_type _glp_lpx_get_row_type int lpx_get_row_type(LPX *lp, int i); /* retrieve row type */ #define lpx_get_row_lb _glp_lpx_get_row_lb double lpx_get_row_lb(LPX *lp, int i); /* retrieve row lower bound */ #define lpx_get_row_ub _glp_lpx_get_row_ub double lpx_get_row_ub(LPX *lp, int i); /* retrieve row upper bound */ #define lpx_get_row_bnds _glp_lpx_get_row_bnds void lpx_get_row_bnds(LPX *lp, int i, int *typx, double *lb, double *ub); /* retrieve row bounds */ #define lpx_get_col_type _glp_lpx_get_col_type int lpx_get_col_type(LPX *lp, int j); /* retrieve column type */ #define lpx_get_col_lb _glp_lpx_get_col_lb double lpx_get_col_lb(LPX *lp, int j); /* retrieve column lower bound */ #define lpx_get_col_ub _glp_lpx_get_col_ub double lpx_get_col_ub(LPX *lp, int j); /* retrieve column upper bound */ #define lpx_get_col_bnds _glp_lpx_get_col_bnds void lpx_get_col_bnds(LPX *lp, int j, int *typx, double *lb, double *ub); /* retrieve column bounds */ #define lpx_get_obj_coef _glp_lpx_get_obj_coef double lpx_get_obj_coef(LPX *lp, int j); /* retrieve obj. coefficient or constant term */ #define lpx_get_num_nz _glp_lpx_get_num_nz int lpx_get_num_nz(LPX *lp); /* retrieve number of constraint coefficients */ #define lpx_get_mat_row _glp_lpx_get_mat_row int lpx_get_mat_row(LPX *lp, int i, int ind[], double val[]); /* retrieve row of the constraint matrix */ #define lpx_get_mat_col _glp_lpx_get_mat_col int lpx_get_mat_col(LPX *lp, int j, int ind[], double val[]); /* retrieve column of the constraint matrix */ #define lpx_create_index _glp_lpx_create_index void lpx_create_index(LPX *lp); /* create the name index */ #define lpx_find_row _glp_lpx_find_row int lpx_find_row(LPX *lp, const char *name); /* find row by its name */ #define lpx_find_col _glp_lpx_find_col int lpx_find_col(LPX *lp, const char *name); /* find column by its name */ #define lpx_delete_index _glp_lpx_delete_index void lpx_delete_index(LPX *lp); /* delete the name index */ #define lpx_scale_prob _glp_lpx_scale_prob void lpx_scale_prob(LPX *lp); /* scale problem data */ #define lpx_unscale_prob _glp_lpx_unscale_prob void lpx_unscale_prob(LPX *lp); /* unscale problem data */ #define lpx_set_row_stat _glp_lpx_set_row_stat void lpx_set_row_stat(LPX *lp, int i, int stat); /* set (change) row status */ #define lpx_set_col_stat _glp_lpx_set_col_stat void lpx_set_col_stat(LPX *lp, int j, int stat); /* set (change) column status */ #define lpx_std_basis _glp_lpx_std_basis void lpx_std_basis(LPX *lp); /* construct standard initial LP basis */ #define lpx_adv_basis _glp_lpx_adv_basis void lpx_adv_basis(LPX *lp); /* construct advanced initial LP basis */ #define lpx_cpx_basis _glp_lpx_cpx_basis void lpx_cpx_basis(LPX *lp); /* construct Bixby's initial LP basis */ #define lpx_simplex _glp_lpx_simplex int lpx_simplex(LPX *lp); /* easy-to-use driver to the simplex method */ #define lpx_exact _glp_lpx_exact int lpx_exact(LPX *lp); /* easy-to-use driver to the exact simplex method */ #define lpx_get_status _glp_lpx_get_status int lpx_get_status(LPX *lp); /* retrieve generic status of basic solution */ #define lpx_get_prim_stat _glp_lpx_get_prim_stat int lpx_get_prim_stat(LPX *lp); /* retrieve primal status of basic solution */ #define lpx_get_dual_stat _glp_lpx_get_dual_stat int lpx_get_dual_stat(LPX *lp); /* retrieve dual status of basic solution */ #define lpx_get_obj_val _glp_lpx_get_obj_val double lpx_get_obj_val(LPX *lp); /* retrieve objective value (basic solution) */ #define lpx_get_row_stat _glp_lpx_get_row_stat int lpx_get_row_stat(LPX *lp, int i); /* retrieve row status (basic solution) */ #define lpx_get_row_prim _glp_lpx_get_row_prim double lpx_get_row_prim(LPX *lp, int i); /* retrieve row primal value (basic solution) */ #define lpx_get_row_dual _glp_lpx_get_row_dual double lpx_get_row_dual(LPX *lp, int i); /* retrieve row dual value (basic solution) */ #define lpx_get_row_info _glp_lpx_get_row_info void lpx_get_row_info(LPX *lp, int i, int *tagx, double *vx, double *dx); /* obtain row solution information */ #define lpx_get_col_stat _glp_lpx_get_col_stat int lpx_get_col_stat(LPX *lp, int j); /* retrieve column status (basic solution) */ #define lpx_get_col_prim _glp_lpx_get_col_prim double lpx_get_col_prim(LPX *lp, int j); /* retrieve column primal value (basic solution) */ #define lpx_get_col_dual _glp_lpx_get_col_dual double lpx_get_col_dual(glp_prob *lp, int j); /* retrieve column dual value (basic solution) */ #define lpx_get_col_info _glp_lpx_get_col_info void lpx_get_col_info(LPX *lp, int j, int *tagx, double *vx, double *dx); /* obtain column solution information (obsolete) */ #define lpx_get_ray_info _glp_lpx_get_ray_info int lpx_get_ray_info(LPX *lp); /* determine what causes primal unboundness */ #define lpx_check_kkt _glp_lpx_check_kkt void lpx_check_kkt(LPX *lp, int scaled, LPXKKT *kkt); /* check Karush-Kuhn-Tucker conditions */ #define lpx_warm_up _glp_lpx_warm_up int lpx_warm_up(LPX *lp); /* "warm up" LP basis */ #define lpx_eval_tab_row _glp_lpx_eval_tab_row int lpx_eval_tab_row(LPX *lp, int k, int ind[], double val[]); /* compute row of the simplex table */ #define lpx_eval_tab_col _glp_lpx_eval_tab_col int lpx_eval_tab_col(LPX *lp, int k, int ind[], double val[]); /* compute column of the simplex table */ #define lpx_transform_row _glp_lpx_transform_row int lpx_transform_row(LPX *lp, int len, int ind[], double val[]); /* transform explicitly specified row */ #define lpx_transform_col _glp_lpx_transform_col int lpx_transform_col(LPX *lp, int len, int ind[], double val[]); /* transform explicitly specified column */ #define lpx_prim_ratio_test _glp_lpx_prim_ratio_test int lpx_prim_ratio_test(LPX *lp, int len, const int ind[], const double val[], int how, double tol); /* perform primal ratio test */ #define lpx_dual_ratio_test _glp_lpx_dual_ratio_test int lpx_dual_ratio_test(LPX *lp, int len, const int ind[], const double val[], int how, double tol); /* perform dual ratio test */ #define lpx_interior _glp_lpx_interior int lpx_interior(LPX *lp); /* easy-to-use driver to the interior point method */ #define lpx_ipt_status _glp_lpx_ipt_status int lpx_ipt_status(LPX *lp); /* retrieve status of interior-point solution */ #define lpx_ipt_obj_val _glp_lpx_ipt_obj_val double lpx_ipt_obj_val(LPX *lp); /* retrieve objective value (interior point) */ #define lpx_ipt_row_prim _glp_lpx_ipt_row_prim double lpx_ipt_row_prim(LPX *lp, int i); /* retrieve row primal value (interior point) */ #define lpx_ipt_row_dual _glp_lpx_ipt_row_dual double lpx_ipt_row_dual(LPX *lp, int i); /* retrieve row dual value (interior point) */ #define lpx_ipt_col_prim _glp_lpx_ipt_col_prim double lpx_ipt_col_prim(LPX *lp, int j); /* retrieve column primal value (interior point) */ #define lpx_ipt_col_dual _glp_lpx_ipt_col_dual double lpx_ipt_col_dual(LPX *lp, int j); /* retrieve column dual value (interior point) */ #define lpx_set_class _glp_lpx_set_class void lpx_set_class(LPX *lp, int klass); /* set problem class */ #define lpx_get_class _glp_lpx_get_class int lpx_get_class(LPX *lp); /* determine problem klass */ #define lpx_set_col_kind _glp_lpx_set_col_kind void lpx_set_col_kind(LPX *lp, int j, int kind); /* set (change) column kind */ #define lpx_get_col_kind _glp_lpx_get_col_kind int lpx_get_col_kind(LPX *lp, int j); /* retrieve column kind */ #define lpx_get_num_int _glp_lpx_get_num_int int lpx_get_num_int(LPX *lp); /* retrieve number of integer columns */ #define lpx_get_num_bin _glp_lpx_get_num_bin int lpx_get_num_bin(LPX *lp); /* retrieve number of binary columns */ #define lpx_integer _glp_lpx_integer int lpx_integer(LPX *lp); /* easy-to-use driver to the branch-and-bound method */ #define lpx_intopt _glp_lpx_intopt int lpx_intopt(LPX *lp); /* easy-to-use driver to the branch-and-bound method */ #define lpx_mip_status _glp_lpx_mip_status int lpx_mip_status(LPX *lp); /* retrieve status of MIP solution */ #define lpx_mip_obj_val _glp_lpx_mip_obj_val double lpx_mip_obj_val(LPX *lp); /* retrieve objective value (MIP solution) */ #define lpx_mip_row_val _glp_lpx_mip_row_val double lpx_mip_row_val(LPX *lp, int i); /* retrieve row value (MIP solution) */ #define lpx_mip_col_val _glp_lpx_mip_col_val double lpx_mip_col_val(LPX *lp, int j); /* retrieve column value (MIP solution) */ #define lpx_check_int _glp_lpx_check_int void lpx_check_int(LPX *lp, LPXKKT *kkt); /* check integer feasibility conditions */ #define lpx_reset_parms _glp_lpx_reset_parms void lpx_reset_parms(LPX *lp); /* reset control parameters to default values */ #define lpx_set_int_parm _glp_lpx_set_int_parm void lpx_set_int_parm(LPX *lp, int parm, int val); /* set (change) integer control parameter */ #define lpx_get_int_parm _glp_lpx_get_int_parm int lpx_get_int_parm(LPX *lp, int parm); /* query integer control parameter */ #define lpx_set_real_parm _glp_lpx_set_real_parm void lpx_set_real_parm(LPX *lp, int parm, double val); /* set (change) real control parameter */ #define lpx_get_real_parm _glp_lpx_get_real_parm double lpx_get_real_parm(LPX *lp, int parm); /* query real control parameter */ #define lpx_read_mps _glp_lpx_read_mps LPX *lpx_read_mps(const char *fname); /* read problem data in fixed MPS format */ #define lpx_write_mps _glp_lpx_write_mps int lpx_write_mps(LPX *lp, const char *fname); /* write problem data in fixed MPS format */ #define lpx_read_bas _glp_lpx_read_bas int lpx_read_bas(LPX *lp, const char *fname); /* read LP basis in fixed MPS format */ #define lpx_write_bas _glp_lpx_write_bas int lpx_write_bas(LPX *lp, const char *fname); /* write LP basis in fixed MPS format */ #define lpx_read_freemps _glp_lpx_read_freemps LPX *lpx_read_freemps(const char *fname); /* read problem data in free MPS format */ #define lpx_write_freemps _glp_lpx_write_freemps int lpx_write_freemps(LPX *lp, const char *fname); /* write problem data in free MPS format */ #define lpx_read_cpxlp _glp_lpx_read_cpxlp LPX *lpx_read_cpxlp(const char *fname); /* read problem data in CPLEX LP format */ #define lpx_write_cpxlp _glp_lpx_write_cpxlp int lpx_write_cpxlp(LPX *lp, const char *fname); /* write problem data in CPLEX LP format */ #define lpx_read_model _glp_lpx_read_model LPX *lpx_read_model(const char *model, const char *data, const char *output); /* read LP/MIP model written in GNU MathProg language */ #define lpx_print_prob _glp_lpx_print_prob int lpx_print_prob(LPX *lp, const char *fname); /* write problem data in plain text format */ #define lpx_print_sol _glp_lpx_print_sol int lpx_print_sol(LPX *lp, const char *fname); /* write LP problem solution in printable format */ #define lpx_print_sens_bnds _glp_lpx_print_sens_bnds int lpx_print_sens_bnds(LPX *lp, const char *fname); /* write bounds sensitivity information */ #define lpx_print_ips _glp_lpx_print_ips int lpx_print_ips(LPX *lp, const char *fname); /* write interior point solution in printable format */ #define lpx_print_mip _glp_lpx_print_mip int lpx_print_mip(LPX *lp, const char *fname); /* write MIP problem solution in printable format */ #define lpx_is_b_avail _glp_lpx_is_b_avail int lpx_is_b_avail(LPX *lp); /* check if LP basis is available */ #define lpx_write_pb _glp_lpx_write_pb int lpx_write_pb(LPX *lp, const char *fname, int normalized, int binarize); /* write problem data in (normalized) OPB format */ #define lpx_main _glp_lpx_main int lpx_main(int argc, const char *argv[]); /* stand-alone LP/MIP solver */ #endif /* eof */ Rglpk/src/GLPK/zlib/0000755000176000001440000000000012175147600013650 5ustar ripleyusersRglpk/src/GLPK/zlib/zconf.h0000644000176000001440000000362512245352174015150 0ustar ripleyusers/* zconf.h */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* zconf.h -- configuration of the zlib compression library * Copyright (C) 1995-2012 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ #ifndef ZCONF_H #define ZCONF_H #if 1 /* by mao */ #include "zsymb.h" #endif /* Maximum value for memLevel in deflateInit2 */ #ifndef MAX_MEM_LEVEL # define MAX_MEM_LEVEL 9 #endif /* Maximum value for windowBits in deflateInit2 and inflateInit2. * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files * created by gzip. (Files created by minigzip can still be extracted by * gzip.) */ #ifndef MAX_WBITS # define MAX_WBITS 15 /* 32K LZ77 window */ #endif /* The memory requirements for deflate are (in bytes): (1 << (windowBits+2)) + (1 << (memLevel+9)) that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) plus a few kilobytes for small objects. For example, if you want to reduce the default memory requirements from 256K to 128K, compile with make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" Of course this will generally degrade compression (there's no free lunch). The memory requirements for inflate are (in bytes) 1 << windowBits that is, 32K for windowBits=15 (default value) plus a few kilobytes for small objects. */ /* Type declarations */ typedef unsigned char Byte; /* 8 bits */ typedef unsigned int uInt; /* 16 bits or more */ typedef unsigned long uLong; /* 32 bits or more */ typedef Byte Bytef; typedef char charf; typedef int intf; typedef uInt uIntf; typedef uLong uLongf; typedef void const *voidpc; typedef void *voidpf; typedef void *voidp; typedef unsigned long z_crc_t; #ifndef z_off_t # define z_off_t long #endif #define z_off64_t z_off_t #endif /* ZCONF_H */ /* eof */ Rglpk/src/GLPK/zlib/adler32.c0000644000176000001440000001146012245352174015254 0ustar ripleyusers/* adler32.c */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* adler32.c -- compute the Adler-32 checksum of a data stream * Copyright (C) 1995-2011 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" static uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2); #define BASE 65521 /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ #define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); #define DO16(buf) DO8(buf,0); DO8(buf,8); /* use NO_DIVIDE if your processor does not do division in hardware -- try it both ways to see which is faster */ #ifdef NO_DIVIDE /* note that this assumes BASE is 65521, where 65536 % 65521 == 15 (thank you to John Reiser for pointing this out) */ # define CHOP(a) \ do { \ unsigned long tmp = a >> 16; \ a &= 0xffffUL; \ a += (tmp << 4) - tmp; \ } while (0) # define MOD28(a) \ do { \ CHOP(a); \ if (a >= BASE) a -= BASE; \ } while (0) # define MOD(a) \ do { \ CHOP(a); \ MOD28(a); \ } while (0) # define MOD63(a) \ do { /* this assumes a is not negative */ \ z_off64_t tmp = a >> 32; \ a &= 0xffffffffL; \ a += (tmp << 8) - (tmp << 5) + tmp; \ tmp = a >> 16; \ a &= 0xffffL; \ a += (tmp << 4) - tmp; \ tmp = a >> 16; \ a &= 0xffffL; \ a += (tmp << 4) - tmp; \ if (a >= BASE) a -= BASE; \ } while (0) #else # define MOD(a) a %= BASE # define MOD28(a) a %= BASE # define MOD63(a) a %= BASE #endif /* ========================================================================= */ uLong adler32(uLong adler, const Bytef *buf, uInt len) { unsigned long sum2; unsigned n; /* split Adler-32 into component sums */ sum2 = (adler >> 16) & 0xffff; adler &= 0xffff; /* in case user likes doing a byte at a time, keep it fast */ if (len == 1) { adler += buf[0]; if (adler >= BASE) adler -= BASE; sum2 += adler; if (sum2 >= BASE) sum2 -= BASE; return adler | (sum2 << 16); } /* initial Adler-32 value (deferred check for len == 1 speed) */ if (buf == Z_NULL) return 1L; /* in case short lengths are provided, keep it somewhat fast */ if (len < 16) { while (len--) { adler += *buf++; sum2 += adler; } if (adler >= BASE) adler -= BASE; MOD28(sum2); /* only added so many BASE's */ return adler | (sum2 << 16); } /* do length NMAX blocks -- requires just one modulo operation */ while (len >= NMAX) { len -= NMAX; n = NMAX / 16; /* NMAX is divisible by 16 */ do { DO16(buf); /* 16 sums unrolled */ buf += 16; } while (--n); MOD(adler); MOD(sum2); } /* do remaining bytes (less than NMAX, still just one modulo) */ if (len) { /* avoid modulos if none remaining */ while (len >= 16) { len -= 16; DO16(buf); buf += 16; } while (len--) { adler += *buf++; sum2 += adler; } MOD(adler); MOD(sum2); } /* return recombined sums */ return adler | (sum2 << 16); } /* ========================================================================= */ static uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2) { unsigned long sum1; unsigned long sum2; unsigned rem; /* for negative len, return invalid adler32 as a clue for debugging */ if (len2 < 0) return 0xffffffffUL; /* the derivation of this formula is left as an exercise for the reader */ MOD63(len2); /* assumes len2 >= 0 */ rem = (unsigned)len2; sum1 = adler1 & 0xffff; sum2 = rem * sum1; MOD(sum2); sum1 += (adler2 & 0xffff) + BASE - 1; sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; if (sum1 >= BASE) sum1 -= BASE; if (sum1 >= BASE) sum1 -= BASE; if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1); if (sum2 >= BASE) sum2 -= BASE; return sum1 | (sum2 << 16); } /* ========================================================================= */ uLong adler32_combine(uLong adler1, uLong adler2, z_off_t len2) { return adler32_combine_(adler1, adler2, len2); } uLong adler32_combine64(uLong adler1, uLong adler2, z_off64_t len2) { return adler32_combine_(adler1, adler2, len2); } /* eof */ Rglpk/src/GLPK/zlib/zio.c0000644000176000001440000000344712245352174014627 0ustar ripleyusers/* zio.c (simulation of POSIX low-level I/O functions) */ /* Written by Andrew Makhorin , June 2013 * For conditions of distribution and use, see copyright notice in * zlib.h */ #include #include #include "zio.h" static FILE *file[FOPEN_MAX]; int open(const char *path, int oflag, ...) { FILE *f; int fd; /* see file gzlib.c, function gz_open */ if (oflag == O_RDONLY) f = fopen(path, "rb"); else if (oflag == (O_WRONLY | O_CREAT | O_TRUNC)) f = fopen(path, "wb"); else if (oflag == (O_WRONLY | O_CREAT | O_APPEND)) f = fopen(path, "ab"); else assert(oflag != oflag); if (f == NULL) return -1; for (fd = 3; fd < FOPEN_MAX; fd++) if (file[fd] == NULL) break; assert(fd < FOPEN_MAX); file[fd] = f; return fd; } long read(int fd, void *buf, unsigned long cnt) { FILE *f; assert(3 <= fd && fd < FOPEN_MAX); f = file[fd]; assert(f != NULL); cnt = fread(buf, 1, cnt, f); if (ferror(f)) return -1; return cnt; } long write(int fd, const void *buf, unsigned long cnt) { FILE *f; assert(3 <= fd && fd < FOPEN_MAX); f = file[fd]; assert(f != NULL); cnt = fwrite(buf, 1, cnt, f); if (ferror(f)) return -1; if (fflush(f) != 0) return -1; return cnt; } long lseek(int fd, long offset, int whence) { FILE *f; assert(3 <= fd && fd < FOPEN_MAX); f = file[fd]; assert(f != NULL); if (fseek(f, offset, whence) != 0) return -1; return ftell(f); } int close(int fd) { FILE *f; assert(3 <= fd && fd < FOPEN_MAX); f = file[fd]; assert(f != NULL); file[fd] = NULL; return fclose(f); } /* eof */ Rglpk/src/GLPK/zlib/crc32.h0000644000176000001440000007353712245352174014756 0ustar ripleyusers/* crc32.h -- tables for rapid CRC calculation * Generated automatically by crc32.c */ static const z_crc_t crc_table[TBLS][256] = { { 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, 0x2d02ef8dUL #ifdef BYFOUR }, { 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, 0x9324fd72UL }, { 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, 0xbe9834edUL }, { 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, 0xde0506f1UL }, { 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, 0x8def022dUL }, { 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, 0x72fd2493UL }, { 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, 0xed3498beUL }, { 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, 0xf10605deUL #endif } }; Rglpk/src/GLPK/zlib/inftrees.h0000644000176000001440000000570112245352174015645 0ustar ripleyusers/* inftrees.h */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* inftrees.h -- header to use inftrees.c * Copyright (C) 1995-2005, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* Structure for decoding tables. Each entry provides either the information needed to do the operation requested by the code that indexed that table entry, or it provides a pointer to another table that indexes more bits of the code. op indicates whether the entry is a pointer to another table, a literal, a length or distance, an end-of-block, or an invalid code. For a table pointer, the low four bits of op is the number of index bits of that table. For a length or distance, the low four bits of op is the number of extra bits to get after the code. bits is the number of bits in this code or part of the code to drop off of the bit buffer. val is the actual byte to output in the case of a literal, the base length or distance, or the offset from the current table to the next table. Each entry is four bytes. */ typedef struct { unsigned char op; /* operation, extra bits, table bits */ unsigned char bits; /* bits in this part of the code */ unsigned short val; /* offset in table or code value */ } code; /* op values as set by inflate_table(): 00000000 - literal 0000tttt - table link, tttt != 0 is the number of table index bits 0001eeee - length or distance, eeee is the number of extra bits 01100000 - end of block 01000000 - invalid code */ /* Maximum size of the dynamic table. The maximum number of code structures is 1444, which is the sum of 852 for literal/length codes and 592 for distance codes. These values were found by exhaustive searches using the program examples/enough.c found in the zlib distribtution. The arguments to that program are the number of symbols, the initial root table size, and the maximum bit length of a code. "enough 286 9 15" for literal/length codes returns returns 852, and "enough 30 6 15" for distance codes returns 592. The initial root table size (9 or 6) is found in the fifth argument of the inflate_table() calls in inflate.c and infback.c. If the root table size is changed, then these maximum sizes would be need to be recalculated and updated. */ #define ENOUGH_LENS 852 #define ENOUGH_DISTS 592 #define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) /* Type of code to build for inflate_table() */ typedef enum { CODES, LENS, DISTS } codetype; int inflate_table(codetype type, unsigned short *lens, unsigned codes, code **table, unsigned *bits, unsigned short *work); /* eof */ Rglpk/src/GLPK/zlib/gzread.c0000644000176000001440000004362612245352174015305 0ustar ripleyusers/* gzread.c */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* gzread.c -- zlib functions for reading gzip files * Copyright (C) 2004, 2005, 2010, 2011, 2012 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* Local functions */ static int gz_load (gz_statep, unsigned char *, unsigned, unsigned *); static int gz_avail (gz_statep); static int gz_look (gz_statep); static int gz_decomp (gz_statep); static int gz_fetch (gz_statep); static int gz_skip (gz_statep, z_off64_t); /* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from state->fd, and update state->eof, state->err, and state->msg as appropriate. This function needs to loop on read(), since read() is not guaranteed to read the number of bytes requested, depending on the type of descriptor. */ static int gz_load(gz_statep state, unsigned char *buf, unsigned len, unsigned *have) { int ret; *have = 0; do { ret = read(state->fd, buf + *have, len - *have); if (ret <= 0) break; *have += ret; } while (*have < len); if (ret < 0) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } if (ret == 0) state->eof = 1; return 0; } /* Load up input buffer and set eof flag if last data loaded -- return -1 on error, 0 otherwise. Note that the eof flag is set when the end of the input file is reached, even though there may be unused data in the buffer. Once that data has been used, no more attempts will be made to read the file. If strm->avail_in != 0, then the current data is moved to the beginning of the input buffer, and then the remainder of the buffer is loaded with the available data from the input file. */ static int gz_avail(gz_statep state) { unsigned got; z_streamp strm = &(state->strm); if (state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; if (state->eof == 0) { if (strm->avail_in) { /* copy what's there to the start */ unsigned char *p = state->in, *q = strm->next_in; unsigned n = strm->avail_in; do { *p++ = *q++; } while (--n); } if (gz_load(state, state->in + strm->avail_in, state->size - strm->avail_in, &got) == -1) return -1; strm->avail_in += got; strm->next_in = state->in; } return 0; } /* Look for gzip header, set up for inflate or copy. state->x.have must be 0. If this is the first time in, allocate required memory. state->how will be left unchanged if there is no more input data available, will be set to COPY if there is no gzip header and direct copying will be performed, or it will be set to GZIP for decompression. If direct copying, then leftover input data from the input buffer will be copied to the output buffer. In that case, all further file reads will be directly to either the output buffer or a user buffer. If decompressing, the inflate state will be initialized. gz_look() will return 0 on success or -1 on failure. */ static int gz_look(gz_statep state) { z_streamp strm = &(state->strm); /* allocate read buffers and inflate memory */ if (state->size == 0) { /* allocate buffers */ state->in = malloc(state->want); state->out = malloc(state->want << 1); if (state->in == NULL || state->out == NULL) { if (state->out != NULL) free(state->out); if (state->in != NULL) free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } state->size = state->want; /* allocate inflate memory */ state->strm.zalloc = Z_NULL; state->strm.zfree = Z_NULL; state->strm.opaque = Z_NULL; state->strm.avail_in = 0; state->strm.next_in = Z_NULL; if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */ free(state->out); free(state->in); state->size = 0; gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } } /* get at least the magic bytes in the input buffer */ if (strm->avail_in < 2) { if (gz_avail(state) == -1) return -1; if (strm->avail_in == 0) return 0; } /* look for gzip magic bytes -- if there, do gzip decoding (note: there is a logical dilemma here when considering the case of a partially written gzip file, to wit, if a single 31 byte is written, then we cannot tell whether this is a single-byte file, or just a partially written gzip file -- for here we assume that if a gzip file is being written, then the header will be written in a single operation, so that reading a single byte is sufficient indication that it is not a gzip file) */ if (strm->avail_in > 1 && strm->next_in[0] == 31 && strm->next_in[1] == 139) { inflateReset(strm); state->how = GZIP; state->direct = 0; return 0; } /* no gzip header -- if we were decoding gzip before, then this is trailing garbage. Ignore the trailing garbage and finish. */ if (state->direct == 0) { strm->avail_in = 0; state->eof = 1; state->x.have = 0; return 0; } /* doing raw i/o, copy any leftover input to output -- this assumes that the output buffer is larger than the input buffer, which also assures space for gzungetc() */ state->x.next = state->out; if (strm->avail_in) { memcpy(state->x.next, strm->next_in, strm->avail_in); state->x.have = strm->avail_in; strm->avail_in = 0; } state->how = COPY; state->direct = 1; return 0; } /* Decompress from input to the provided next_out and avail_out in the state. On return, state->x.have and state->x.next point to the just decompressed data. If the gzip stream completes, state->how is reset to LOOK to look for the next gzip stream or raw data, once state->x.have is depleted. Returns 0 on success, -1 on failure. */ static int gz_decomp(gz_statep state) { int ret = Z_OK; unsigned had; z_streamp strm = &(state->strm); /* fill output buffer up to end of deflate stream */ had = strm->avail_out; do { /* get more input for inflate() */ if (strm->avail_in == 0 && gz_avail(state) == -1) return -1; if (strm->avail_in == 0) { gz_error(state, Z_BUF_ERROR, "unexpected end of file"); break; } /* decompress and handle errors */ ret = inflate(strm, Z_NO_FLUSH); if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { gz_error(state, Z_STREAM_ERROR, "internal error: inflate stream corrupt"); return -1; } if (ret == Z_MEM_ERROR) { gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ gz_error(state, Z_DATA_ERROR, strm->msg == NULL ? "compressed data error" : strm->msg); return -1; } } while (strm->avail_out && ret != Z_STREAM_END); /* update available output */ state->x.have = had - strm->avail_out; state->x.next = strm->next_out - state->x.have; /* if the gzip stream completed successfully, look for another */ if (ret == Z_STREAM_END) state->how = LOOK; /* good decompression */ return 0; } /* Fetch data and put it in the output buffer. Assumes state->x.have is 0. Data is either copied from the input file or decompressed from the input file depending on state->how. If state->how is LOOK, then a gzip header is looked for to determine whether to copy or decompress. Returns -1 on error, otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the end of the input file has been reached and all data has been processed. */ static int gz_fetch(gz_statep state) { z_streamp strm = &(state->strm); do { switch(state->how) { case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ if (gz_look(state) == -1) return -1; if (state->how == LOOK) return 0; break; case COPY: /* -> COPY */ if (gz_load(state, state->out, state->size << 1, &(state->x.have)) == -1) return -1; state->x.next = state->out; return 0; case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */ strm->avail_out = state->size << 1; strm->next_out = state->out; if (gz_decomp(state) == -1) return -1; } } while (state->x.have == 0 && (!state->eof || strm->avail_in)); return 0; } /* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ static int gz_skip(gz_statep state, z_off64_t len) { unsigned n; /* skip over len bytes or reach end-of-file, whichever comes first */ while (len) /* skip over whatever is in output buffer */ if (state->x.have) { n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? (unsigned)len : state->x.have; state->x.have -= n; state->x.next += n; state->x.pos += n; len -= n; } /* output buffer empty -- return if we're at the end of the input */ else if (state->eof && state->strm.avail_in == 0) break; /* need more data to skip -- load up output buffer */ else { /* get more output, looking for header if required */ if (gz_fetch(state) == -1) return -1; } return 0; } /* -- see zlib.h -- */ int gzread(gzFile file, voidp buf, unsigned len) { unsigned got, n; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; strm = &(state->strm); /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids the flaw in the interface) */ if ((int)len < 0) { gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); return -1; } /* if len is zero, avoid unnecessary operations */ if (len == 0) return 0; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return -1; } /* get len bytes to buf, or less than len if at the end */ got = 0; do { /* first just try copying data from the output buffer */ if (state->x.have) { n = state->x.have > len ? len : state->x.have; memcpy(buf, state->x.next, n); state->x.next += n; state->x.have -= n; } /* output buffer empty -- return if we're at the end of the input */ else if (state->eof && strm->avail_in == 0) { state->past = 1; /* tried to read past end */ break; } /* need output data -- for small len or new stream load up our output buffer */ else if (state->how == LOOK || len < (state->size << 1)) { /* get more output, looking for header if required */ if (gz_fetch(state) == -1) return -1; continue; /* no progress yet -- go back to copy above */ /* the copy above assures that we will leave with space in the output buffer, allowing at least one gzungetc() to succeed */ } /* large len -- read directly into user buffer */ else if (state->how == COPY) { /* read directly */ if (gz_load(state, buf, len, &n) == -1) return -1; } /* large len -- decompress directly into user buffer */ else { /* state->how == GZIP */ strm->avail_out = len; strm->next_out = buf; if (gz_decomp(state) == -1) return -1; n = state->x.have; state->x.have = 0; } /* update progress */ len -= n; buf = (char *)buf + n; got += n; state->x.pos += n; } while (len); /* return number of bytes read into user buffer (will fit in int) */ return (int)got; } /* -- see zlib.h -- */ int gzgetc(gzFile file) { int ret; unsigned char buf[1]; gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* try output buffer (no need to check for skip request) */ if (state->x.have) { state->x.have--; state->x.pos++; return *(state->x.next)++; } /* nothing there -- try gzread() */ ret = gzread(file, buf, 1); return ret < 1 ? -1 : buf[0]; } /* -- see zlib.h -- */ int gzungetc(int c, gzFile file) { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return -1; } /* can't push EOF */ if (c < 0) return -1; /* if output buffer empty, put byte at end (allows more pushing) */ if (state->x.have == 0) { state->x.have = 1; state->x.next = state->out + (state->size << 1) - 1; state->x.next[0] = c; state->x.pos--; state->past = 0; return c; } /* if no room, give up (must have already done a gzungetc()) */ if (state->x.have == (state->size << 1)) { gz_error(state, Z_DATA_ERROR, "out of room to push characters"); return -1; } /* slide output data if needed and insert byte before existing data */ if (state->x.next == state->out) { unsigned char *src = state->out + state->x.have; unsigned char *dest = state->out + (state->size << 1); while (src > state->out) *--dest = *--src; state->x.next = dest; } state->x.have++; state->x.next--; state->x.next[0] = c; state->x.pos--; state->past = 0; return c; } /* -- see zlib.h -- */ char *gzgets(gzFile file, char *buf, int len) { unsigned left, n; char *str; unsigned char *eol; gz_statep state; /* check parameters and get internal structure */ if (file == NULL || buf == NULL || len < 1) return NULL; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return NULL; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return NULL; } /* copy output bytes up to new line or len - 1, whichever comes first -- append a terminating zero to the string (we don't check for a zero in the contents, let the user worry about that) */ str = buf; left = (unsigned)len - 1; if (left) do { /* assure that something is in the output buffer */ if (state->x.have == 0 && gz_fetch(state) == -1) return NULL; /* error */ if (state->x.have == 0) { /* end of file */ state->past = 1; /* read past end */ break; /* return what we have */ } /* look for end-of-line in current output buffer */ n = state->x.have > left ? left : state->x.have; eol = memchr(state->x.next, '\n', n); if (eol != NULL) n = (unsigned)(eol - state->x.next) + 1; /* copy through end-of-line, or remainder if not found */ memcpy(buf, state->x.next, n); state->x.have -= n; state->x.next += n; state->x.pos += n; left -= n; buf += n; } while (left && eol == NULL); /* return terminated string, or if nothing, end of file */ if (buf == str) return NULL; buf[0] = 0; return str; } /* -- see zlib.h -- */ int gzdirect(gzFile file) { gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; /* if the state is not known, but we can find out, then do so (this is mainly for right after a gzopen() or gzdopen()) */ if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) (void)gz_look(state); /* return 1 if transparent, 0 if processing a gzip stream */ return state->direct; } /* -- see zlib.h -- */ int gzclose_r(gzFile file) { int ret, err; gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; /* check that we're reading */ if (state->mode != GZ_READ) return Z_STREAM_ERROR; /* free memory and close file */ if (state->size) { inflateEnd(&(state->strm)); free(state->out); free(state->in); } err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; gz_error(state, Z_OK, NULL); free(state->path); ret = close(state->fd); free(state); return ret ? Z_ERRNO : err; } /* eof */ Rglpk/src/GLPK/zlib/zutil.h0000644000176000001440000000617312245352174015201 0ustar ripleyusers/* zutil.h */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* zutil.h -- internal interface and configuration of the compression library * Copyright (C) 1995-2012 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ #ifndef ZUTIL_H #define ZUTIL_H #include #include #include "zlib.h" typedef unsigned char uch; typedef uch uchf; typedef unsigned short ush; typedef ush ushf; typedef unsigned long ulg; extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* (size given to avoid silly warnings with Visual C++) */ #define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] #define ERR_RETURN(strm,err) \ return (strm->msg = (char*)ERR_MSG(err), (err)) /* To be used only when the state is known to be valid */ /* common constants */ #ifndef DEF_WBITS # define DEF_WBITS MAX_WBITS #endif /* default windowBits for decompression. MAX_WBITS is for compression only */ #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif /* default memLevel */ #define STORED_BLOCK 0 #define STATIC_TREES 1 #define DYN_TREES 2 /* The three kinds of block type */ #define MIN_MATCH 3 #define MAX_MATCH 258 /* The minimum and maximum match lengths */ #define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ /* target dependencies */ uLong adler32_combine64(uLong, uLong, z_off_t); uLong crc32_combine64(uLong, uLong, z_off_t); /* common defaults */ #ifndef OS_CODE # define OS_CODE 0x03 /* assume Unix */ #endif #ifndef F_OPEN # define F_OPEN(name, mode) fopen((name), (mode)) #endif /* functions */ #define zmemcpy memcpy #define zmemcmp memcmp #define zmemzero(dest, len) memset(dest, 0, len) /* Diagnostic functions */ #ifdef DEBUG # include extern int z_verbose; extern void z_error(char *m); # define Assert(cond,msg) {if(!(cond)) z_error(msg);} # define Trace(x) {if (z_verbose>=0) fprintf x ;} # define Tracev(x) {if (z_verbose>0) fprintf x ;} # define Tracevv(x) {if (z_verbose>1) fprintf x ;} # define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} # define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} #else # define Assert(cond,msg) # define Trace(x) # define Tracev(x) # define Tracevv(x) # define Tracec(c,x) # define Tracecv(c,x) #endif #ifndef Z_SOLO voidpf zcalloc(voidpf opaque, unsigned items, unsigned size); void zcfree(voidpf opaque, voidpf ptr); #endif #define ZALLOC(strm, items, size) \ (*((strm)->zalloc))((strm)->opaque, (items), (size)) #define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) #define TRY_FREE(s, p) {if (p) ZFREE(s, p);} /* Reverse the bytes in a 32-bit value */ #define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) #endif /* ZUTIL_H */ /* eof */ Rglpk/src/GLPK/zlib/inflate.h0000644000176000001440000001461412245352174015453 0ustar ripleyusers/* inflate.h */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* inflate.h -- internal inflate state definition * Copyright (C) 1995-2009 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* define NO_GZIP when compiling if you want to disable gzip header and trailer decoding by inflate(). NO_GZIP would be used to avoid linking in the crc code when it is not needed. For shared libraries, gzip decoding should be left enabled. */ #ifndef NO_GZIP # define GUNZIP #endif /* Possible inflate modes between inflate() calls */ typedef enum { HEAD, /* i: waiting for magic header */ FLAGS, /* i: waiting for method and flags (gzip) */ TIME, /* i: waiting for modification time (gzip) */ OS, /* i: waiting for extra flags and operating system (gzip) */ EXLEN, /* i: waiting for extra length (gzip) */ EXTRA, /* i: waiting for extra bytes (gzip) */ NAME, /* i: waiting for end of file name (gzip) */ COMMENT, /* i: waiting for end of comment (gzip) */ HCRC, /* i: waiting for header crc (gzip) */ DICTID, /* i: waiting for dictionary check value */ DICT, /* waiting for inflateSetDictionary() call */ TYPE, /* i: waiting for type bits, including last-flag bit */ TYPEDO, /* i: same, but skip check to exit inflate on new block */ STORED, /* i: waiting for stored size (length and complement) */ COPY_, /* i/o: same as COPY below, but only first time in */ COPY, /* i/o: waiting for input or output to copy stored block */ TABLE, /* i: waiting for dynamic block table lengths */ LENLENS, /* i: waiting for code length code lengths */ CODELENS, /* i: waiting for length/lit and distance code lengths */ LEN_, /* i: same as LEN below, but only first time in */ LEN, /* i: waiting for length/lit/eob code */ LENEXT, /* i: waiting for length extra bits */ DIST, /* i: waiting for distance code */ DISTEXT, /* i: waiting for distance extra bits */ MATCH, /* o: waiting for output space to copy string */ LIT, /* o: waiting for output space to write literal */ CHECK, /* i: waiting for 32-bit check value */ LENGTH, /* i: waiting for 32-bit length (gzip) */ DONE, /* finished check, done -- remain here until reset */ BAD, /* got a data error -- remain here until reset */ MEM, /* got an inflate() memory error -- remain here until reset */ SYNC /* looking for synchronization bytes to restart inflate() */ } inflate_mode; /* State transitions between above modes - (most modes can go to BAD or MEM on error -- not shown for clarity) Process header: HEAD -> (gzip) or (zlib) or (raw) (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> HCRC -> TYPE (zlib) -> DICTID or TYPE DICTID -> DICT -> TYPE (raw) -> TYPEDO Read deflate blocks: TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK STORED -> COPY_ -> COPY -> TYPE TABLE -> LENLENS -> CODELENS -> LEN_ LEN_ -> LEN Read deflate codes in fixed or dynamic block: LEN -> LENEXT or LIT or TYPE LENEXT -> DIST -> DISTEXT -> MATCH -> LEN LIT -> LEN Process trailer: CHECK -> LENGTH -> DONE */ /* state maintained between inflate() calls. Approximately 10K bytes. */ struct inflate_state { inflate_mode mode; /* current inflate mode */ int last; /* true if processing last block */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ int havedict; /* true if dictionary provided */ int flags; /* gzip header method and flags (0 if zlib) */ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ unsigned long check; /* protected copy of check value */ unsigned long total; /* protected copy of output count */ gz_headerp head; /* where to save gzip header information */ /* sliding window */ unsigned wbits; /* log base 2 of requested window size */ unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned wnext; /* window write index */ unsigned char *window; /* allocated sliding window, if needed */ /* bit accumulator */ unsigned long hold; /* input bit accumulator */ unsigned bits; /* number of bits in "in" */ /* for string and stored block copying */ unsigned length; /* literal or length of data to copy */ unsigned offset; /* distance back to copy string from */ /* for table and code decoding */ unsigned extra; /* extra bits needed */ /* fixed and dynamic code tables */ code const *lencode; /* starting table for length/literal codes */ code const *distcode; /* starting table for distance codes */ unsigned lenbits; /* index bits for lencode */ unsigned distbits; /* index bits for distcode */ /* dynamic table building */ unsigned ncode; /* number of code length code lengths */ unsigned nlen; /* number of length code lengths */ unsigned ndist; /* number of distance code lengths */ unsigned have; /* number of code lengths in lens[] */ code *next; /* next available space in codes[] */ unsigned short lens[320]; /* temporary storage for code lengths */ unsigned short work[288]; /* work area for code table building */ code codes[ENOUGH]; /* space for code tables */ int sane; /* if false, allow invalid distance too far */ int back; /* bits back of last unprocessed length/lit */ unsigned was; /* initial length of match */ }; /* eof */ Rglpk/src/GLPK/zlib/gzwrite.c0000644000176000001440000003055212245352174015516 0ustar ripleyusers/* gzwrite.c */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* gzwrite.c -- zlib functions for writing gzip files * Copyright (C) 2004, 2005, 2010, 2011, 2012 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* Local functions */ static int gz_init (gz_statep); static int gz_comp (gz_statep, int); static int gz_zero (gz_statep, z_off64_t); /* Initialize state for writing a gzip file. Mark initialization by setting state->size to non-zero. Return -1 on failure or 0 on success. */ static int gz_init(gz_statep state) { int ret; z_streamp strm = &(state->strm); /* allocate input buffer */ state->in = malloc(state->want); if (state->in == NULL) { gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } /* only need output buffer and deflate state if compressing */ if (!state->direct) { /* allocate output buffer */ state->out = malloc(state->want); if (state->out == NULL) { free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } /* allocate deflate memory, set up for gzip compression */ strm->zalloc = Z_NULL; strm->zfree = Z_NULL; strm->opaque = Z_NULL; ret = deflateInit2(strm, state->level, Z_DEFLATED, MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); if (ret != Z_OK) { free(state->out); free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } } /* mark state as initialized */ state->size = state->want; /* initialize write buffer if compressing */ if (!state->direct) { strm->avail_out = state->size; strm->next_out = state->out; state->x.next = strm->next_out; } return 0; } /* Compress whatever is at avail_in and next_in and write to the output file. Return -1 if there is an error writing to the output file, otherwise 0. flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, then the deflate() state is reset to start a new gzip stream. If gz->direct is true, then simply write to the output file without compressing, and ignore flush. */ static int gz_comp(gz_statep state, int flush) { int ret, got; unsigned have; z_streamp strm = &(state->strm); /* allocate memory if this is the first time through */ if (state->size == 0 && gz_init(state) == -1) return -1; /* write directly if requested */ if (state->direct) { got = write(state->fd, strm->next_in, strm->avail_in); if (got < 0 || (unsigned)got != strm->avail_in) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } strm->avail_in = 0; return 0; } /* run deflate() on provided input until it produces no more output */ ret = Z_OK; do { /* write out current buffer contents if full, or if flushing, but if doing Z_FINISH then don't write until we get to Z_STREAM_END */ if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && (flush != Z_FINISH || ret == Z_STREAM_END))) { have = (unsigned)(strm->next_out - state->x.next); if (have && ((got = write(state->fd, state->x.next, have)) < 0 || (unsigned)got != have)) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } if (strm->avail_out == 0) { strm->avail_out = state->size; strm->next_out = state->out; } state->x.next = strm->next_out; } /* compress */ have = strm->avail_out; ret = deflate(strm, flush); if (ret == Z_STREAM_ERROR) { gz_error(state, Z_STREAM_ERROR, "internal error: deflate stream corrupt"); return -1; } have -= strm->avail_out; } while (have); /* if that completed a deflate stream, allow another to start */ if (flush == Z_FINISH) deflateReset(strm); /* all done, no errors */ return 0; } /* Compress len zeros to output. Return -1 on error, 0 on success. */ static int gz_zero(gz_statep state, z_off64_t len) { int first; unsigned n; z_streamp strm = &(state->strm); /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return -1; /* compress len zeros (len guaranteed > 0) */ first = 1; while (len) { n = GT_OFF(state->size) || (z_off64_t)state->size > len ? (unsigned)len : state->size; if (first) { memset(state->in, 0, n); first = 0; } strm->avail_in = n; strm->next_in = state->in; state->x.pos += n; if (gz_comp(state, Z_NO_FLUSH) == -1) return -1; len -= n; } return 0; } /* -- see zlib.h -- */ int gzwrite(gzFile file, voidpc buf, unsigned len) { unsigned put = len; unsigned n; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return 0; /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids the flaw in the interface) */ if ((int)len < 0) { gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); return 0; } /* if len is zero, avoid unnecessary operations */ if (len == 0) return 0; /* allocate memory if this is the first time through */ if (state->size == 0 && gz_init(state) == -1) return 0; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return 0; } /* for small len, copy to input buffer, otherwise compress directly */ if (len < state->size) { /* copy to input buffer, compress when full */ do { if (strm->avail_in == 0) strm->next_in = state->in; n = state->size - strm->avail_in; if (n > len) n = len; memcpy(strm->next_in + strm->avail_in, buf, n); strm->avail_in += n; state->x.pos += n; buf = (char *)buf + n; len -= n; if (len && gz_comp(state, Z_NO_FLUSH) == -1) return 0; } while (len); } else { /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* directly compress user buffer to file */ strm->avail_in = len; strm->next_in = (voidp)buf; state->x.pos += len; if (gz_comp(state, Z_NO_FLUSH) == -1) return 0; } /* input was all buffered or compressed (put will fit in int) */ return (int)put; } /* -- see zlib.h -- */ int gzputc(gzFile file, int c) { unsigned char buf[1]; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return -1; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return -1; } /* try writing to input buffer for speed (state->size == 0 if buffer not initialized) */ if (strm->avail_in < state->size) { if (strm->avail_in == 0) strm->next_in = state->in; strm->next_in[strm->avail_in++] = c; state->x.pos++; return c & 0xff; } /* no room in buffer or not initialized, use gz_write() */ buf[0] = c; if (gzwrite(file, buf, 1) != 1) return -1; return c & 0xff; } /* -- see zlib.h -- */ int gzputs(gzFile file, const char *str) { int ret; unsigned len; /* write string */ len = (unsigned)strlen(str); ret = gzwrite(file, str, len); return ret == 0 && len != 0 ? -1 : ret; } /* -- see zlib.h -- */ int gzprintf(gzFile file, const char *format, ...) { int size, len; gz_statep state; z_streamp strm; va_list va; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return 0; /* make sure we have some buffer space */ if (state->size == 0 && gz_init(state) == -1) return 0; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return 0; } /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* do the printf() into the input buffer, put length in len */ size = (int)(state->size); state->in[size - 1] = 0; va_start(va, format); len = vsprintf((char *)(state->in), format, va); va_end(va); /* check that printf() results fit in buffer */ if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) return 0; /* update buffer and position, defer compression until needed */ strm->avail_in = (unsigned)len; strm->next_in = state->in; state->x.pos += len; return len; } /* -- see zlib.h -- */ int gzflush(gzFile file, int flush) { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* check flush parameter */ if (flush < 0 || flush > Z_FINISH) return Z_STREAM_ERROR; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return -1; } /* compress remaining data with requested flush */ gz_comp(state, flush); return state->err; } /* -- see zlib.h -- */ int gzsetparams(gzFile file, int level, int strategy) { gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* if no change is requested, then do nothing */ if (level == state->level && strategy == state->strategy) return Z_OK; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return -1; } /* change compression parameters for subsequent input */ if (state->size) { /* flush previous input with previous parameters before changing */ if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1) return state->err; deflateParams(strm, level, strategy); } state->level = level; state->strategy = strategy; return Z_OK; } /* -- see zlib.h -- */ int gzclose_w(gzFile file) { int ret = Z_OK; gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; /* check that we're writing */ if (state->mode != GZ_WRITE) return Z_STREAM_ERROR; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) ret = state->err; } /* flush, free memory, and close file */ if (state->size) { if (gz_comp(state, Z_FINISH) == -1) ret = state->err; if (!state->direct) { (void)deflateEnd(&(state->strm)); free(state->out); } free(state->in); } gz_error(state, Z_OK, NULL); free(state->path); if (close(state->fd) == -1) ret = Z_ERRNO; free(state); return ret; } /* eof */ Rglpk/src/GLPK/zlib/inffast.c0000644000176000001440000003230712245352174015455 0ustar ripleyusers/* inffast.c */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* inffast.c -- fast decoding * Copyright (C) 1995-2008, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" /* Allow machine dependent optimization for post-increment or pre-increment. Based on testing to date, Pre-increment preferred for: - PowerPC G3 (Adler) - MIPS R5000 (Randers-Pehrson) Post-increment preferred for: - none No measurable difference: - Pentium III (Anderson) - M68060 (Nikl) */ #ifdef POSTINC # define OFF 0 # define PUP(a) *(a)++ #else # define OFF 1 # define PUP(a) *++(a) #endif /* Decode literal, length, and distance codes and write out the resulting literal and match bytes until either not enough input or output is available, an end-of-block is encountered, or a data error is encountered. When large enough input and output buffers are supplied to inflate(), for example, a 16K input buffer and a 64K output buffer, more than 95% of the inflate execution time is spent in this routine. Entry assumptions: state->mode == LEN strm->avail_in >= 6 strm->avail_out >= 258 start >= strm->avail_out state->bits < 8 On return, state->mode is one of: LEN -- ran out of enough output space or enough available input TYPE -- reached end of block code, inflate() to interpret next block BAD -- error in block data Notes: - The maximum input bits used by a length/distance pair is 15 bits for the length code, 5 bits for the length extra, 15 bits for the distance code, and 13 bits for the distance extra. This totals 48 bits, or six bytes. Therefore if strm->avail_in >= 6, then there is enough input to avoid checking for available input while decoding. - The maximum bytes that a single length/distance pair can output is 258 bytes, which is the maximum length that can be coded. inflate_fast() requires strm->avail_out >= 258 for each loop to avoid checking for output space. */ void inflate_fast(z_streamp strm, unsigned start) /* start = inflate()'s starting value for strm->avail_out */ { struct inflate_state *state; unsigned char *in; /* local strm->next_in */ unsigned char *last; /* while in < last, enough input available */ unsigned char *out; /* local strm->next_out */ unsigned char *beg; /* inflate()'s initial strm->next_out */ unsigned char *end; /* while out < end, enough space available */ #ifdef INFLATE_STRICT unsigned dmax; /* maximum distance from zlib header */ #endif unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned wnext; /* window write index */ unsigned char *window; /* allocated sliding window, if wsize != 0 */ unsigned long hold; /* local strm->hold */ unsigned bits; /* local strm->bits */ code const *lcode; /* local strm->lencode */ code const *dcode; /* local strm->distcode */ unsigned lmask; /* mask for first level of length codes */ unsigned dmask; /* mask for first level of distance codes */ code here; /* retrieved table entry */ unsigned op; /* code bits, operation, extra bits, or */ /* window position, window bytes to copy */ unsigned len; /* match length, unused bytes */ unsigned dist; /* match distance */ unsigned char *from; /* where to copy match from */ /* copy state to local variables */ state = (struct inflate_state *)strm->state; in = strm->next_in - OFF; last = in + (strm->avail_in - 5); out = strm->next_out - OFF; beg = out - (start - strm->avail_out); end = out + (strm->avail_out - 257); #ifdef INFLATE_STRICT dmax = state->dmax; #endif wsize = state->wsize; whave = state->whave; wnext = state->wnext; window = state->window; hold = state->hold; bits = state->bits; lcode = state->lencode; dcode = state->distcode; lmask = (1U << state->lenbits) - 1; dmask = (1U << state->distbits) - 1; /* decode literals and length/distances until end-of-block or not enough input data or output space */ do { if (bits < 15) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; hold += (unsigned long)(PUP(in)) << bits; bits += 8; } here = lcode[hold & lmask]; dolen: op = (unsigned)(here.bits); hold >>= op; bits -= op; op = (unsigned)(here.op); if (op == 0) { /* literal */ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); PUP(out) = (unsigned char)(here.val); } else if (op & 16) { /* length base */ len = (unsigned)(here.val); op &= 15; /* number of extra bits */ if (op) { if (bits < op) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; } len += (unsigned)hold & ((1U << op) - 1); hold >>= op; bits -= op; } Tracevv((stderr, "inflate: length %u\n", len)); if (bits < 15) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; hold += (unsigned long)(PUP(in)) << bits; bits += 8; } here = dcode[hold & dmask]; dodist: op = (unsigned)(here.bits); hold >>= op; bits -= op; op = (unsigned)(here.op); if (op & 16) { /* distance base */ dist = (unsigned)(here.val); op &= 15; /* number of extra bits */ if (bits < op) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; if (bits < op) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; } } dist += (unsigned)hold & ((1U << op) - 1); #ifdef INFLATE_STRICT if (dist > dmax) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #endif hold >>= op; bits -= op; Tracevv((stderr, "inflate: distance %u\n", dist)); op = (unsigned)(out - beg); /* max distance in output */ if (dist > op) { /* see if copy from window */ op = dist - op; /* distance back in window */ if (op > whave) { if (state->sane) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR if (len <= op - whave) { do { PUP(out) = 0; } while (--len); continue; } len -= op - whave; do { PUP(out) = 0; } while (--op > whave); if (op == 0) { from = out - dist; do { PUP(out) = PUP(from); } while (--len); continue; } #endif } from = window - OFF; if (wnext == 0) { /* very common case */ from += wsize - op; if (op < len) { /* some from window */ len -= op; do { PUP(out) = PUP(from); } while (--op); from = out - dist; /* rest from output */ } } else if (wnext < op) { /* wrap around window */ from += wsize + wnext - op; op -= wnext; if (op < len) { /* some from end of window */ len -= op; do { PUP(out) = PUP(from); } while (--op); from = window - OFF; if (wnext < len) { /* some from start of window */ op = wnext; len -= op; do { PUP(out) = PUP(from); } while (--op); from = out - dist; /* rest from output */ } } } else { /* contiguous in window */ from += wnext - op; if (op < len) { /* some from window */ len -= op; do { PUP(out) = PUP(from); } while (--op); from = out - dist; /* rest from output */ } } while (len > 2) { PUP(out) = PUP(from); PUP(out) = PUP(from); PUP(out) = PUP(from); len -= 3; } if (len) { PUP(out) = PUP(from); if (len > 1) PUP(out) = PUP(from); } } else { from = out - dist; /* copy direct from output */ do { /* minimum length is three */ PUP(out) = PUP(from); PUP(out) = PUP(from); PUP(out) = PUP(from); len -= 3; } while (len > 2); if (len) { PUP(out) = PUP(from); if (len > 1) PUP(out) = PUP(from); } } } else if ((op & 64) == 0) { /* 2nd level distance code */ here = dcode[here.val + (hold & ((1U << op) - 1))]; goto dodist; } else { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } } else if ((op & 64) == 0) { /* 2nd level length code */ here = lcode[here.val + (hold & ((1U << op) - 1))]; goto dolen; } else if (op & 32) { /* end-of-block */ Tracevv((stderr, "inflate: end of block\n")); state->mode = TYPE; break; } else { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } } while (in < last && out < end); /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ len = bits >> 3; in -= len; bits -= len << 3; hold &= (1U << bits) - 1; /* update state and return */ strm->next_in = in + OFF; strm->next_out = out + OFF; strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); strm->avail_out = (unsigned)(out < end ? 257 + (end - out) : 257 - (out - end)); state->hold = hold; state->bits = bits; return; } /* inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - Using bit fields for code structure - Different op definition to avoid & for extra bits (do & for table bits) - Three separate decoding do-loops for direct, window, and wnext == 0 - Special case for distance > 1 copies to do overlapped load and store copy - Explicit branch predictions (based on measured branch probabilities) - Deferring match copy and interspersed it with decoding subsequent codes - Swapping literal/length else - Swapping window/direct else - Larger unrolled copy loops (three is about right) - Moving len -= 3 statement into middle of loop */ /* eof */ Rglpk/src/GLPK/zlib/inflate.c0000644000176000001440000014663212245352174015454 0ustar ripleyusers/* inflate.c */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* inflate.c -- zlib decompression * Copyright (C) 1995-2012 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * Change history: * * 1.2.beta0 24 Nov 2002 * - First version -- complete rewrite of inflate to simplify code, avoid * creation of window when not needed, minimize use of window when it is * needed, make inffast.c even faster, implement gzip decoding, and to * improve code readability and style over the previous zlib inflate code * * 1.2.beta1 25 Nov 2002 * - Use pointers for available input and output checking in inffast.c * - Remove input and output counters in inffast.c * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 * - Remove unnecessary second byte pull from length extra in inffast.c * - Unroll direct copy to three copies per loop in inffast.c * * 1.2.beta2 4 Dec 2002 * - Change external routine names to reduce potential conflicts * - Correct filename to inffixed.h for fixed tables in inflate.c * - Make hbuf[] unsigned char to match parameter type in inflate.c * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) * to avoid negation problem on Alphas (64 bit) in inflate.c * * 1.2.beta3 22 Dec 2002 * - Add comments on state->bits assertion in inffast.c * - Add comments on op field in inftrees.h * - Fix bug in reuse of allocated window after inflateReset() * - Remove bit fields--back to byte structure for speed * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths * - Change post-increments to pre-increments in inflate_fast(), PPC biased? * - Add compile time option, POSTINC, to use post-increments instead (Intel?) * - Make MATCH copy in inflate() much faster for when inflate_fast() not used * - Use local copies of stream next and avail values, as well as local bit * buffer and bit count in inflate()--for speed when inflate_fast() not used * * 1.2.beta4 1 Jan 2003 * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings * - Move a comment on output buffer sizes from inffast.c to inflate.c * - Add comments in inffast.c to introduce the inflate_fast() routine * - Rearrange window copies in inflate_fast() for speed and simplification * - Unroll last copy for window match in inflate_fast() * - Use local copies of window variables in inflate_fast() for speed * - Pull out common wnext == 0 case for speed in inflate_fast() * - Make op and len in inflate_fast() unsigned for consistency * - Add FAR to lcode and dcode declarations in inflate_fast() * - Simplified bad distance check in inflate_fast() * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new * source file infback.c to provide a call-back interface to inflate for * programs like gzip and unzip -- uses window as output buffer to avoid * window copying * * 1.2.beta5 1 Jan 2003 * - Improved inflateBack() interface to allow the caller to provide initial * input in strm. * - Fixed stored blocks bug in inflateBack() * * 1.2.beta6 4 Jan 2003 * - Added comments in inffast.c on effectiveness of POSTINC * - Typecasting all around to reduce compiler warnings * - Changed loops from while (1) or do {} while (1) to for (;;), again to * make compilers happy * - Changed type of window in inflateBackInit() to unsigned char * * * 1.2.beta7 27 Jan 2003 * - Changed many types to unsigned or unsigned short to avoid warnings * - Added inflateCopy() function * * 1.2.0 9 Mar 2003 * - Changed inflateBack() interface to provide separate opaque descriptors * for the in() and out() functions * - Changed inflateBack() argument and in_func typedef to swap the length * and buffer address return values for the input function * - Check next_in and next_out for Z_NULL on entry to inflate() * * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" #ifdef MAKEFIXED # ifndef BUILDFIXED # define BUILDFIXED # endif #endif /* function prototypes */ static void fixedtables(struct inflate_state *state); static int updatewindow(z_streamp strm, unsigned out); #ifdef BUILDFIXED void makefixed(void); #endif static unsigned syncsearch(unsigned *have, unsigned char *buf, unsigned len); int inflateResetKeep(z_streamp strm) { struct inflate_state *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state *)strm->state; strm->total_in = strm->total_out = state->total = 0; strm->msg = Z_NULL; if (state->wrap) /* to support ill-conceived Java test suite */ strm->adler = state->wrap & 1; state->mode = HEAD; state->last = 0; state->havedict = 0; state->dmax = 32768U; state->head = Z_NULL; state->hold = 0; state->bits = 0; state->lencode = state->distcode = state->next = state->codes; state->sane = 1; state->back = -1; Tracev((stderr, "inflate: reset\n")); return Z_OK; } int inflateReset(z_streamp strm) { struct inflate_state *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state *)strm->state; state->wsize = 0; state->whave = 0; state->wnext = 0; return inflateResetKeep(strm); } int inflateReset2(z_streamp strm, int windowBits) { int wrap; struct inflate_state *state; /* get the state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state *)strm->state; /* extract wrap request from windowBits parameter */ if (windowBits < 0) { wrap = 0; windowBits = -windowBits; } else { wrap = (windowBits >> 4) + 1; #ifdef GUNZIP if (windowBits < 48) windowBits &= 15; #endif } /* set number of window bits, free window if different */ if (windowBits && (windowBits < 8 || windowBits > 15)) return Z_STREAM_ERROR; if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { ZFREE(strm, state->window); state->window = Z_NULL; } /* update state and reset the rest of it */ state->wrap = wrap; state->wbits = (unsigned)windowBits; return inflateReset(strm); } int inflateInit2_(z_streamp strm, int windowBits, const char *version, int stream_size) { int ret; struct inflate_state *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR; if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; /* in case we return an error */ if (strm->zalloc == (alloc_func)0) { #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; #endif } if (strm->zfree == (free_func)0) #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zfree = zcfree; #endif state = (struct inflate_state *) ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state *)state; state->window = Z_NULL; ret = inflateReset2(strm, windowBits); if (ret != Z_OK) { ZFREE(strm, state); strm->state = Z_NULL; } return ret; } int inflateInit_(z_streamp strm, const char *version, int stream_size) { return inflateInit2_(strm, DEF_WBITS, version, stream_size); } int inflatePrime(z_streamp strm, int bits, int value) { struct inflate_state *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state *)strm->state; if (bits < 0) { state->hold = 0; state->bits = 0; return Z_OK; } if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; value &= (1L << bits) - 1; state->hold += value << state->bits; state->bits += bits; return Z_OK; } /* Return state with length and distance decoding tables and index sizes set to fixed code decoding. Normally this returns fixed tables from inffixed.h. If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ static void fixedtables(struct inflate_state *state) { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; static code fixed[544]; /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { unsigned sym, bits; static code *next; /* literal/length table */ sym = 0; while (sym < 144) state->lens[sym++] = 8; while (sym < 256) state->lens[sym++] = 9; while (sym < 280) state->lens[sym++] = 7; while (sym < 288) state->lens[sym++] = 8; next = fixed; lenfix = next; bits = 9; inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); /* distance table */ sym = 0; while (sym < 32) state->lens[sym++] = 5; distfix = next; bits = 5; inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); /* do this just once */ virgin = 0; } #else /* !BUILDFIXED */ # include "inffixed.h" #endif /* BUILDFIXED */ state->lencode = lenfix; state->lenbits = 9; state->distcode = distfix; state->distbits = 5; } #ifdef MAKEFIXED #include /* Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also defines BUILDFIXED, so the tables are built on the fly. makefixed() writes those tables to stdout, which would be piped to inffixed.h. A small program can simply call makefixed to do this: void makefixed(void); int main(void) { makefixed(); return 0; } Then that can be linked with zlib built with MAKEFIXED defined and run: a.out > inffixed.h */ void makefixed(void) { unsigned low, size; struct inflate_state state; fixedtables(&state); puts(" /* inffixed.h -- table for decoding fixed codes"); puts(" * Generated automatically by makefixed()."); puts(" */"); puts(""); puts(" /* WARNING: this file should *not* be used by applications."); puts(" It is part of the implementation of this library and is"); puts(" subject to change. Applications should only use zlib.h."); puts(" */"); puts(""); size = 1U << 9; printf(" static const code lenfix[%u] = {", size); low = 0; for (;;) { if ((low % 7) == 0) printf("\n "); printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, state.lencode[low].bits, state.lencode[low].val); if (++low == size) break; putchar(','); } puts("\n };"); size = 1U << 5; printf("\n static const code distfix[%u] = {", size); low = 0; for (;;) { if ((low % 6) == 0) printf("\n "); printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, state.distcode[low].val); if (++low == size) break; putchar(','); } puts("\n };"); } #endif /* MAKEFIXED */ /* Update the window with the last wsize (normally 32K) bytes written before returning. If window does not exist yet, create it. This is only called when a window is already in use, or when output has been written during this inflate call, but the end of the deflate stream has not been reached yet. It is also called to create a window for dictionary data when a dictionary is loaded. Providing output buffers larger than 32K to inflate() should provide a speed advantage, since only the last 32K of output is copied to the sliding window upon return from inflate(), and since all distances after the first 32K of output will fall in the output data, making match copies simpler and faster. The advantage may be dependent on the size of the processor's data caches. */ static int updatewindow(z_streamp strm, unsigned out) { struct inflate_state *state; unsigned copy, dist; state = (struct inflate_state *)strm->state; /* if it hasn't been done already, allocate space for the window */ if (state->window == Z_NULL) { state->window = (unsigned char *) ZALLOC(strm, 1U << state->wbits, sizeof(unsigned char)); if (state->window == Z_NULL) return 1; } /* if window not in use yet, initialize */ if (state->wsize == 0) { state->wsize = 1U << state->wbits; state->wnext = 0; state->whave = 0; } /* copy state->wsize or less output bytes into the circular window */ copy = out - strm->avail_out; if (copy >= state->wsize) { zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); state->wnext = 0; state->whave = state->wsize; } else { dist = state->wsize - state->wnext; if (dist > copy) dist = copy; zmemcpy(state->window + state->wnext, strm->next_out - copy, dist); copy -= dist; if (copy) { zmemcpy(state->window, strm->next_out - copy, copy); state->wnext = copy; state->whave = state->wsize; } else { state->wnext += dist; if (state->wnext == state->wsize) state->wnext = 0; if (state->whave < state->wsize) state->whave += dist; } } return 0; } /* Macros for inflate(): */ /* check function to use adler32() for zlib or crc32() for gzip */ #ifdef GUNZIP # define UPDATE(check, buf, len) \ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) #else # define UPDATE(check, buf, len) adler32(check, buf, len) #endif /* check macros for header crc */ #ifdef GUNZIP # define CRC2(check, word) \ do { \ hbuf[0] = (unsigned char)(word); \ hbuf[1] = (unsigned char)((word) >> 8); \ check = crc32(check, hbuf, 2); \ } while (0) # define CRC4(check, word) \ do { \ hbuf[0] = (unsigned char)(word); \ hbuf[1] = (unsigned char)((word) >> 8); \ hbuf[2] = (unsigned char)((word) >> 16); \ hbuf[3] = (unsigned char)((word) >> 24); \ check = crc32(check, hbuf, 4); \ } while (0) #endif /* Load registers with state in inflate() for speed */ #define LOAD() \ do { \ put = strm->next_out; \ left = strm->avail_out; \ next = strm->next_in; \ have = strm->avail_in; \ hold = state->hold; \ bits = state->bits; \ } while (0) /* Restore state from registers in inflate() */ #define RESTORE() \ do { \ strm->next_out = put; \ strm->avail_out = left; \ strm->next_in = next; \ strm->avail_in = have; \ state->hold = hold; \ state->bits = bits; \ } while (0) /* Clear the input bit accumulator */ #define INITBITS() \ do { \ hold = 0; \ bits = 0; \ } while (0) /* Get a byte of input into the bit accumulator, or return from inflate() if there is no input available. */ #define PULLBYTE() \ do { \ if (have == 0) goto inf_leave; \ have--; \ hold += (unsigned long)(*next++) << bits; \ bits += 8; \ } while (0) /* Assure that there are at least n bits in the bit accumulator. If there is not enough available input to do that, then return from inflate(). */ #define NEEDBITS(n) \ do { \ while (bits < (unsigned)(n)) \ PULLBYTE(); \ } while (0) /* Return the low n bits of the bit accumulator (n < 16) */ #define BITS(n) \ ((unsigned)hold & ((1U << (n)) - 1)) /* Remove n bits from the bit accumulator */ #define DROPBITS(n) \ do { \ hold >>= (n); \ bits -= (unsigned)(n); \ } while (0) /* Remove zero to seven bits as needed to go to a byte boundary */ #define BYTEBITS() \ do { \ hold >>= bits & 7; \ bits -= bits & 7; \ } while (0) /* inflate() uses a state machine to process as much input data and generate as much output data as possible before returning. The state machine is structured roughly as follows: for (;;) switch (state) { ... case STATEn: if (not enough input data or output space to make progress) return; ... make progress ... state = STATEm; break; ... } so when inflate() is called again, the same case is attempted again, and if the appropriate resources are provided, the machine proceeds to the next state. The NEEDBITS() macro is usually the way the state evaluates whether it can proceed or should return. NEEDBITS() does the return if the requested bits are not available. The typical use of the BITS macros is: NEEDBITS(n); ... do something with BITS(n) ... DROPBITS(n); where NEEDBITS(n) either returns from inflate() if there isn't enough input left to load n bits into the accumulator, or it continues. BITS(n) gives the low n bits in the accumulator. When done, DROPBITS(n) drops the low n bits off the accumulator. INITBITS() clears the accumulator and sets the number of available bits to zero. BYTEBITS() discards just enough bits to put the accumulator on a byte boundary. After BYTEBITS() and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return if there is no input available. The decoding of variable length codes uses PULLBYTE() directly in order to pull just enough bytes to decode the next code, and no more. Some states loop until they get enough input, making sure that enough state information is maintained to continue the loop where it left off if NEEDBITS() returns in the loop. For example, want, need, and keep would all have to actually be part of the saved state in case NEEDBITS() returns: case STATEw: while (want < need) { NEEDBITS(n); keep[want++] = BITS(n); DROPBITS(n); } state = STATEx; case STATEx: As shown above, if the next state is also the next case, then the break is omitted. A state may also return if there is not enough output space available to complete that state. Those states are copying stored data, writing a literal byte, and copying a matching string. When returning, a "goto inf_leave" is used to update the total counters, update the check value, and determine whether any progress has been made during that inflate() call in order to return the proper return code. Progress is defined as a change in either strm->avail_in or strm->avail_out. When there is a window, goto inf_leave will update the window with the last output written. If a goto inf_leave occurs in the middle of decompression and there is no window currently, goto inf_leave will create one and copy output to the window for the next call of inflate(). In this implementation, the flush parameter of inflate() only affects the return code (per zlib.h). inflate() always writes as much as possible to strm->next_out, given the space available and the provided input--the effect documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers the allocation of and copying into a sliding window until necessary, which provides the effect documented in zlib.h for Z_FINISH when the entire input stream available. So the only thing the flush parameter actually does is: when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it will return Z_BUF_ERROR if it has not reached the end of the stream. */ int inflate(z_streamp strm, int flush) { struct inflate_state *state; unsigned char *next; /* next input */ unsigned char *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ unsigned bits; /* bits in bit buffer */ unsigned in, out; /* save starting available input and output */ unsigned copy; /* number of stored or match bytes to copy */ unsigned char *from; /* where to copy match bytes from */ code here; /* current decoding table entry */ code last; /* parent table entry */ unsigned len; /* length to copy for repeats, bits to drop */ int ret; /* return code */ #ifdef GUNZIP unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ #endif static const unsigned short order[19] = /* permutation of code lengths */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || (strm->next_in == Z_NULL && strm->avail_in != 0)) return Z_STREAM_ERROR; state = (struct inflate_state *)strm->state; if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ LOAD(); in = have; out = left; ret = Z_OK; for (;;) switch (state->mode) { case HEAD: if (state->wrap == 0) { state->mode = TYPEDO; break; } NEEDBITS(16); #ifdef GUNZIP if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ state->check = crc32(0L, Z_NULL, 0); CRC2(state->check, hold); INITBITS(); state->mode = FLAGS; break; } state->flags = 0; /* expect zlib header */ if (state->head != Z_NULL) state->head->done = -1; if (!(state->wrap & 1) || /* check if zlib header allowed */ #else if ( #endif ((BITS(8) << 8) + (hold >> 8)) % 31) { strm->msg = (char *)"incorrect header check"; state->mode = BAD; break; } if (BITS(4) != Z_DEFLATED) { strm->msg = (char *)"unknown compression method"; state->mode = BAD; break; } DROPBITS(4); len = BITS(4) + 8; if (state->wbits == 0) state->wbits = len; else if (len > state->wbits) { strm->msg = (char *)"invalid window size"; state->mode = BAD; break; } state->dmax = 1U << len; Tracev((stderr, "inflate: zlib header ok\n")); strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = hold & 0x200 ? DICTID : TYPE; INITBITS(); break; #ifdef GUNZIP case FLAGS: NEEDBITS(16); state->flags = (int)(hold); if ((state->flags & 0xff) != Z_DEFLATED) { strm->msg = (char *)"unknown compression method"; state->mode = BAD; break; } if (state->flags & 0xe000) { strm->msg = (char *)"unknown header flags set"; state->mode = BAD; break; } if (state->head != Z_NULL) state->head->text = (int)((hold >> 8) & 1); if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); state->mode = TIME; case TIME: NEEDBITS(32); if (state->head != Z_NULL) state->head->time = hold; if (state->flags & 0x0200) CRC4(state->check, hold); INITBITS(); state->mode = OS; case OS: NEEDBITS(16); if (state->head != Z_NULL) { state->head->xflags = (int)(hold & 0xff); state->head->os = (int)(hold >> 8); } if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); state->mode = EXLEN; case EXLEN: if (state->flags & 0x0400) { NEEDBITS(16); state->length = (unsigned)(hold); if (state->head != Z_NULL) state->head->extra_len = (unsigned)hold; if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); } else if (state->head != Z_NULL) state->head->extra = Z_NULL; state->mode = EXTRA; case EXTRA: if (state->flags & 0x0400) { copy = state->length; if (copy > have) copy = have; if (copy) { if (state->head != Z_NULL && state->head->extra != Z_NULL) { len = state->head->extra_len - state->length; zmemcpy(state->head->extra + len, next, len + copy > state->head->extra_max ? state->head->extra_max - len : copy); } if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; next += copy; state->length -= copy; } if (state->length) goto inf_leave; } state->length = 0; state->mode = NAME; case NAME: if (state->flags & 0x0800) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && state->head->name != Z_NULL && state->length < state->head->name_max) state->head->name[state->length++] = len; } while (len && copy < have); if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->name = Z_NULL; state->length = 0; state->mode = COMMENT; case COMMENT: if (state->flags & 0x1000) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && state->head->comment != Z_NULL && state->length < state->head->comm_max) state->head->comment[state->length++] = len; } while (len && copy < have); if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->comment = Z_NULL; state->mode = HCRC; case HCRC: if (state->flags & 0x0200) { NEEDBITS(16); if (hold != (state->check & 0xffff)) { strm->msg = (char *)"header crc mismatch"; state->mode = BAD; break; } INITBITS(); } if (state->head != Z_NULL) { state->head->hcrc = (int)((state->flags >> 9) & 1); state->head->done = 1; } strm->adler = state->check = crc32(0L, Z_NULL, 0); state->mode = TYPE; break; #endif case DICTID: NEEDBITS(32); strm->adler = state->check = ZSWAP32(hold); INITBITS(); state->mode = DICT; case DICT: if (state->havedict == 0) { RESTORE(); return Z_NEED_DICT; } strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = TYPE; case TYPE: if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; case TYPEDO: if (state->last) { BYTEBITS(); state->mode = CHECK; break; } NEEDBITS(3); state->last = BITS(1); DROPBITS(1); switch (BITS(2)) { case 0: /* stored block */ Tracev((stderr, "inflate: stored block%s\n", state->last ? " (last)" : "")); state->mode = STORED; break; case 1: /* fixed block */ fixedtables(state); Tracev((stderr, "inflate: fixed codes block%s\n", state->last ? " (last)" : "")); state->mode = LEN_; /* decode codes */ if (flush == Z_TREES) { DROPBITS(2); goto inf_leave; } break; case 2: /* dynamic block */ Tracev((stderr, "inflate: dynamic codes block%s\n", state->last ? " (last)" : "")); state->mode = TABLE; break; case 3: strm->msg = (char *)"invalid block type"; state->mode = BAD; } DROPBITS(2); break; case STORED: BYTEBITS(); /* go to byte boundary */ NEEDBITS(32); if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { strm->msg = (char *)"invalid stored block lengths"; state->mode = BAD; break; } state->length = (unsigned)hold & 0xffff; Tracev((stderr, "inflate: stored length %u\n", state->length)); INITBITS(); state->mode = COPY_; if (flush == Z_TREES) goto inf_leave; case COPY_: state->mode = COPY; case COPY: copy = state->length; if (copy) { if (copy > have) copy = have; if (copy > left) copy = left; if (copy == 0) goto inf_leave; zmemcpy(put, next, copy); have -= copy; next += copy; left -= copy; put += copy; state->length -= copy; break; } Tracev((stderr, "inflate: stored end\n")); state->mode = TYPE; break; case TABLE: NEEDBITS(14); state->nlen = BITS(5) + 257; DROPBITS(5); state->ndist = BITS(5) + 1; DROPBITS(5); state->ncode = BITS(4) + 4; DROPBITS(4); #ifndef PKZIP_BUG_WORKAROUND if (state->nlen > 286 || state->ndist > 30) { strm->msg = (char *)"too many length or distance symbols"; state->mode = BAD; break; } #endif Tracev((stderr, "inflate: table sizes ok\n")); state->have = 0; state->mode = LENLENS; case LENLENS: while (state->have < state->ncode) { NEEDBITS(3); state->lens[order[state->have++]] = (unsigned short)BITS(3); DROPBITS(3); } while (state->have < 19) state->lens[order[state->have++]] = 0; state->next = state->codes; state->lencode = (code const *)(state->next); state->lenbits = 7; ret = inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid code lengths set"; state->mode = BAD; break; } Tracev((stderr, "inflate: code lengths ok\n")); state->have = 0; state->mode = CODELENS; case CODELENS: while (state->have < state->nlen + state->ndist) { for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.val < 16) { DROPBITS(here.bits); state->lens[state->have++] = here.val; } else { if (here.val == 16) { NEEDBITS(here.bits + 2); DROPBITS(here.bits); if (state->have == 0) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } len = state->lens[state->have - 1]; copy = 3 + BITS(2); DROPBITS(2); } else if (here.val == 17) { NEEDBITS(here.bits + 3); DROPBITS(here.bits); len = 0; copy = 3 + BITS(3); DROPBITS(3); } else { NEEDBITS(here.bits + 7); DROPBITS(here.bits); len = 0; copy = 11 + BITS(7); DROPBITS(7); } if (state->have + copy > state->nlen + state->ndist) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } while (copy--) state->lens[state->have++] = (unsigned short)len; } } /* handle error breaks in while */ if (state->mode == BAD) break; /* check for end-of-block code (better have one) */ if (state->lens[256] == 0) { strm->msg = (char *)"invalid code -- missing end-of-block"; state->mode = BAD; break; } /* build code tables -- note: do not change the lenbits or distbits values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state->next = state->codes; state->lencode = (code const *)(state->next); state->lenbits = 9; ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid literal/lengths set"; state->mode = BAD; break; } state->distcode = (code const *)(state->next); state->distbits = 6; ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next), &(state->distbits), state->work); if (ret) { strm->msg = (char *)"invalid distances set"; state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN_; if (flush == Z_TREES) goto inf_leave; case LEN_: state->mode = LEN; case LEN: if (have >= 6 && left >= 258) { RESTORE(); inflate_fast(strm, out); LOAD(); if (state->mode == TYPE) state->back = -1; break; } state->back = 0; for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.op && (here.op & 0xf0) == 0) { last = here; for (;;) { here = state->lencode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); state->back += last.bits; } DROPBITS(here.bits); state->back += here.bits; state->length = (unsigned)here.val; if ((int)(here.op) == 0) { Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); state->mode = LIT; break; } if (here.op & 32) { Tracevv((stderr, "inflate: end of block\n")); state->back = -1; state->mode = TYPE; break; } if (here.op & 64) { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } state->extra = (unsigned)(here.op) & 15; state->mode = LENEXT; case LENEXT: if (state->extra) { NEEDBITS(state->extra); state->length += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } Tracevv((stderr, "inflate: length %u\n", state->length)); state->was = state->length; state->mode = DIST; case DIST: for (;;) { here = state->distcode[BITS(state->distbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if ((here.op & 0xf0) == 0) { last = here; for (;;) { here = state->distcode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); state->back += last.bits; } DROPBITS(here.bits); state->back += here.bits; if (here.op & 64) { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } state->offset = (unsigned)here.val; state->extra = (unsigned)(here.op) & 15; state->mode = DISTEXT; case DISTEXT: if (state->extra) { NEEDBITS(state->extra); state->offset += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } #ifdef INFLATE_STRICT if (state->offset > state->dmax) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #endif Tracevv((stderr, "inflate: distance %u\n", state->offset)); state->mode = MATCH; case MATCH: if (left == 0) goto inf_leave; copy = out - left; if (state->offset > copy) { /* copy from window */ copy = state->offset - copy; if (copy > state->whave) { if (state->sane) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR Trace((stderr, "inflate.c too far\n")); copy -= state->whave; if (copy > state->length) copy = state->length; if (copy > left) copy = left; left -= copy; state->length -= copy; do { *put++ = 0; } while (--copy); if (state->length == 0) state->mode = LEN; break; #endif } if (copy > state->wnext) { copy -= state->wnext; from = state->window + (state->wsize - copy); } else from = state->window + (state->wnext - copy); if (copy > state->length) copy = state->length; } else { /* copy from output */ from = put - state->offset; copy = state->length; } if (copy > left) copy = left; left -= copy; state->length -= copy; do { *put++ = *from++; } while (--copy); if (state->length == 0) state->mode = LEN; break; case LIT: if (left == 0) goto inf_leave; *put++ = (unsigned char)(state->length); left--; state->mode = LEN; break; case CHECK: if (state->wrap) { NEEDBITS(32); out -= left; strm->total_out += out; state->total += out; if (out) strm->adler = state->check = UPDATE(state->check, put - out, out); out = left; if (( #ifdef GUNZIP state->flags ? hold : #endif ZSWAP32(hold)) != state->check) { strm->msg = (char *)"incorrect data check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: check matches trailer\n")); } #ifdef GUNZIP state->mode = LENGTH; case LENGTH: if (state->wrap && state->flags) { NEEDBITS(32); if (hold != (state->total & 0xffffffffUL)) { strm->msg = (char *)"incorrect length check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: length matches trailer\n")); } #endif state->mode = DONE; case DONE: ret = Z_STREAM_END; goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; case MEM: return Z_MEM_ERROR; case SYNC: default: return Z_STREAM_ERROR; } /* Return from inflate(), updating the total counts and the check value. If there was no progress during the inflate() call, return a buffer error. Call updatewindow() to create and/or update the window state. Note: a memory error from inflate() is non-recoverable. */ inf_leave: RESTORE(); if (state->wsize || (out != strm->avail_out && state->mode < BAD && (state->mode < CHECK || flush != Z_FINISH))) if (updatewindow(strm, out)) { state->mode = MEM; return Z_MEM_ERROR; } in -= strm->avail_in; out -= strm->avail_out; strm->total_in += in; strm->total_out += out; state->total += out; if (state->wrap && out) strm->adler = state->check = UPDATE(state->check, strm->next_out - out, out); strm->data_type = state->bits + (state->last ? 64 : 0) + (state->mode == TYPE ? 128 : 0) + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) ret = Z_BUF_ERROR; return ret; } int inflateEnd(z_streamp strm) { struct inflate_state *state; if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR; state = (struct inflate_state *)strm->state; if (state->window != Z_NULL) ZFREE(strm, state->window); ZFREE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } int inflateSetDictionary(z_streamp strm, const Bytef *dictionary, uInt dictLength) { struct inflate_state *state; unsigned long dictid; unsigned char *next; unsigned avail; int ret; /* check state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state *)strm->state; if (state->wrap != 0 && state->mode != DICT) return Z_STREAM_ERROR; /* check for correct dictionary identifier */ if (state->mode == DICT) { dictid = adler32(0L, Z_NULL, 0); dictid = adler32(dictid, dictionary, dictLength); if (dictid != state->check) return Z_DATA_ERROR; } /* copy dictionary to window using updatewindow(), which will amend the existing dictionary if appropriate */ next = strm->next_out; avail = strm->avail_out; strm->next_out = (Bytef *)dictionary + dictLength; strm->avail_out = 0; ret = updatewindow(strm, dictLength); strm->avail_out = avail; strm->next_out = next; if (ret) { state->mode = MEM; return Z_MEM_ERROR; } state->havedict = 1; Tracev((stderr, "inflate: dictionary set\n")); return Z_OK; } int inflateGetHeader(z_streamp strm, gz_headerp head) { struct inflate_state *state; /* check state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state *)strm->state; if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; /* save header structure */ state->head = head; head->done = 0; return Z_OK; } /* Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found or when out of input. When called, *have is the number of pattern bytes found in order so far, in 0..3. On return *have is updated to the new state. If on return *have equals four, then the pattern was found and the return value is how many bytes were read including the last byte of the pattern. If *have is less than four, then the pattern has not been found yet and the return value is len. In the latter case, syncsearch() can be called again with more data and the *have state. *have is initialized to zero for the first call. */ static unsigned syncsearch(unsigned *have, unsigned char *buf, unsigned len) { unsigned got; unsigned next; got = *have; next = 0; while (next < len && got < 4) { if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) got++; else if (buf[next]) got = 0; else got = 4 - got; next++; } *have = got; return next; } int inflateSync(z_streamp strm) { unsigned len; /* number of bytes to look at or looked at */ unsigned long in, out; /* temporary to save total_in and total_out */ unsigned char buf[4]; /* to restore bit buffer to byte string */ struct inflate_state *state; /* check parameters */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state *)strm->state; if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; /* if first time, start search in bit buffer */ if (state->mode != SYNC) { state->mode = SYNC; state->hold <<= state->bits & 7; state->bits -= state->bits & 7; len = 0; while (state->bits >= 8) { buf[len++] = (unsigned char)(state->hold); state->hold >>= 8; state->bits -= 8; } state->have = 0; syncsearch(&(state->have), buf, len); } /* search available input */ len = syncsearch(&(state->have), strm->next_in, strm->avail_in); strm->avail_in -= len; strm->next_in += len; strm->total_in += len; /* return no joy or set up to restart inflate() on a new block */ if (state->have != 4) return Z_DATA_ERROR; in = strm->total_in; out = strm->total_out; inflateReset(strm); strm->total_in = in; strm->total_out = out; state->mode = TYPE; return Z_OK; } /* Returns true if inflate is currently at the end of a block generated by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored block. When decompressing, PPP checks that at the end of input packet, inflate is waiting for these length bytes. */ int inflateSyncPoint(z_streamp strm) { struct inflate_state *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state *)strm->state; return state->mode == STORED && state->bits == 0; } int inflateCopy(z_streamp dest, z_streamp source) { struct inflate_state *state; struct inflate_state *copy; unsigned char *window; unsigned wsize; /* check input */ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) return Z_STREAM_ERROR; state = (struct inflate_state *)source->state; /* allocate space */ copy = (struct inflate_state *) ZALLOC(source, 1, sizeof(struct inflate_state)); if (copy == Z_NULL) return Z_MEM_ERROR; window = Z_NULL; if (state->window != Z_NULL) { window = (unsigned char *) ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); if (window == Z_NULL) { ZFREE(source, copy); return Z_MEM_ERROR; } } /* copy state */ zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); if (state->lencode >= state->codes && state->lencode <= state->codes + ENOUGH - 1) { copy->lencode = copy->codes + (state->lencode - state->codes); copy->distcode = copy->codes + (state->distcode - state->codes); } copy->next = copy->codes + (state->next - state->codes); if (window != Z_NULL) { wsize = 1U << state->wbits; zmemcpy(window, state->window, wsize); } copy->window = window; dest->state = (struct internal_state *)copy; return Z_OK; } int inflateUndermine(z_streamp strm, int subvert) { struct inflate_state *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state *)strm->state; state->sane = !subvert; #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR return Z_OK; #else state->sane = 1; return Z_DATA_ERROR; #endif } long inflateMark(z_streamp strm) { struct inflate_state *state; if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16; state = (struct inflate_state *)strm->state; return ((long)(state->back) << 16) + (state->mode == COPY ? state->length : (state->mode == MATCH ? state->was - state->length : 0)); } /* eof */ Rglpk/src/GLPK/zlib/zutil.c0000644000176000001440000000605012245352174015166 0ustar ripleyusers/* zutil.c */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* zutil.c -- target dependent utility functions for the compression library * Copyright (C) 1995-2005, 2010, 2011, 2012 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #ifndef Z_SOLO # include "gzguts.h" #endif const char * const z_errmsg[10] = { "need dictionary", /* Z_NEED_DICT 2 */ "stream end", /* Z_STREAM_END 1 */ "", /* Z_OK 0 */ "file error", /* Z_ERRNO (-1) */ "stream error", /* Z_STREAM_ERROR (-2) */ "data error", /* Z_DATA_ERROR (-3) */ "insufficient memory", /* Z_MEM_ERROR (-4) */ "buffer error", /* Z_BUF_ERROR (-5) */ "incompatible version",/* Z_VERSION_ERROR (-6) */ ""}; const char *zlibVersion(void) { return ZLIB_VERSION; } uLong zlibCompileFlags(void) { uLong flags; flags = 0; switch ((int)(sizeof(uInt))) { case 2: break; case 4: flags += 1; break; case 8: flags += 2; break; default: flags += 3; } switch ((int)(sizeof(uLong))) { case 2: break; case 4: flags += 1 << 2; break; case 8: flags += 2 << 2; break; default: flags += 3 << 2; } switch ((int)(sizeof(voidpf))) { case 2: break; case 4: flags += 1 << 4; break; case 8: flags += 2 << 4; break; default: flags += 3 << 4; } switch ((int)(sizeof(z_off_t))) { case 2: break; case 4: flags += 1 << 6; break; case 8: flags += 2 << 6; break; default: flags += 3 << 6; } #ifdef DEBUG flags += 1 << 8; #endif #if 0 /* by mao; #if defined(ASMV) || defined(ASMINF) */ flags += 1 << 9; #endif #if 0 /* by mao; #ifdef ZLIB_WINAPI */ flags += 1 << 10; #endif #ifdef BUILDFIXED flags += 1 << 12; #endif #ifdef DYNAMIC_CRC_TABLE flags += 1 << 13; #endif #ifdef NO_GZCOMPRESS flags += 1L << 16; #endif #ifdef NO_GZIP flags += 1L << 17; #endif #ifdef PKZIP_BUG_WORKAROUND flags += 1L << 20; #endif #ifdef FASTEST flags += 1L << 21; #endif return flags; } #ifdef DEBUG # ifndef verbose # define verbose 0 # endif int z_verbose = verbose; void z_error(char *m) { fprintf(stderr, "%s\n", m); exit(1); } #endif /* exported to allow conversion of error code to string for compress() and * uncompress() */ const char *zError(int err) { return ERR_MSG(err); } #ifndef Z_SOLO #ifndef MY_ZCALLOC /* Any system without a special alloc function */ voidpf zcalloc(voidpf opaque, unsigned items, unsigned size) { if (opaque) items += size - size; /* make compiler happy */ return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : (voidpf)calloc(items, size); } void zcfree(voidpf opaque, voidpf ptr) { free(ptr); if (opaque) return; /* make compiler happy */ } #endif /* MY_ZCALLOC */ #endif /* !Z_SOLO */ /* eof */ Rglpk/src/GLPK/zlib/gzclose.c0000644000176000001440000000144112245352174015464 0ustar ripleyusers/* gzclose.c */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* gzclose.c -- zlib gzclose() function * Copyright (C) 2004, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* gzclose() is in a separate file so that it is linked in only if it is used. That way the other gzclose functions can be used instead to avoid linking in unneeded compression or decompression routines. */ int gzclose(gzFile file) { #ifndef NO_GZCOMPRESS gz_statep state; if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file); #else return gzclose_r(file); #endif } /* eof */ Rglpk/src/GLPK/zlib/README0000644000176000001440000000254712175147600014540 0ustar ripleyusersNOTE: Files in this subdirectory are NOT part of the GLPK package, but are used with GLPK. The original code was modified according to GLPK requirements by Andrew Makhorin . The following files were added: zio.h, zio.c, zsymb.h. ************************************************************************ zlib general purpose compression library version 1.2.7, May 2nd, 2012 Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu Rglpk/src/GLPK/zlib/inftrees.c0000644000176000001440000003161012245352174015636 0ustar ripleyusers/* inftrees.c */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* inftrees.c -- generate Huffman trees for efficient decoding * Copyright (C) 1995-2012 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" #define MAXBITS 15 const char inflate_copyright[] = " inflate 1.2.7 Copyright 1995-2012 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ /* Build a set of tables to decode the provided canonical Huffman code. The code lengths are lens[0..codes-1]. The result starts at *table, whose indices are 0..2^bits-1. work is a writable array of at least lens shorts, which is used as a work area. type is the type of code to be generated, CODES, LENS, or DISTS. On return, zero is success, -1 is an invalid code, and +1 means that ENOUGH isn't enough. table on return points to the next available entry's address. bits is the requested root table index bits, and on return it is the actual root table index bits. It will differ if the request is greater than the longest code or if it is less than the shortest code. */ int inflate_table(codetype type, unsigned short *lens, unsigned codes, code **table, unsigned *bits, unsigned short *work) { unsigned len; /* a code's length in bits */ unsigned sym; /* index of code symbols */ unsigned min, max; /* minimum and maximum code lengths */ unsigned root; /* number of index bits for root table */ unsigned curr; /* number of index bits for current table */ unsigned drop; /* code bits to drop for sub-table */ int left; /* number of prefix codes available */ unsigned used; /* code entries in table used */ unsigned huff; /* Huffman code */ unsigned incr; /* for incrementing code, index */ unsigned fill; /* index for replicating entries */ unsigned low; /* low bits for current root entry */ unsigned mask; /* mask for low root bits */ code here; /* table entry for duplication */ code *next; /* next available space in table */ const unsigned short *base; /* base value table to use */ const unsigned short *extra; /* extra bits table to use */ int end; /* use base and extra for symbol > end */ unsigned short count[MAXBITS+1]; /* number of codes of each length */ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ static const unsigned short lbase[31] = { /* Length codes 257..285 base */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 78, 68}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 64, 64}; /* Process a set of code lengths to create a canonical Huffman code. The code lengths are lens[0..codes-1]. Each length corresponds to the symbols 0..codes-1. The Huffman code is generated by first sorting the symbols by length from short to long, and retaining the symbol order for codes with equal lengths. Then the code starts with all zero bits for the first code of the shortest length, and the codes are integer increments for the same length, and zeros are appended as the length increases. For the deflate format, these bits are stored backwards from their more natural integer increment ordering, and so when the decoding tables are built in the large loop below, the integer codes are incremented backwards. This routine assumes, but does not check, that all of the entries in lens[] are in the range 0..MAXBITS. The caller must assure this. 1..MAXBITS is interpreted as that code length. zero means that that symbol does not occur in this code. The codes are sorted by computing a count of codes for each length, creating from that a table of starting indices for each length in the sorted table, and then entering the symbols in order in the sorted table. The sorted table is work[], with that space being provided by the caller. The length counts are used for other purposes as well, i.e. finding the minimum and maximum length codes, determining if there are any codes at all, checking for a valid set of lengths, and looking ahead at length counts to determine sub-table sizes when building the decoding tables. */ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ for (len = 0; len <= MAXBITS; len++) count[len] = 0; for (sym = 0; sym < codes; sym++) count[lens[sym]]++; /* bound code lengths, force root to be within code lengths */ root = *bits; for (max = MAXBITS; max >= 1; max--) if (count[max] != 0) break; if (root > max) root = max; if (max == 0) { /* no symbols to code at all */ here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)1; here.val = (unsigned short)0; *(*table)++ = here; /* make a table to force an error */ *(*table)++ = here; *bits = 1; return 0; /* no symbols, but wait for decoding to report error */ } for (min = 1; min < max; min++) if (count[min] != 0) break; if (root < min) root = min; /* check for an over-subscribed or incomplete set of lengths */ left = 1; for (len = 1; len <= MAXBITS; len++) { left <<= 1; left -= count[len]; if (left < 0) return -1; /* over-subscribed */ } if (left > 0 && (type == CODES || max != 1)) return -1; /* incomplete set */ /* generate offsets into symbol table for each length for sorting */ offs[1] = 0; for (len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + count[len]; /* sort symbols by length, by symbol order within each length */ for (sym = 0; sym < codes; sym++) if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; /* Create and fill in decoding tables. In this loop, the table being filled is at next and has curr index bits. The code being used is huff with length len. That code is converted to an index by dropping drop bits off of the bottom. For codes where len is less than drop + curr, those top drop + curr - len bits are incremented through all values to fill the table with replicated entries. root is the number of index bits for the root table. When len exceeds root, sub-tables are created pointed to by the root entry with an index of the low root bits of huff. This is saved in low to check for when a new sub-table should be started. drop is zero when the root table is being filled, and drop is root when sub-tables are being filled. When a new sub-table is needed, it is necessary to look ahead in the code lengths to determine what size sub-table is needed. The length counts are used for this, and so count[] is decremented as codes are entered in the tables. used keeps track of how many table entries have been allocated from the provided *table space. It is checked for LENS and DIST tables against the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in the initial root table size constants. See the comments in inftrees.h for more information. sym increments through all symbols, and the loop terminates when all codes of length max, i.e. all codes, have been processed. This routine permits incomplete codes, so another loop after this one fills in the rest of the decoding tables with invalid code markers. */ /* set up for code type */ switch (type) { case CODES: base = extra = work; /* dummy value--not used */ end = 19; break; case LENS: base = lbase; base -= 257; extra = lext; extra -= 257; end = 256; break; default: /* DISTS */ base = dbase; extra = dext; end = -1; } /* initialize state for loop */ huff = 0; /* starting code */ sym = 0; /* starting code symbol */ len = min; /* starting code length */ next = *table; /* current table to fill in */ curr = root; /* current table index bits */ drop = 0; /* current bits to drop from code for index */ low = (unsigned)(-1); /* trigger new sub-table when len > root */ used = 1U << root; /* use root table entries */ mask = used - 1; /* mask for comparing low */ /* check available table space */ if ((type == LENS && used >= ENOUGH_LENS) || (type == DISTS && used >= ENOUGH_DISTS)) return 1; /* process all codes and make table entries */ for (;;) { /* create table entry */ here.bits = (unsigned char)(len - drop); if ((int)(work[sym]) < end) { here.op = (unsigned char)0; here.val = work[sym]; } else if ((int)(work[sym]) > end) { here.op = (unsigned char)(extra[work[sym]]); here.val = base[work[sym]]; } else { here.op = (unsigned char)(32 + 64); /* end of block */ here.val = 0; } /* replicate for those indices with low len bits equal to huff */ incr = 1U << (len - drop); fill = 1U << curr; min = fill; /* save offset to next table */ do { fill -= incr; next[(huff >> drop) + fill] = here; } while (fill != 0); /* backwards increment the len-bit code huff */ incr = 1U << (len - 1); while (huff & incr) incr >>= 1; if (incr != 0) { huff &= incr - 1; huff += incr; } else huff = 0; /* go to next symbol, update count, len */ sym++; if (--(count[len]) == 0) { if (len == max) break; len = lens[work[sym]]; } /* create new sub-table if needed */ if (len > root && (huff & mask) != low) { /* if first time, transition to sub-tables */ if (drop == 0) drop = root; /* increment past last table */ next += min; /* here min is 1 << curr */ /* determine length of next table */ curr = len - drop; left = (int)(1 << curr); while (curr + drop < max) { left -= count[curr + drop]; if (left <= 0) break; curr++; left <<= 1; } /* check for enough space */ used += 1U << curr; if ((type == LENS && used >= ENOUGH_LENS) || (type == DISTS && used >= ENOUGH_DISTS)) return 1; /* point entry in root table to sub-table */ low = huff & mask; (*table)[low].op = (unsigned char)curr; (*table)[low].bits = (unsigned char)root; (*table)[low].val = (unsigned short)(next - *table); } } /* fill in remaining table entry if code is incomplete (guaranteed to have at most one remaining entry, since if the code is incomplete, the maximum code length that was allowed to get this far is one bit) */ if (huff != 0) { here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)(len - drop); here.val = (unsigned short)0; next[huff] = here; } /* set return parameters */ *table += used; *bits = root; return 0; } /* eof */ Rglpk/src/GLPK/zlib/gzlib.c0000644000176000001440000003240012245352174015124 0ustar ripleyusers/* gzlib.c */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* gzlib.c -- zlib functions common to reading and writing gzip files * Copyright (C) 2004, 2010, 2011, 2012 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" #define LSEEK lseek /* Local functions */ static void gz_reset (gz_statep); static gzFile gz_open (const void *, int, const char *); /* Reset gzip file state */ static void gz_reset(gz_statep state) { state->x.have = 0; /* no output data available */ if (state->mode == GZ_READ) { /* for reading ... */ state->eof = 0; /* not at end of file */ state->past = 0; /* have not read past end yet */ state->how = LOOK; /* look for gzip header */ } state->seek = 0; /* no seek request pending */ gz_error(state, Z_OK, NULL); /* clear error */ state->x.pos = 0; /* no uncompressed data yet */ state->strm.avail_in = 0; /* no input data yet */ } /* Open a gzip file either by name or file descriptor. */ static gzFile gz_open(const void *path, int fd, const char *mode) { gz_statep state; size_t len; int oflag; #if 0 /* by mao; #ifdef O_CLOEXEC */ int cloexec = 0; #endif #if 0 /* by mao; #ifdef O_EXCL */ int exclusive = 0; #endif /* check input */ if (path == NULL) return NULL; /* allocate gzFile structure to return */ state = malloc(sizeof(gz_state)); if (state == NULL) return NULL; state->size = 0; /* no buffers allocated yet */ state->want = GZBUFSIZE; /* requested buffer size */ state->msg = NULL; /* no error message yet */ /* interpret mode */ state->mode = GZ_NONE; state->level = Z_DEFAULT_COMPRESSION; state->strategy = Z_DEFAULT_STRATEGY; state->direct = 0; while (*mode) { if (*mode >= '0' && *mode <= '9') state->level = *mode - '0'; else switch (*mode) { case 'r': state->mode = GZ_READ; break; #ifndef NO_GZCOMPRESS case 'w': state->mode = GZ_WRITE; break; case 'a': state->mode = GZ_APPEND; break; #endif case '+': /* can't read and write at the same time */ free(state); return NULL; case 'b': /* ignore -- will request binary anyway */ break; #if 0 /* by mao; #ifdef O_CLOEXEC */ case 'e': cloexec = 1; break; #endif #if 0 /* by mao; #ifdef O_EXCL */ case 'x': exclusive = 1; break; #endif case 'f': state->strategy = Z_FILTERED; break; case 'h': state->strategy = Z_HUFFMAN_ONLY; break; case 'R': state->strategy = Z_RLE; break; case 'F': state->strategy = Z_FIXED; case 'T': state->direct = 1; default: /* could consider as an error, but just ignore */ ; } mode++; } /* must provide an "r", "w", or "a" */ if (state->mode == GZ_NONE) { free(state); return NULL; } /* can't force transparent read */ if (state->mode == GZ_READ) { if (state->direct) { free(state); return NULL; } state->direct = 1; /* for empty file */ } /* save the path name for error messages */ #if 0 /* by mao; #ifdef _WIN32 */ if (fd == -2) { len = wcstombs(NULL, path, 0); if (len == (size_t)-1) len = 0; } else #endif len = strlen(path); state->path = malloc(len + 1); if (state->path == NULL) { free(state); return NULL; } #if 0 /* by mao; #ifdef _WIN32 */ if (fd == -2) if (len) wcstombs(state->path, path, len + 1); else *(state->path) = 0; else #endif strcpy(state->path, path); /* compute the flags for open() */ oflag = #if 0 /* by mao; #ifdef O_LARGEFILE */ O_LARGEFILE | #endif #if 0 /* by mao; #ifdef O_BINARY */ O_BINARY | #endif #if 0 /* by mao; #ifdef O_CLOEXEC */ (cloexec ? O_CLOEXEC : 0) | #endif (state->mode == GZ_READ ? O_RDONLY : (O_WRONLY | O_CREAT | #if 0 /* by mao; #ifdef O_EXCL */ (exclusive ? O_EXCL : 0) | #endif (state->mode == GZ_WRITE ? O_TRUNC : O_APPEND))); /* open the file with the appropriate flags (or just use fd) */ state->fd = fd > -1 ? fd : ( #if 0 /* by mao; #ifdef _WIN32 */ fd == -2 ? _wopen(path, oflag, 0666) : #endif open(path, oflag, 0666)); if (state->fd == -1) { free(state->path); free(state); return NULL; } if (state->mode == GZ_APPEND) state->mode = GZ_WRITE; /* simplify later checks */ /* save the current position for rewinding (only if reading) */ if (state->mode == GZ_READ) { state->start = LSEEK(state->fd, 0, SEEK_CUR); if (state->start == -1) state->start = 0; } /* initialize stream */ gz_reset(state); /* return stream */ return (gzFile)state; } /* -- see zlib.h -- */ gzFile gzopen(const char *path, const char *mode) { return gz_open(path, -1, mode); } /* -- see zlib.h -- */ gzFile gzopen64(const char *path, const char *mode) { return gz_open(path, -1, mode); } /* -- see zlib.h -- */ gzFile gzdopen(int fd, const char *mode) { char *path; /* identifier for error messages */ gzFile gz; if (fd == -1 || (path = malloc(7 + 3 * sizeof(int))) == NULL) return NULL; sprintf(path, "", fd); /* for debugging */ gz = gz_open(path, fd, mode); free(path); return gz; } /* -- see zlib.h -- */ int gzbuffer(gzFile file, unsigned size) { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* make sure we haven't already allocated memory */ if (state->size != 0) return -1; /* check and set requested size */ if (size < 2) size = 2; /* need two bytes to check magic header */ state->want = size; return 0; } /* -- see zlib.h -- */ int gzrewind(gzFile file) { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* back up and start over */ if (LSEEK(state->fd, state->start, SEEK_SET) == -1) return -1; gz_reset(state); return 0; } /* -- see zlib.h -- */ z_off64_t gzseek64(gzFile file, z_off64_t offset, int whence) { unsigned n; z_off64_t ret; gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* check that there's no error */ if (state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; /* can only seek from start or relative to current position */ if (whence != SEEK_SET && whence != SEEK_CUR) return -1; /* normalize offset to a SEEK_CUR specification */ if (whence == SEEK_SET) offset -= state->x.pos; else if (state->seek) offset += state->skip; state->seek = 0; /* if within raw area while reading, just go there */ if (state->mode == GZ_READ && state->how == COPY && state->x.pos + offset >= 0) { ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR); if (ret == -1) return -1; state->x.have = 0; state->eof = 0; state->past = 0; state->seek = 0; gz_error(state, Z_OK, NULL); state->strm.avail_in = 0; state->x.pos += offset; return state->x.pos; } /* calculate skip amount, rewinding if needed for back seek when reading */ if (offset < 0) { if (state->mode != GZ_READ) /* writing -- can't go backwards */ return -1; offset += state->x.pos; if (offset < 0) /* before start of file! */ return -1; if (gzrewind(file) == -1) /* rewind, then skip to offset */ return -1; } /* if reading, skip what's in output buffer (one less gzgetc() check) */ if (state->mode == GZ_READ) { n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? (unsigned)offset : state->x.have; state->x.have -= n; state->x.next += n; state->x.pos += n; offset -= n; } /* request skip (if not zero) */ if (offset) { state->seek = 1; state->skip = offset; } return state->x.pos + offset; } /* -- see zlib.h -- */ z_off_t gzseek(gzFile file, z_off_t offset, int whence) { z_off64_t ret; ret = gzseek64(file, (z_off64_t)offset, whence); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ z_off64_t gztell64(gzFile file) { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* return position */ return state->x.pos + (state->seek ? state->skip : 0); } /* -- see zlib.h -- */ z_off_t gztell(gzFile file) { z_off64_t ret; ret = gztell64(file); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ z_off64_t gzoffset64(gzFile file) { z_off64_t offset; gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* compute and return effective offset in file */ offset = LSEEK(state->fd, 0, SEEK_CUR); if (offset == -1) return -1; if (state->mode == GZ_READ) /* reading */ offset -= state->strm.avail_in; /* don't count buffered input */ return offset; } /* -- see zlib.h -- */ z_off_t gzoffset(gzFile file) { z_off64_t ret; ret = gzoffset64(file); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ int gzeof(gzFile file) { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return 0; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return 0; /* return end-of-file state */ return state->mode == GZ_READ ? state->past : 0; } /* -- see zlib.h -- */ const char *gzerror(gzFile file, int *errnum) { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return NULL; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return NULL; /* return error information */ if (errnum != NULL) *errnum = state->err; return state->msg == NULL ? "" : state->msg; } /* -- see zlib.h -- */ void gzclearerr(gzFile file) { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return; /* clear error and end-of-file */ if (state->mode == GZ_READ) { state->eof = 0; state->past = 0; } gz_error(state, Z_OK, NULL); } /* Create an error message in allocated memory and set state->err and state->msg accordingly. Free any previous error message already there. Do not try to free or allocate space if the error is Z_MEM_ERROR (out of memory). Simply save the error message as a static string. If there is an allocation failure constructing the error message, then convert the error to out of memory. */ void gz_error(gz_statep state, int err, const char *msg) { /* free previously allocated message and clear */ if (state->msg != NULL) { if (state->err != Z_MEM_ERROR) free(state->msg); state->msg = NULL; } /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */ if (err != Z_OK && err != Z_BUF_ERROR) state->x.have = 0; /* set error code, and if no message, then done */ state->err = err; if (msg == NULL) return; /* for an out of memory error, save as static string */ if (err == Z_MEM_ERROR) { state->msg = (char *)msg; return; } /* construct error message with path */ if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) { state->err = Z_MEM_ERROR; state->msg = (char *)"out of memory"; return; } strcpy(state->msg, state->path); strcat(state->msg, ": "); strcat(state->msg, msg); return; } /* eof */ Rglpk/src/GLPK/zlib/deflate.h0000644000176000001440000003063412245352174015435 0ustar ripleyusers/* deflate.h */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* deflate.h -- internal compression state * Copyright (C) 1995-2012 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ #ifndef DEFLATE_H #define DEFLATE_H #include "zutil.h" /* define NO_GZIP when compiling if you want to disable gzip header and trailer creation by deflate(). NO_GZIP would be used to avoid linking in the crc code when it is not needed. For shared libraries, gzip encoding should be left enabled. */ #ifndef NO_GZIP # define GZIP #endif /* =========================================================================== * Internal compression state. */ #define LENGTH_CODES 29 /* number of length codes, not counting the special END_BLOCK code */ #define LITERALS 256 /* number of literal bytes 0..255 */ #define L_CODES (LITERALS+1+LENGTH_CODES) /* number of Literal or Length codes, including the END_BLOCK code */ #define D_CODES 30 /* number of distance codes */ #define BL_CODES 19 /* number of codes used to transfer the bit lengths */ #define HEAP_SIZE (2*L_CODES+1) /* maximum heap size */ #define MAX_BITS 15 /* All codes must not exceed MAX_BITS bits */ #define Buf_size 16 /* size of bit buffer in bi_buf */ #define INIT_STATE 42 #define EXTRA_STATE 69 #define NAME_STATE 73 #define COMMENT_STATE 91 #define HCRC_STATE 103 #define BUSY_STATE 113 #define FINISH_STATE 666 /* Stream status */ /* Data structure describing a single value and its code string. */ typedef struct ct_data_s { union { ush freq; /* frequency count */ ush code; /* bit string */ } fc; union { ush dad; /* father node in Huffman tree */ ush len; /* length of bit string */ } dl; } ct_data; #define Freq fc.freq #define Code fc.code #define Dad dl.dad #define Len dl.len typedef struct static_tree_desc_s static_tree_desc; typedef struct tree_desc_s { ct_data *dyn_tree; /* the dynamic tree */ int max_code; /* largest code with non zero frequency */ static_tree_desc *stat_desc; /* the corresponding static tree */ } tree_desc; typedef ush Pos; typedef Pos Posf; typedef unsigned IPos; /* A Pos is an index in the character window. We use short instead of int to * save space in the various tables. IPos is used only for parameter passing. */ typedef struct internal_state { z_streamp strm; /* pointer back to this zlib stream */ int status; /* as the name implies */ Bytef *pending_buf; /* output still pending */ ulg pending_buf_size; /* size of pending_buf */ Bytef *pending_out; /* next pending byte to output to the stream */ uInt pending; /* nb of bytes in the pending buffer */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ gz_headerp gzhead; /* gzip header information to write */ uInt gzindex; /* where in extra, name, or comment */ Byte method; /* STORED (for zip only) or DEFLATED */ int last_flush; /* value of flush param for previous deflate call */ /* used by deflate.c: */ uInt w_size; /* LZ77 window size (32K by default) */ uInt w_bits; /* log2(w_size) (8..16) */ uInt w_mask; /* w_size - 1 */ Bytef *window; /* Sliding window. Input bytes are read into the second half of the window, * and move to the first half later to keep a dictionary of at least wSize * bytes. With this organization, matches are limited to a distance of * wSize-MAX_MATCH bytes, but this ensures that IO is always * performed with a length multiple of the block size. Also, it limits * the window size to 64K, which is quite useful on MSDOS. * To do: use the user input buffer as sliding window. */ ulg window_size; /* Actual size of window: 2*wSize, except when the user input buffer * is directly used as sliding window. */ Posf *prev; /* Link to older string with same hash index. To limit the size of this * array to 64K, this link is maintained only for the last 32K strings. * An index in this array is thus a window index modulo 32K. */ Posf *head; /* Heads of the hash chains or NIL. */ uInt ins_h; /* hash index of string to be inserted */ uInt hash_size; /* number of elements in hash table */ uInt hash_bits; /* log2(hash_size) */ uInt hash_mask; /* hash_size-1 */ uInt hash_shift; /* Number of bits by which ins_h must be shifted at each input * step. It must be such that after MIN_MATCH steps, the oldest * byte no longer takes part in the hash key, that is: * hash_shift * MIN_MATCH >= hash_bits */ long block_start; /* Window position at the beginning of the current output block. Gets * negative when the window is moved backwards. */ uInt match_length; /* length of best match */ IPos prev_match; /* previous match */ int match_available; /* set if previous match exists */ uInt strstart; /* start of string to insert */ uInt match_start; /* start of matching string */ uInt lookahead; /* number of valid bytes ahead in window */ uInt prev_length; /* Length of the best match at previous step. Matches not greater than this * are discarded. This is used in the lazy match evaluation. */ uInt max_chain_length; /* To speed up deflation, hash chains are never searched beyond this * length. A higher limit improves compression ratio but degrades the * speed. */ uInt max_lazy_match; /* Attempt to find a better match only when the current match is strictly * smaller than this value. This mechanism is used only for compression * levels >= 4. */ # define max_insert_length max_lazy_match /* Insert new strings in the hash table only if the match length is not * greater than this length. This saves time but degrades compression. * max_insert_length is used only for compression levels <= 3. */ int level; /* compression level (1..9) */ int strategy; /* favor or force Huffman coding*/ uInt good_match; /* Use a faster search when the previous match is longer than this */ int nice_match; /* Stop searching when current match exceeds this */ /* used by trees.c: */ /* Didn't use ct_data typedef below to suppress compiler warning */ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ struct tree_desc_s l_desc; /* desc. for literal tree */ struct tree_desc_s d_desc; /* desc. for distance tree */ struct tree_desc_s bl_desc; /* desc. for bit length tree */ ush bl_count[MAX_BITS+1]; /* number of codes at each bit length for an optimal tree */ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ int heap_len; /* number of elements in the heap */ int heap_max; /* element of largest frequency */ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. * The same heap array is used to build all trees. */ uch depth[2*L_CODES+1]; /* Depth of each subtree used as tie breaker for trees of equal frequency */ uchf *l_buf; /* buffer for literals or lengths */ uInt lit_bufsize; /* Size of match buffer for literals/lengths. There are 4 reasons for * limiting lit_bufsize to 64K: * - frequencies can be kept in 16 bit counters * - if compression is not successful for the first block, all input * data is still in the window so we can still emit a stored block even * when input comes from standard input. (This can also be done for * all blocks if lit_bufsize is not greater than 32K.) * - if compression is not successful for a file smaller than 64K, we can * even emit a stored file instead of a stored block (saving 5 bytes). * This is applicable only for zip (not gzip or zlib). * - creating new Huffman trees less frequently may not provide fast * adaptation to changes in the input data statistics. (Take for * example a binary file with poorly compressible code followed by * a highly compressible string table.) Smaller buffer sizes give * fast adaptation but have of course the overhead of transmitting * trees more frequently. * - I can't count above 4 */ uInt last_lit; /* running index in l_buf */ ushf *d_buf; /* Buffer for distances. To simplify the code, d_buf and l_buf have * the same number of elements. To use different lengths, an extra flag * array would be necessary. */ ulg opt_len; /* bit length of current block with optimal trees */ ulg static_len; /* bit length of current block with static trees */ uInt matches; /* number of string matches in current block */ uInt insert; /* bytes at end of window left to insert */ #ifdef DEBUG ulg compressed_len; /* total bit length of compressed file mod 2^32 */ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ #endif ush bi_buf; /* Output buffer. bits are inserted starting at the bottom (least * significant bits). */ int bi_valid; /* Number of valid bits in bi_buf. All bits above the last valid bit * are always zero. */ ulg high_water; /* High water mark offset in window for initialized bytes -- bytes above * this are set to zero in order to avoid memory check warnings when * longest match routines access bytes past the input. This is then * updated to the new high water mark. */ } deflate_state; /* Output a byte on the stream. * IN assertion: there is enough room in pending_buf. */ #define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) /* Minimum amount of lookahead, except at the end of the input file. * See deflate.c for comments about the MIN_MATCH+1. */ #define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) /* In order to simplify the code, particularly on 16 bit machines, match * distances are limited to MAX_DIST instead of WSIZE. */ #define WIN_INIT MAX_MATCH /* Number of bytes after end of data in window to initialize in order to avoid memory checker errors from longest match routines */ /* in trees.c */ void _tr_init(deflate_state *s); int _tr_tally(deflate_state *s, unsigned dist, unsigned lc); void _tr_flush_block(deflate_state *s, charf *buf, ulg stored_len, int last); void _tr_flush_bits(deflate_state *s); void _tr_align(deflate_state *s); void _tr_stored_block(deflate_state *s, charf *buf, ulg stored_len, int last); #define d_code(dist) \ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) /* Mapping from a distance to a distance code. dist is the distance - 1 and * must not have side effects. _dist_code[256] and _dist_code[257] are never * used. */ #ifndef DEBUG /* Inline versions of _tr_tally for speed: */ #if defined(GEN_TREES_H) extern uch _length_code[]; extern uch _dist_code[]; #else extern const uch _length_code[]; extern const uch _dist_code[]; #endif # define _tr_tally_lit(s, c, flush) \ { uch cc = (c); \ s->d_buf[s->last_lit] = 0; \ s->l_buf[s->last_lit++] = cc; \ s->dyn_ltree[cc].Freq++; \ flush = (s->last_lit == s->lit_bufsize-1); \ } # define _tr_tally_dist(s, distance, length, flush) \ { uch len = (length); \ ush dist = (distance); \ s->d_buf[s->last_lit] = dist; \ s->l_buf[s->last_lit++] = len; \ dist--; \ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ s->dyn_dtree[d_code(dist)].Freq++; \ flush = (s->last_lit == s->lit_bufsize-1); \ } #else # define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) # define _tr_tally_dist(s, distance, length, flush) \ flush = _tr_tally(s, distance, length) #endif #endif /* DEFLATE_H */ /* eof */ Rglpk/src/GLPK/zlib/zlib.h0000644000176000001440000023623312245352174014774 0ustar ripleyusers/* zlib.h */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* zlib.h -- interface of the 'zlib' general purpose compression library version 1.2.7, May 2nd, 2012 Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). */ #ifndef ZLIB_H #define ZLIB_H #include "zconf.h" #define ZLIB_VERSION "1.2.7" #define ZLIB_VERNUM 0x1270 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2 #define ZLIB_VER_REVISION 7 #define ZLIB_VER_SUBREVISION 0 /* The 'zlib' compression library provides in-memory compression and decompression functions, including integrity checks of the uncompressed data. This version of the library supports only one compression method (deflation) but other algorithms will be added later and will have the same stream interface. Compression can be done in a single step if the buffers are large enough, or can be done by repeated calls of the compression function. In the latter case, the application must provide more input and/or consume the output (providing more output space) before each call. The compressed data format used by default by the in-memory functions is the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped around a deflate stream, which is itself documented in RFC 1951. The library also supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. This library can optionally read and write gzip streams in memory as well. The zlib format was designed to be compact and fast for use in memory and on communications channels. The gzip format was designed for single- file compression on file systems, has a larger header than zlib to maintain directory information, and uses a different, slower check method than zlib. The library does not install any signal handler. The decoder checks the consistency of the compressed data, so the library should never crash even in case of corrupted input. */ typedef voidpf (*alloc_func) (voidpf opaque, uInt items, uInt size); typedef void (*free_func) (voidpf opaque, voidpf address); struct internal_state; typedef struct z_stream_s { Bytef *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ uLong total_in; /* total number of input bytes read so far */ Bytef *next_out; /* next output byte should be put there */ uInt avail_out; /* remaining free space at next_out */ uLong total_out; /* total number of bytes output so far */ const char *msg; /* last error message, NULL if no error */ struct internal_state *state; /* not visible by applications */ alloc_func zalloc; /* used to allocate the internal state */ free_func zfree; /* used to free the internal state */ voidpf opaque; /* private data object passed to zalloc and zfree */ int data_type; /* best guess about the data type: binary or text */ uLong adler; /* adler32 value of the uncompressed data */ uLong reserved; /* reserved for future use */ } z_stream; typedef z_stream *z_streamp; /* gzip header information passed to and from zlib routines. See RFC 1952 for more details on the meanings of these fields. */ typedef struct gz_header_s { int text; /* true if compressed data believed to be text */ uLong time; /* modification time */ int xflags; /* extra flags (not used when writing a gzip file) */ int os; /* operating system */ Bytef *extra; /* pointer to extra field or Z_NULL if none */ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ uInt extra_max; /* space at extra (only when reading header) */ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ uInt name_max; /* space at name (only when reading header) */ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ uInt comm_max; /* space at comment (only when reading header) */ int hcrc; /* true if there was or will be a header crc */ int done; /* true when done reading gzip header (not used when writing a gzip file) */ } gz_header; typedef gz_header *gz_headerp; /* The application must update next_in and avail_in when avail_in has dropped to zero. It must update next_out and avail_out when avail_out has dropped to zero. The application must initialize zalloc, zfree and opaque before calling the init function. All other fields are set by the compression library and must not be updated by the application. The opaque value provided by the application will be passed as the first parameter for calls of zalloc and zfree. This can be useful for custom memory management. The compression library attaches no meaning to the opaque value. zalloc must return Z_NULL if there is not enough memory for the object. If zlib is used in a multi-threaded application, zalloc and zfree must be thread safe. On 16-bit systems, the functions zalloc and zfree must be able to allocate exactly 65536 bytes, but will not be required to allocate more than this if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers returned by zalloc for objects of exactly 65536 bytes *must* have their offset normalized to zero. The default allocation function provided by this library ensures this (see zutil.c). To reduce memory requirements and avoid any allocation of 64K objects, at the expense of compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). The fields total_in and total_out can be used for statistics or progress reports. After compression, total_in holds the total size of the uncompressed data and may be saved for use in the decompressor (particularly if the decompressor wants to decompress everything in a single step). */ /* constants */ #define Z_NO_FLUSH 0 #define Z_PARTIAL_FLUSH 1 #define Z_SYNC_FLUSH 2 #define Z_FULL_FLUSH 3 #define Z_FINISH 4 #define Z_BLOCK 5 #define Z_TREES 6 /* Allowed flush values; see deflate() and inflate() below for details */ #define Z_OK 0 #define Z_STREAM_END 1 #define Z_NEED_DICT 2 #define Z_ERRNO (-1) #define Z_STREAM_ERROR (-2) #define Z_DATA_ERROR (-3) #define Z_MEM_ERROR (-4) #define Z_BUF_ERROR (-5) #define Z_VERSION_ERROR (-6) /* Return codes for the compression/decompression functions. Negative values * are errors, positive values are used for special but normal events. */ #define Z_NO_COMPRESSION 0 #define Z_BEST_SPEED 1 #define Z_BEST_COMPRESSION 9 #define Z_DEFAULT_COMPRESSION (-1) /* compression levels */ #define Z_FILTERED 1 #define Z_HUFFMAN_ONLY 2 #define Z_RLE 3 #define Z_FIXED 4 #define Z_DEFAULT_STRATEGY 0 /* compression strategy; see deflateInit2() below for details */ #define Z_BINARY 0 #define Z_TEXT 1 #define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ #define Z_UNKNOWN 2 /* Possible values of the data_type field (though see inflate()) */ #define Z_DEFLATED 8 /* The deflate compression method (the only one supported in this version) */ #define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ #define zlib_version zlibVersion() /* for compatibility with versions < 1.0.2 */ /* basic functions */ const char *zlibVersion(void); /* The application can compare zlibVersion and ZLIB_VERSION for consistency. If the first character differs, the library code actually used is not compatible with the zlib.h header file used by the application. This check is automatically made by deflateInit and inflateInit. */ /* int deflateInit(z_streamp strm, int level); Initializes the internal stream state for compression. The fields zalloc, zfree and opaque must be initialized before by the caller. If zalloc and zfree are set to Z_NULL, deflateInit updates them to use default allocation functions. The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION requests a default compromise between speed and compression (currently equivalent to level 6). deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if level is not a valid compression level, or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit does not perform any compression: this will be done by deflate(). */ int deflate(z_streamp strm, int flush); /* deflate compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. deflate performs one or both of the following actions: - Compress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in and avail_in are updated and processing will resume at this point for the next call of deflate(). - Provide more output starting at next_out and update next_out and avail_out accordingly. This action is forced if the parameter flush is non zero. Forcing flush frequently degrades the compression ratio, so this parameter should be set only when necessary (in interactive applications). Some output may be provided even if flush is not set. Before the call of deflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating avail_in or avail_out accordingly; avail_out should never be zero before the call. The application can consume the compressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to decide how much data to accumulate before producing output, in order to maximize compression. If the parameter flush is set to Z_SYNC_FLUSH, all pending output is flushed to the output buffer and the output is aligned on a byte boundary, so that the decompressor can get all input data available so far. (In particular avail_in is zero after the call if enough output space has been provided before the call.) Flushing may degrade compression for some compression algorithms and so it should be used only when necessary. This completes the current deflate block and follows it with an empty stored block that is three bits plus filler bits to the next byte, followed by four bytes (00 00 ff ff). If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the output buffer, but the output is not aligned to a byte boundary. All of the input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. This completes the current deflate block and follows it with an empty fixed codes block that is 10 bits long. This assures that enough bytes are output in order for the decompressor to finish the block before the empty fixed code block. If flush is set to Z_BLOCK, a deflate block is completed and emitted, as for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to seven bits of the current block are held to be written as the next byte after the next deflate block is completed. In this case, the decompressor may not be provided enough bits at this point in order to complete decompression of the data provided so far to the compressor. It may need to wait for the next block to be emitted. This is for advanced applications that need to control the emission of deflate blocks. If flush is set to Z_FULL_FLUSH, all output is flushed as with Z_SYNC_FLUSH, and the compression state is reset so that decompression can restart from this point if previous compressed data has been damaged or if random access is desired. Using Z_FULL_FLUSH too often can seriously degrade compression. If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out is greater than six to avoid repeated flush markers due to avail_out == 0 on return. If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there was enough output space; if deflate returns with Z_OK, this function must be called again with Z_FINISH and more output space (updated avail_out) but no more input data, until it returns with Z_STREAM_END or an error. After deflate has returned Z_STREAM_END, the only possible operations on the stream are deflateReset or deflateEnd. Z_FINISH can be used immediately after deflateInit if all the compression is to be done in a single step. In this case, avail_out must be at least the value returned by deflateBound (see below). Then deflate is guaranteed to return Z_STREAM_END. If not enough output space is provided, deflate will not return Z_STREAM_END, and it must be called again as described above. deflate() sets strm->adler to the adler32 checksum of all input read so far (that is, total_in bytes). deflate() may update strm->data_type if it can make a good guess about the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered binary. This field is only for information purposes and does not affect the compression algorithm in any manner. deflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if all input has been consumed and all output has been produced (only when flush is set to Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and deflate() can be called again with more input and more output space to continue compressing. */ int deflateEnd(z_streamp strm); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent, Z_DATA_ERROR if the stream was freed prematurely (some input or output was discarded). In the error case, msg may be set but then points to a static string (which must not be deallocated). */ /* int inflateInit(z_streamp strm); Initializes the internal stream state for decompression. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. If next_in is not Z_NULL and avail_in is large enough (the exact value depends on the compression method), inflateInit determines the compression method from the zlib header and allocates all data structures accordingly; otherwise the allocation will be deferred to the first call of inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to use default allocation functions. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit does not perform any decompression apart from possibly reading the zlib header if present: actual decompression will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unused and unchanged.) The current implementation of inflateInit() does not process any header information -- that is deferred until inflate() is called. */ int inflate(z_streamp strm, int flush); /* inflate decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. inflate performs one or both of the following actions: - Decompress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in is updated and processing will resume at this point for the next call of inflate(). - Provide more output starting at next_out and update next_out and avail_out accordingly. inflate() provides as much output as possible, until there is no more input data or no more space in the output buffer (see below about the flush parameter). Before the call of inflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating the next_* and avail_* values accordingly. The application can consume the uncompressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of inflate(). If inflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much output as possible to the output buffer. Z_BLOCK requests that inflate() stop if and when it gets to the next deflate block boundary. When decoding the zlib or gzip format, this will cause inflate() to return immediately after the header and before the first block. When doing a raw inflate, inflate() will go ahead and process the first block, and will return when it gets to the end of that block, or when it runs out of data. The Z_BLOCK option assists in appending to or combining deflate streams. Also to assist in this, on return inflate() will set strm->data_type to the number of unused bits in the last byte taken from strm->next_in, plus 64 if inflate() is currently decoding the last block in the deflate stream, plus 128 if inflate() returned immediately after decoding an end-of-block code or decoding the complete header up to just before the first byte of the deflate stream. The end-of-block will not be indicated until all of the uncompressed data from that block has been written to strm->next_out. The number of unused bits may in general be greater than seven, except when bit 7 of data_type is set, in which case the number of unused bits will be less than eight. data_type is set as noted here every time inflate() returns for all flush options, and so can be used to determine the amount of currently consumed input in bits. The Z_TREES option behaves as Z_BLOCK does, but it also returns when the end of each deflate block header is reached, before any actual data in that block is decoded. This allows the caller to determine the length of the deflate block header for later use in random access within a deflate block. 256 is added to the value of strm->data_type when inflate() returns immediately after reaching the end of the deflate block header. inflate() should normally be called until it returns Z_STREAM_END or an error. However if all decompression is to be performed in a single step (a single call of inflate), the parameter flush should be set to Z_FINISH. In this case all pending input is processed and all pending output is flushed; avail_out must be large enough to hold all of the uncompressed data for the operation to complete. (The size of the uncompressed data may have been saved by the compressor for this purpose.) The use of Z_FINISH is not required to perform an inflation in one step. However it may be used to inform inflate that a faster approach can be used for the single inflate() call. Z_FINISH also informs inflate to not maintain a sliding window if the stream completes, which reduces inflate's memory footprint. If the stream does not complete, either because not all of the stream is provided or not enough output space is provided, then a sliding window will be allocated and inflate() can be called again to continue the operation as if Z_NO_FLUSH had been used. In this implementation, inflate() always flushes as much output as possible to the output buffer, and always uses the faster approach on the first call. So the effects of the flush parameter in this implementation are on the return value of inflate() as noted below, when inflate() returns early when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of memory for a sliding window when Z_FINISH is used. If a preset dictionary is needed after this call (see inflateSetDictionary below), inflate sets strm->adler to the Adler-32 checksum of the dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise it sets strm->adler to the Adler-32 checksum of all output produced so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described below. At the end of the stream, inflate() checks that its computed adler32 checksum is equal to that saved by the compressor and returns Z_STREAM_END only if the checksum is correct. inflate() can decompress and check either zlib-wrapped or gzip-wrapped deflate data. The header type is detected automatically, if requested when initializing with inflateInit2(). Any information contained in the gzip header is not retained, so applications that need that information should instead use raw inflate, see inflateInit2() below, or inflateBack() and perform their own processing of the gzip header and trailer. When processing gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output producted so far. The CRC-32 is checked against the gzip trailer. inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has been reached and all uncompressed output has been produced, Z_NEED_DICT if a preset dictionary is needed at this point, Z_DATA_ERROR if the input data was corrupted (input stream not conforming to the zlib format or incorrect check value), Z_STREAM_ERROR if the stream structure was inconsistent (for example next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no progress is possible or if there was not enough room in the output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and inflate() can be called again with more input and more output space to continue decompressing. If Z_DATA_ERROR is returned, the application may then call inflateSync() to look for a good compression block if a partial recovery of the data is desired. */ int inflateEnd(z_streamp strm); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent. In the error case, msg may be set but then points to a static string (which must not be deallocated). */ /* Advanced functions */ /* The following functions are needed only in some special applications. */ /* int deflateInit2(z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy); This is another version of deflateInit with more compression options. The fields next_in, zalloc, zfree and opaque must be initialized before by the caller. The method parameter is the compression method. It must be Z_DEFLATED in this version of the library. The windowBits parameter is the base two logarithm of the window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. Larger values of this parameter result in better compression at the expense of memory usage. The default value is 15 if deflateInit is used instead. windowBits can also be -8..-15 for raw deflate. In this case, -windowBits determines the window size. deflate() will then generate raw deflate data with no zlib header or trailer, and will not compute an adler32 check value. windowBits can also be greater than 15 for optional gzip encoding. Add 16 to windowBits to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper. The gzip header will have no file name, no extra data, no comment, no modification time (set to zero), no header crc, and the operating system will be set to 255 (unknown). If a gzip stream is being written, strm->adler is a crc32 instead of an adler32. The memLevel parameter specifies how much memory should be allocated for the internal compression state. memLevel=1 uses minimum memory but is slow and reduces compression ratio; memLevel=9 uses maximum memory for optimal speed. The default value is 8. See zconf.h for total memory usage as a function of windowBits and memLevel. The strategy parameter is used to tune the compression algorithm. Use the value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no string match), or Z_RLE to limit match distances to one (run-length encoding). Filtered data consists mostly of small values with a somewhat random distribution. In this case, the compression algorithm is tuned to compress them better. The effect of Z_FILTERED is to force more Huffman coding and less string matching; it is somewhat intermediate between Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy parameter only affects the compression ratio but not the correctness of the compressed output even if it is not set appropriately. Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler decoder for special applications. deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit2 does not perform any compression: this will be done by deflate(). */ int deflateSetDictionary(z_streamp strm, const Bytef *dictionary, uInt dictLength); /* Initializes the compression dictionary from the given byte sequence without producing any compressed output. When using the zlib format, this function must be called immediately after deflateInit, deflateInit2 or deflateReset, and before any call of deflate. When doing raw deflate, this function must be called either before any call of deflate, or immediately after the completion of a deflate block, i.e. after all input has been consumed and all output has been delivered when using any of the flush options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The compressor and decompressor must use exactly the same dictionary (see inflateSetDictionary). The dictionary should consist of strings (byte sequences) that are likely to be encountered later in the data to be compressed, with the most commonly used strings preferably put towards the end of the dictionary. Using a dictionary is most useful when the data to be compressed is short and can be predicted with good accuracy; the data can then be compressed better than with the default empty dictionary. Depending on the size of the compression data structures selected by deflateInit or deflateInit2, a part of the dictionary may in effect be discarded, for example if the dictionary is larger than the window size provided in deflateInit or deflateInit2. Thus the strings most likely to be useful should be put at the end of the dictionary, not at the front. In addition, the current implementation of deflate will use at most the window size minus 262 bytes of the provided dictionary. Upon return of this function, strm->adler is set to the adler32 value of the dictionary; the decompressor may later use this value to determine which dictionary has been used by the compressor. (The adler32 value applies to the whole dictionary even if only a subset of the dictionary is actually used by the compressor.) If a raw deflate was requested, then the adler32 value is not computed and strm->adler is not set. deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent (for example if deflate has already been called for this stream or if not at a block boundary for raw deflate). deflateSetDictionary does not perform any compression: this will be done by deflate(). */ int deflateCopy(z_streamp dest, z_streamp source); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when several compression strategies will be tried, for example when there are several ways of pre-processing the input data with a filter. The streams that will be discarded should then be freed by calling deflateEnd. Note that deflateCopy duplicates the internal compression state which can be quite large, so this strategy is slow and can consume lots of memory. deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ int deflateReset(z_streamp strm); /* This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate all the internal compression state. The stream will keep the same compression level and any other attributes that may have been set by deflateInit2. deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ int deflateParams(z_streamp strm, int level, int strategy); /* Dynamically update the compression level and compression strategy. The interpretation of level and strategy is as in deflateInit2. This can be used to switch between compression and straight copy of the input data, or to switch to a different kind of input data requiring a different strategy. If the compression level is changed, the input available so far is compressed with the old level (and may be flushed); the new level will take effect only at the next call of deflate(). Before the call of deflateParams, the stream state must be set as for a call of deflate(), since the currently available input may have to be compressed and flushed. In particular, strm->avail_out must be non-zero. deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if strm->avail_out was zero. */ int deflateTune(z_streamp strm, int good_length, int max_lazy, int nice_length, int max_chain); /* Fine tune deflate's internal compression parameters. This should only be used by someone who understands the algorithm used by zlib's deflate for searching for the best matching string, and even then only by the most fanatic optimizer trying to squeeze out the last compressed bit for their specific input data. Read the deflate.c source code for the meaning of the max_lazy, good_length, nice_length, and max_chain parameters. deflateTune() can be called after deflateInit() or deflateInit2(), and returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. */ uLong deflateBound(z_streamp strm, uLong sourceLen); /* deflateBound() returns an upper bound on the compressed size after deflation of sourceLen bytes. It must be called after deflateInit() or deflateInit2(), and after deflateSetHeader(), if used. This would be used to allocate an output buffer for deflation in a single pass, and so would be called before deflate(). If that first deflate() call is provided the sourceLen input bytes, an output buffer allocated to the size returned by deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed to return Z_STREAM_END. Note that it is possible for the compressed size to be larger than the value returned by deflateBound() if flush options other than Z_FINISH or Z_NO_FLUSH are used. */ int deflatePending(z_streamp strm, unsigned *pending, int *bits); /* deflatePending() returns the number of bytes and bits of output that have been generated, but not yet provided in the available output. The bytes not provided would be due to the available output space having being consumed. The number of bits of output not provided are between 0 and 7, where they await more bits to join them in order to fill out a full byte. If pending or bits are Z_NULL, then those values are not set. deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ int deflatePrime(z_streamp strm, int bits, int value); /* deflatePrime() inserts bits in the deflate output stream. The intent is that this function is used to start off the deflate output with the bits leftover from a previous deflate stream when appending to it. As such, this function can only be used for raw deflate, and must be used before the first deflate() call after a deflateInit2() or deflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the output. deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the source stream state was inconsistent. */ int deflateSetHeader(z_streamp strm, gz_headerp head); /* deflateSetHeader() provides gzip header information for when a gzip stream is requested by deflateInit2(). deflateSetHeader() may be called after deflateInit2() or deflateReset() and before the first call of deflate(). The text, time, os, extra field, name, and comment information in the provided gz_header structure are written to the gzip header (xflag is ignored -- the extra flags are set according to the compression level). The caller must assure that, if not Z_NULL, name and comment are terminated with a zero byte, and that if extra is not Z_NULL, that extra_len bytes are available there. If hcrc is true, a gzip header crc is included. Note that the current versions of the command-line version of gzip (up through version 1.3.x) do not support header crc's, and will report that it is a "multi-part gzip file" and give up. If deflateSetHeader is not used, the default gzip header has text false, the time set to zero, and os set to 255, with no extra, name, or comment fields. The gzip header is returned to the default state by deflateReset(). deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* int inflateInit2(z_streamp strm, int windowBits); This is another version of inflateInit with an extra parameter. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. The windowBits parameter is the base two logarithm of the maximum window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. The default value is 15 if inflateInit is used instead. windowBits must be greater than or equal to the windowBits value provided to deflateInit2() while compressing, or it must be equal to 15 if deflateInit2() was not used. If a compressed stream with a larger window size is given as input, inflate() will return with the error code Z_DATA_ERROR instead of trying to allocate a larger window. windowBits can also be zero to request that inflate use the window size in the zlib header of the compressed stream. windowBits can also be -8..-15 for raw inflate. In this case, -windowBits determines the window size. inflate() will then process raw deflate data, not looking for a zlib or gzip header, not generating a check value, and not looking for any check values for comparison at the end of the stream. This is for use with other formats that use the deflate compressed data format such as zip. Those formats provide their own check values. If a custom format is developed using the raw deflate format for compressed data, it is recommended that a check value such as an adler32 or a crc32 be applied to the uncompressed data as is done in the zlib, gzip, and zip formats. For most applications, the zlib format should be used as is. Note that comments above on the use in deflateInit2() applies to the magnitude of windowBits. windowBits can also be greater than 15 for optional gzip decoding. Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection, or add 16 to decode only the gzip format (the zlib format will return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a crc32 instead of an adler32. inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit2 does not perform any decompression apart from possibly reading the zlib header if present: actual decompression will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unused and unchanged.) The current implementation of inflateInit2() does not process any header information -- that is deferred until inflate() is called. */ int inflateSetDictionary(z_streamp strm, const Bytef *dictionary, uInt dictLength); /* Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate, if that call returned Z_NEED_DICT. The dictionary chosen by the compressor can be determined from the adler32 value returned by that call of inflate. The compressor and decompressor must use exactly the same dictionary (see deflateSetDictionary). For raw inflate, this function can be called at any time to set the dictionary. If the provided dictionary is smaller than the window and there is already data in the window, then the provided dictionary will amend what's there. The application must insure that the dictionary that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the expected one (incorrect adler32 value). inflateSetDictionary does not perform any decompression: this will be done by subsequent calls of inflate(). */ int inflateSync(z_streamp strm); /* Skips invalid compressed data until a possible full flush point (see above for the description of deflate with Z_FULL_FLUSH) can be found, or until all available input is skipped. No output is provided. inflateSync searches for a 00 00 FF FF pattern in the compressed data. All full flush points have this pattern, but not all occurences of this pattern are full flush points. inflateSync returns Z_OK if a possible full flush point has been found, Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the success case, the application may save the current current value of total_in which indicates where valid compressed data was found. In the error case, the application may repeatedly call inflateSync, providing more input each time, until success or end of the input data. */ int inflateCopy(z_streamp dest, z_streamp source); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when randomly accessing a large stream. The first pass through the stream can periodically record the inflate state, allowing restarting inflate at those points when randomly accessing the stream. inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ int inflateReset(z_streamp strm); /* This function is equivalent to inflateEnd followed by inflateInit, but does not free and reallocate all the internal decompression state. The stream will keep attributes that may have been set by inflateInit2. inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ int inflateReset2(z_streamp strm, int windowBits); /* This function is the same as inflateReset, but it also permits changing the wrap and window size requests. The windowBits parameter is interpreted the same as it is for inflateInit2. inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL), or if the windowBits parameter is invalid. */ int inflatePrime(z_streamp strm, int bits, int value); /* This function inserts bits in the inflate input stream. The intent is that this function is used to start inflating at a bit position in the middle of a byte. The provided bits will be used before any bytes are used from next_in. This function should only be used with raw inflate, and should be used before the first inflate() call after inflateInit2() or inflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the input. If bits is negative, then the input stream bit buffer is emptied. Then inflatePrime() can be called again to put bits in the buffer. This is used to clear out bits leftover after feeding inflate a block description prior to feeding inflate codes. inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ long inflateMark(z_streamp strm); /* This function returns two values, one in the lower 16 bits of the return value, and the other in the remaining upper bits, obtained by shifting the return value down 16 bits. If the upper value is -1 and the lower value is zero, then inflate() is currently decoding information outside of a block. If the upper value is -1 and the lower value is non-zero, then inflate is in the middle of a stored block, with the lower value equaling the number of bytes from the input remaining to copy. If the upper value is not -1, then it is the number of bits back from the current bit position in the input of the code (literal or length/distance pair) currently being processed. In that case the lower value is the number of bytes already emitted for that code. A code is being processed if inflate is waiting for more input to complete decoding of the code, or if it has completed decoding but is waiting for more output space to write the literal or match data. inflateMark() is used to mark locations in the input data for random access, which may be at bit positions, and to note those cases where the output of a code may span boundaries of random access blocks. The current location in the input stream can be determined from avail_in and data_type as noted in the description for the Z_BLOCK flush parameter for inflate. inflateMark returns the value noted above or -1 << 16 if the provided source stream state was inconsistent. */ int inflateGetHeader(z_streamp strm, gz_headerp head); /* inflateGetHeader() requests that gzip header information be stored in the provided gz_header structure. inflateGetHeader() may be called after inflateInit2() or inflateReset(), and before the first call of inflate(). As inflate() processes the gzip stream, head->done is zero until the header is completed, at which time head->done is set to one. If a zlib stream is being decoded, then head->done is set to -1 to indicate that there will be no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be used to force inflate() to return immediately after header processing is complete and before any actual data is decompressed. The text, time, xflags, and os fields are filled in with the gzip header contents. hcrc is set to true if there is a header CRC. (The header CRC was valid if done is set to one.) If extra is not Z_NULL, then extra_max contains the maximum number of bytes to write to extra. Once done is true, extra_len contains the actual extra field length, and extra contains the extra field, or that field truncated if extra_max is less than extra_len. If name is not Z_NULL, then up to name_max characters are written there, terminated with a zero unless the length is greater than name_max. If comment is not Z_NULL, then up to comm_max characters are written there, terminated with a zero unless the length is greater than comm_max. When any of extra, name, or comment are not Z_NULL and the respective field is not present in the header, then that field is set to Z_NULL to signal its absence. This allows the use of deflateSetHeader() with the returned structure to duplicate the header. However if those fields are set to allocated memory, then the application will need to save those pointers elsewhere so that they can be eventually freed. If inflateGetHeader is not used, then the header information is simply discarded. The header is always checked for validity, including the header CRC if present. inflateReset() will reset the process to discard the header information. The application would need to call inflateGetHeader() again to retrieve the header from the next gzip stream. inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* int inflateBackInit(z_streamp strm, int windowBits, unsigned char *window); Initialize the internal stream state for decompression using inflateBack() calls. The fields zalloc, zfree and opaque in strm must be initialized before the call. If zalloc and zfree are Z_NULL, then the default library- derived memory allocation routines are used. windowBits is the base two logarithm of the window size, in the range 8..15. window is a caller supplied buffer of that size. Except for special applications where it is assured that deflate was used with small window sizes, windowBits must be 15 and a 32K byte window must be supplied to be able to decompress general deflate streams. See inflateBack() for the usage of these routines. inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of the parameters are invalid, Z_MEM_ERROR if the internal state could not be allocated, or Z_VERSION_ERROR if the version of the library does not match the version of the header file. */ typedef unsigned (*in_func)(void *, unsigned char **); typedef int (*out_func)(void *, unsigned char *, unsigned); int inflateBack(z_streamp strm, in_func in, void *in_desc, out_func out, void *out_desc); /* inflateBack() does a raw inflate with a single call using a call-back interface for input and output. This is more efficient than inflate() for file i/o applications in that it avoids copying between the output and the sliding window by simply making the window itself the output buffer. This function trusts the application to not change the output buffer passed by the output function, at least until inflateBack() returns. inflateBackInit() must be called first to allocate the internal state and to initialize the state with the user-provided window buffer. inflateBack() may then be used multiple times to inflate a complete, raw deflate stream with each call. inflateBackEnd() is then called to free the allocated state. A raw deflate stream is one with no zlib or gzip header or trailer. This routine would normally be used in a utility that reads zip or gzip files and writes out uncompressed files. The utility would decode the header and process the trailer on its own, hence this routine expects only the raw deflate stream to decompress. This is different from the normal behavior of inflate(), which expects either a zlib or gzip header and trailer around the deflate stream. inflateBack() uses two subroutines supplied by the caller that are then called by inflateBack() for input and output. inflateBack() calls those routines until it reads a complete deflate stream and writes out all of the uncompressed data, or until it encounters an error. The function's parameters and return types are defined above in the in_func and out_func typedefs. inflateBack() will call in(in_desc, &buf) which should return the number of bytes of provided input, and a pointer to that input in buf. If there is no input available, in() must return zero--buf is ignored in that case--and inflateBack() will return a buffer error. inflateBack() will call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() should return zero on success, or non-zero on failure. If out() returns non-zero, inflateBack() will return with an error. Neither in() nor out() are permitted to change the contents of the window provided to inflateBackInit(), which is also the buffer that out() uses to write from. The length written by out() will be at most the window size. Any non-zero amount of input may be provided by in(). For convenience, inflateBack() can be provided input on the first call by setting strm->next_in and strm->avail_in. If that input is exhausted, then in() will be called. Therefore strm->next_in must be initialized before calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in must also be initialized, and then if strm->avail_in is not zero, input will initially be taken from strm->next_in[0 .. strm->avail_in - 1]. The in_desc and out_desc parameters of inflateBack() is passed as the first parameter of in() and out() respectively when they are called. These descriptors can be optionally used to pass any information that the caller- supplied in() and out() functions need to do their job. On return, inflateBack() will set strm->next_in and strm->avail_in to pass back any unused input that was provided by the last in() call. The return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR if in() or out() returned an error, Z_DATA_ERROR if there was a format error in the deflate stream (in which case strm->msg is set to indicate the nature of the error), or Z_STREAM_ERROR if the stream was not properly initialized. In the case of Z_BUF_ERROR, an input or output error can be distinguished using strm->next_in which will be Z_NULL only if in() returned an error. If strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning non-zero. (in() will always be called before out(), so strm->next_in is assured to be defined if out() returns non-zero.) Note that inflateBack() cannot return Z_OK. */ int inflateBackEnd(z_streamp strm); /* All memory allocated by inflateBackInit() is freed. inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream state was inconsistent. */ uLong zlibCompileFlags(void); /* Return flags indicating compile-time options. Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: 1.0: size of uInt 3.2: size of uLong 5.4: size of voidpf (pointer) 7.6: size of z_off_t Compiler, assembler, and debug options: 8: DEBUG 9: ASMV or ASMINF -- use ASM code 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention 11: 0 (reserved) One-time table building (smaller code, but not thread-safe if true): 12: BUILDFIXED -- build static block decoding tables when needed 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed 14,15: 0 (reserved) Library content (indicates missing functionality): 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking deflate code when not needed) 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect and decode gzip streams (to avoid linking crc code) 18-19: 0 (reserved) Operation variations (changes in library functionality): 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate 21: FASTEST -- deflate algorithm with only one, lowest compression level 22,23: 0 (reserved) The sprintf variant used by gzprintf (zero is best): 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! 26: 0 = returns value, 1 = void -- 1 means inferred string length returned Remainder: 27-31: 0 (reserved) */ #ifndef Z_SOLO /* utility functions */ /* The following utility functions are implemented on top of the basic stream-oriented functions. To simplify the interface, some default options are assumed (compression level and memory usage, standard memory allocation functions). The source code of these utility functions can be modified if you need special options. */ int compress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen); /* Compresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed buffer. compress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer. */ int compress2(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level); /* Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed buffer. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ uLong compressBound(uLong sourceLen); /* compressBound() returns an upper bound on the compressed size after compress() or compress2() on sourceLen bytes. It would be used before a compress() or compress2() call to allocate the destination buffer. */ int uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen); /* Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, destLen is the actual size of the uncompressed buffer. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In the case where there is not enough room, uncompress() will fill the output buffer with the uncompressed data up to that point. */ /* gzip file access functions */ /* This library supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio, using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. */ typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ /* gzFile gzopen(const char *path, const char *mode); Opens a gzip (.gz) file for reading or writing. The mode parameter is as in fopen ("rb" or "wb") but can also include a compression level ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression as in "wb9F". (See the description of deflateInit2 for more information about the strategy parameter.) 'T' will request transparent writing or appending with no compression and not using the gzip format. "a" can be used instead of "w" to request that the gzip stream that will be written be appended to the file. "+" will result in an error, since reading and writing to the same gzip file is not supported. The addition of "x" when writing will create the file exclusively, which fails if the file already exists. On systems that support it, the addition of "e" when reading or writing will set the flag to close the file on an execve() call. These functions, as well as gzip, will read and decode a sequence of gzip streams in a file. The append function of gzopen() can be used to create such a file. (Also see gzflush() for another way to do this.) When appending, gzopen does not test whether the file begins with a gzip stream, nor does it look for the end of the gzip streams to begin appending. gzopen will simply append a gzip stream to the existing file. gzopen can be used to read a file which is not in gzip format; in this case gzread will directly read from the file without decompression. When reading, this will be detected automatically by looking for the magic two- byte gzip header. gzopen returns NULL if the file could not be opened, if there was insufficient memory to allocate the gzFile state, or if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). errno can be checked to determine if the reason gzopen failed was that the file could not be opened. */ gzFile gzdopen(int fd, const char *mode); /* gzdopen associates a gzFile with the file descriptor fd. File descriptors are obtained from calls like open, dup, creat, pipe or fileno (if the file has been previously opened with fopen). The mode parameter is as in gzopen. The next call of gzclose on the returned gzFile will also close the file descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, mode);. The duplicated descriptor should be saved to avoid a leak, since gzdopen does not close fd if it fails. If you are using fileno() to get the file descriptor from a FILE *, then you will have to use dup() to avoid double-close()ing the file descriptor. Both gzclose() and fclose() will close the associated file descriptor, so they need to have different file descriptors. gzdopen returns NULL if there was insufficient memory to allocate the gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided), or if fd is -1. The file descriptor is not used until the next gz* read, write, seek, or close operation, so gzdopen will not detect if fd is invalid (unless fd is -1). */ int gzbuffer(gzFile file, unsigned size); /* Set the internal buffer size used by this library's functions. The default buffer size is 8192 bytes. This function must be called after gzopen() or gzdopen(), and before any other calls that read or write the file. The buffer memory allocation is always deferred to the first read or write. Two buffers are allocated, either both of the specified size when writing, or one of the specified size and the other twice that size when reading. A larger buffer size of, for example, 64K or 128K bytes will noticeably increase the speed of decompression (reading). The new buffer size also affects the maximum length for gzprintf(). gzbuffer() returns 0 on success, or -1 on failure, such as being called too late. */ int gzsetparams(gzFile file, int level, int strategy); /* Dynamically update the compression level or strategy. See the description of deflateInit2 for the meaning of these parameters. gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not opened for writing. */ int gzread(gzFile file, voidp buf, unsigned len); /* Reads the given number of uncompressed bytes from the compressed file. If the input file is not in gzip format, gzread copies the given number of bytes into the buffer directly from the file. After reaching the end of a gzip stream in the input, gzread will continue to read, looking for another gzip stream. Any number of gzip streams may be concatenated in the input file, and will all be decompressed by gzread(). If something other than a gzip stream is encountered after a gzip stream, that remaining trailing garbage is ignored (and no error is returned). gzread can be used to read a gzip file that is being concurrently written. Upon reaching the end of the input, gzread will return with the available data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then gzclearerr can be used to clear the end of file indicator in order to permit gzread to be tried again. Z_OK indicates that a gzip stream was completed on the last gzread. Z_BUF_ERROR indicates that the input file ended in the middle of a gzip stream. Note that gzread does not return -1 in the event of an incomplete gzip stream. This error is deferred until gzclose(), which will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip stream. Alternatively, gzerror can be used before gzclose to detect this case. gzread returns the number of uncompressed bytes actually read, less than len for end of file, or -1 for error. */ int gzwrite(gzFile file, voidpc buf, unsigned len); /* Writes the given number of uncompressed bytes into the compressed file. gzwrite returns the number of uncompressed bytes written or 0 in case of error. */ int gzprintf(gzFile file, const char *format, ...); /* Converts, formats, and writes the arguments to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of uncompressed bytes actually written, or 0 in case of error. The number of uncompressed bytes written is limited to 8191, or one less than the buffer size given to gzbuffer(). The caller should assure that this limit is not exceeded. If it is exceeded, then gzprintf() will return an error (0) with nothing written. In this case, there may also be a buffer overflow with unpredictable consequences, which is possible only if zlib was compiled with the insecure functions sprintf() or vsprintf() because the secure snprintf() or vsnprintf() functions were not available. This can be determined using zlibCompileFlags(). */ int gzputs(gzFile file, const char *s); /* Writes the given null-terminated string to the compressed file, excluding the terminating null character. gzputs returns the number of characters written, or -1 in case of error. */ char *gzgets(gzFile file, char *buf, int len); /* Reads bytes from the compressed file until len-1 characters are read, or a newline character is read and transferred to buf, or an end-of-file condition is encountered. If any characters are read or if len == 1, the string is terminated with a null character. If no characters are read due to an end-of-file or len < 1, then the buffer is left untouched. gzgets returns buf which is a null-terminated string, or it returns NULL for end-of-file or in case of error. If there was an error, the contents at buf are indeterminate. */ int gzputc(gzFile file, int c); /* Writes c, converted to an unsigned char, into the compressed file. gzputc returns the value that was written, or -1 in case of error. */ int gzgetc(gzFile file); /* Reads one byte from the compressed file. gzgetc returns this byte or -1 in case of end of file or error. This is implemented as a macro for speed. As such, it does not do all of the checking the other functions do. I.e. it does not check to see if file is NULL, nor whether the structure file points to has been clobbered or not. */ int gzungetc(int c, gzFile file); /* Push one character back onto the stream to be read as the first character on the next read. At least one character of push-back is allowed. gzungetc() returns the character pushed, or -1 on failure. gzungetc() will fail if c is -1, and may fail if a character has been pushed but not read yet. If gzungetc is used immediately after gzopen or gzdopen, at least the output buffer size of pushed characters is allowed. (See gzbuffer above.) The pushed character will be discarded if the stream is repositioned with gzseek() or gzrewind(). */ int gzflush(gzFile file, int flush); /* Flushes all pending output into the compressed file. The parameter flush is as in the deflate() function. The return value is the zlib error number (see function gzerror below). gzflush is only permitted when writing. If the flush parameter is Z_FINISH, the remaining data is written and the gzip stream is completed in the output. If gzwrite() is called again, a new gzip stream will be started in the output. gzread() is able to read such concatented gzip streams. gzflush should be called only when strictly necessary because it will degrade compression if called too often. */ /* z_off_t gzseek(gzFile file, z_off_t offset, int whence); Sets the starting position for the next gzread or gzwrite on the given compressed file. The offset represents a number of bytes in the uncompressed data stream. The whence parameter is defined as in lseek(2); the value SEEK_END is not supported. If the file is opened for reading, this function is emulated but can be extremely slow. If the file is opened for writing, only forward seeks are supported; gzseek then compresses a sequence of zeroes up to the new starting position. gzseek returns the resulting offset location as measured in bytes from the beginning of the uncompressed stream, or -1 in case of error, in particular if the file is opened for writing and the new starting position would be before the current position. */ int gzrewind(gzFile file); /* Rewinds the given file. This function is supported only for reading. gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) */ /* z_off_t gztell(gzFile file); Returns the starting position for the next gzread or gzwrite on the given compressed file. This position represents a number of bytes in the uncompressed data stream, and is zero when starting, even if appending or reading a gzip stream from the middle of a file using gzdopen(). gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) */ /* z_off_t gzoffset(gzFile file); Returns the current offset in the file being read or written. This offset includes the count of bytes that precede the gzip stream, for example when appending or when using gzdopen() for reading. When reading, the offset does not include as yet unused buffered input. This information can be used for a progress indicator. On error, gzoffset() returns -1. */ int gzeof(gzFile file); /* Returns true (1) if the end-of-file indicator has been set while reading, false (0) otherwise. Note that the end-of-file indicator is set only if the read tried to go past the end of the input, but came up short. Therefore, just like feof(), gzeof() may return false even if there is no more data to read, in the event that the last read request was for the exact number of bytes remaining in the input file. This will happen if the input file size is an exact multiple of the buffer size. If gzeof() returns true, then the read functions will return no more data, unless the end-of-file indicator is reset by gzclearerr() and the input file has grown since the previous end of file was detected. */ int gzdirect(gzFile file); /* Returns true (1) if file is being copied directly while reading, or false (0) if file is a gzip stream being decompressed. If the input file is empty, gzdirect() will return true, since the input does not contain a gzip stream. If gzdirect() is used immediately after gzopen() or gzdopen() it will cause buffers to be allocated to allow reading the file to determine if it is a gzip file. Therefore if gzbuffer() is used, it should be called before gzdirect(). When writing, gzdirect() returns true (1) if transparent writing was requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: gzdirect() is not needed when writing. Transparent writing must be explicitly requested, so the application already knows the answer. When linking statically, using gzdirect() will include all of the zlib code for gzip file reading and decompression, which may not be desired.) */ int gzclose(gzFile file); /* Flushes all pending output if necessary, closes the compressed file and deallocates the (de)compression state. Note that once file is closed, you cannot call gzerror with file, since its structures have been deallocated. gzclose must not be called more than once on the same file, just as free must not be called more than once on the same allocation. gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the last read ended in the middle of a gzip stream, or Z_OK on success. */ int gzclose_r(gzFile file); int gzclose_w(gzFile file); /* Same as gzclose(), but gzclose_r() is only for use when reading, and gzclose_w() is only for use when writing or appending. The advantage to using these instead of gzclose() is that they avoid linking in zlib compression or decompression code that is not used when only reading or only writing respectively. If gzclose() is used, then both compression and decompression code will be included the application when linking to a static zlib library. */ const char *gzerror(gzFile file, int *errnum); /* Returns the error message for the last error which occurred on the given compressed file. errnum is set to zlib error number. If an error occurred in the file system and not in the compression library, errnum is set to Z_ERRNO and the application may consult errno to get the exact error code. The application must not modify the returned string. Future calls to this function may invalidate the previously returned string. If file is closed, then the string previously returned by gzerror will no longer be available. gzerror() should be used to distinguish errors from end-of-file for those functions above that do not distinguish those cases in their return values. */ void gzclearerr(gzFile file); /* Clears the error and end-of-file flags for file. This is analogous to the clearerr() function in stdio. This is useful for continuing to read a gzip file that is being written concurrently. */ #endif /* !Z_SOLO */ /* checksum functions */ /* These functions are not related to compression but are exported anyway because they might be useful in applications using the compression library. */ uLong adler32(uLong adler, const Bytef *buf, uInt len); /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and return the updated checksum. If buf is Z_NULL, this function returns the required initial value for the checksum. An Adler-32 checksum is almost as reliable as a CRC32 but can be computed much faster. Usage example: uLong adler = adler32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { adler = adler32(adler, buffer, length); } if (adler != original_adler) error(); */ /* uLong adler32_combine(uLong adler1, uLong adler2, z_off_t len2); Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note that the z_off_t type (like off_t) is a signed integer. If len2 is negative, the result has no meaning or utility. */ uLong crc32(uLong crc, const Bytef *buf, uInt len); /* Update a running CRC-32 with the bytes buf[0..len-1] and return the updated CRC-32. If buf is Z_NULL, this function returns the required initial value for the crc. Pre- and post-conditioning (one's complement) is performed within this function so it shouldn't be done by the application. Usage example: uLong crc = crc32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { crc = crc32(crc, buffer, length); } if (crc != original_crc) error(); */ /* uLong crc32_combine(uLong crc1, uLong crc2, z_off_t len2); Combine two CRC-32 check values into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, CRC-32 check values were calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and len2. */ /* various hacks, don't look :) */ /* deflateInit and inflateInit are macros to allow checking the zlib version * and the compiler's view of z_stream: */ int deflateInit_(z_streamp strm, int level, const char *version, int stream_size); int inflateInit_(z_streamp strm, const char *version, int stream_size); int deflateInit2_(z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size); int inflateInit2_(z_streamp strm, int windowBits, const char *version, int stream_size); int inflateBackInit_(z_streamp strm, int windowBits, unsigned char *window, const char *version, int stream_size); #define deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) #define inflateInit(strm) \ inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) #define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) #define inflateInit2(strm, windowBits) \ inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ (int)sizeof(z_stream)) #define inflateBackInit(strm, windowBits, window) \ inflateBackInit_((strm), (windowBits), (window), \ ZLIB_VERSION, (int)sizeof(z_stream)) #ifndef Z_SOLO /* gzgetc() macro and its supporting function and exposed data structure. Note * that the real internal state is much larger than the exposed structure. * This abbreviated structure exposes just enough for the gzgetc() macro. The * user should not mess with these exposed elements, since their names or * behavior could change in the future, perhaps even capriciously. They can * only be used by the gzgetc() macro. You have been warned. */ struct gzFile_s { unsigned have; unsigned char *next; z_off64_t pos; }; gzFile gzopen(const char *, const char *); z_off_t gzseek(gzFile, z_off_t, int); z_off_t gztell(gzFile); z_off_t gzoffset(gzFile); uLong adler32_combine(uLong, uLong, z_off_t); uLong crc32_combine(uLong, uLong, z_off_t); #else /* Z_SOLO */ uLong adler32_combine(uLong, uLong, z_off_t); uLong crc32_combine(uLong, uLong, z_off_t); #endif /* !Z_SOLO */ /* undocumented functions */ const char *zError(int); int inflateSyncPoint(z_streamp); const z_crc_t *get_crc_table(void); int inflateUndermine(z_streamp, int); int inflateResetKeep(z_streamp); int deflateResetKeep(z_streamp); #endif /* ZLIB_H */ /* eof */ Rglpk/src/GLPK/zlib/compress.c0000644000176000001440000000472612245352174015662 0ustar ripleyusers/* compress.c */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* compress.c -- compress a memory buffer * Copyright (C) 1995-2005 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zlib.h" /* =========================================================================== Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least 0.1% larger than sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ int compress2(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level) { z_stream stream; int err; stream.next_in = (Bytef*)source; stream.avail_in = (uInt)sourceLen; #if 0 /* by mao; #ifdef MAXSEG_64K */ /* Check for source > 64K on 16-bit machine: */ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; #endif stream.next_out = dest; stream.avail_out = (uInt)*destLen; if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; stream.opaque = (voidpf)0; err = deflateInit(&stream, level); if (err != Z_OK) return err; err = deflate(&stream, Z_FINISH); if (err != Z_STREAM_END) { deflateEnd(&stream); return err == Z_OK ? Z_BUF_ERROR : err; } *destLen = stream.total_out; err = deflateEnd(&stream); return err; } /* =========================================================================== */ int compress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen) { return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); } /* =========================================================================== If the default memLevel or windowBits for deflateInit() is changed, then this function needs to be updated. */ uLong compressBound(uLong sourceLen) { return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13; } /* eof */ Rglpk/src/GLPK/zlib/gzguts.h0000644000176000001440000000673412245352174015360 0ustar ripleyusers/* gzguts.h */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* gzguts.h -- zlib internal header definitions for gz* operations * Copyright (C) 2004, 2005, 2010, 2011, 2012 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include #include #include #include #include #include #include "zio.h" #include "zlib.h" /* get errno and strerror definition */ #define zstrerror() strerror(errno) gzFile gzopen64(const char *, const char *); z_off64_t gzseek64(gzFile, z_off64_t, int); z_off64_t gztell64(gzFile); z_off64_t gzoffset64(gzFile); /* default memLevel */ #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif /* default i/o buffer size -- double this for output when reading */ #define GZBUFSIZE 8192 /* gzip modes, also provide a little integrity check on the passed structure */ #define GZ_NONE 0 #define GZ_READ 7247 #define GZ_WRITE 31153 #define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ /* values for gz_state how */ #define LOOK 0 /* look for a gzip header */ #define COPY 1 /* copy input directly */ #define GZIP 2 /* decompress a gzip stream */ /* internal gzip file state data structure */ typedef struct { /* exposed contents for gzgetc() macro */ struct gzFile_s x; /* "x" for exposed */ /* x.have: number of bytes available at x.next */ /* x.next: next output data to deliver or write */ /* x.pos: current position in uncompressed data */ /* used for both reading and writing */ int mode; /* see gzip modes above */ int fd; /* file descriptor */ char *path; /* path or fd for error messages */ unsigned size; /* buffer size, zero if not allocated yet */ unsigned want; /* requested buffer size, default is GZBUFSIZE */ unsigned char *in; /* input buffer */ unsigned char *out; /* output buffer (double-sized when reading) */ int direct; /* 0 if processing gzip, 1 if transparent */ /* just for reading */ int how; /* 0: get header, 1: copy, 2: decompress */ z_off64_t start; /* where the gzip data started, for rewinding */ int eof; /* true if end of input file reached */ int past; /* true if read requested past end */ /* just for writing */ int level; /* compression level */ int strategy; /* compression strategy */ /* seek request */ z_off64_t skip; /* amount to skip (already rewound if backwards) */ int seek; /* true if seek request pending */ /* error information */ int err; /* error code */ char *msg; /* error message */ /* zlib inflate or deflate stream */ z_stream strm; /* stream structure in-place (not a pointer) */ } gz_state; typedef gz_state *gz_statep; void gz_error (gz_statep, int, const char *); /* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t value -- needed when comparing unsigned to z_off64_t, which is signed (possible z_off64_t types off_t, off64_t, and long are all signed) */ #define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) /* eof */ Rglpk/src/GLPK/zlib/zsymb.h0000644000176000001440000001124112245352174015166 0ustar ripleyusers/* zsymb.h */ /* Written by Andrew Makhorin , June 2013 * For conditions of distribution and use, see copyright notice in * zlib.h */ #ifndef ZSYMB_H #define ZSYMB_H /* (adler32.c) */ #define adler32 zlib_adler32 #define adler32_combine zlib_adler32_combine #define adler32_combine64 zlib_adler32_combine64 /* (compress.c) */ #define compress2 zlib_compress2 #define compress zlib_compress #define compressBound zlib_compressBound /* (crc32.c) */ #define get_crc_table zlib_get_crc_table #define crc32 zlib_crc32 #define crc32_combine zlib_crc32_combine #define crc32_combine64 zlib_crc32_combine64 /* (deflate.c) */ #define deflate_copyright zlib_deflate_copyright #define deflateInit_ zlib_deflateInit_ #define deflateInit2_ zlib_deflateInit2_ #define deflateSetDictionary zlib_deflateSetDictionary #define deflateResetKeep zlib_deflateResetKeep #define deflateReset zlib_deflateReset #define deflateSetHeader zlib_deflateSetHeader #define deflatePending zlib_deflatePending #define deflatePrime zlib_deflatePrime #define deflateParams zlib_deflateParams #define deflateTune zlib_deflateTune #define deflateBound zlib_deflateBound #define deflate zlib_deflate #define deflateEnd zlib_deflateEnd #define deflateCopy zlib_deflateCopy /* (gzclose.c) */ #define gzclose zlib_gzclose /* (gzlib.c) */ #define gzopen zlib_gzopen #define gzopen64 zlib_gzopen64 #define gzdopen zlib_gzdopen #define gzbuffer zlib_gzbuffer #define gzrewind zlib_gzrewind #define gzseek64 zlib_gzseek64 #define gzseek zlib_gzseek #define gztell64 zlib_gztell64 #define gztell zlib_gztell #define gzoffset64 zlib_gzoffset64 #define gzoffset zlib_gzoffset #define gzeof zlib_gzeof #define gzerror zlib_gzerror #define gzclearerr zlib_gzclearerr #define gz_error zlib_gz_error /* (gzread.c) */ #define gzread zlib_gzread #define gzgetc zlib_gzgetc #define gzungetc zlib_gzungetc #define gzgets zlib_gzgets #define gzdirect zlib_gzdirect #define gzclose_r zlib_gzclose_r /* (gzwrite.c) */ #define gzwrite zlib_gzwrite #define gzputc zlib_gzputc #define gzputs zlib_gzputs #define gzprintf zlib_gzprintf #define gzflush zlib_gzflush #define gzsetparams zlib_gzsetparams #define gzclose_w zlib_gzclose_w /* (inffast.c) */ #define inflate_fast zlib_inflate_fast /* (inflate.c) */ #define inflate_copyright zlib_inflate_copyright #define inflateResetKeep zlib_inflateResetKeep #define inflateReset zlib_inflateReset #define inflateReset2 zlib_inflateReset2 #define inflateInit2_ zlib_inflateInit2_ #define inflateInit_ zlib_inflateInit_ #define inflatePrime zlib_inflatePrime #define inflate zlib_inflate #define inflateEnd zlib_inflateEnd #define inflateSetDictionary zlib_inflateSetDictionary #define inflateGetHeader zlib_inflateGetHeader #define inflateSync zlib_inflateSync #define inflateSyncPoint zlib_inflateSyncPoint #define inflateCopy zlib_inflateCopy #define inflateUndermine zlib_inflateUndermine #define inflateMark zlib_inflateMark /* (inftrees.c) */ #define inflate_table zlib_inflate_table /* (trees.c) */ #define _dist_code zlib_dist_code #define _length_code zlib_length_code #define _tr_init zlib_tr_init #define _tr_stored_block zlib_tr_stored_block #define _tr_flush_bits zlib_tr_flush_bits #define _tr_align zlib_tr_align #define _tr_flush_block zlib_tr_flush_block #define _tr_tally zlib_tr_tally /* (uncompr.c) */ #define uncompress zlib_uncompress /* (zio.c) */ #define open zlib_open #define read zlib_read #define write zlib_write #define lseek zlib_lseek #define close zlib_close /* (zutil.c) */ #define z_errmsg zlib_z_errmsg #define zlibVersion zlib_zlibVersion #define zlibCompileFlags zlib_zlibCompileFlags #define z_error zlib_z_error #define zError zlib_zError #define zcalloc zlib_zcalloc #define zcfree zlib_zcfree #endif /* eof */ Rglpk/src/GLPK/zlib/uncompr.c0000644000176000001440000000400412245352174015477 0ustar ripleyusers/* uncompr.c */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* uncompr.c -- decompress a memory buffer * Copyright (C) 1995-2003, 2010 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zlib.h" /* =========================================================================== Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, destLen is the actual size of the compressed buffer. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted. */ int uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen) { z_stream stream; int err; stream.next_in = (Bytef*)source; stream.avail_in = (uInt)sourceLen; /* Check for source > 64K on 16-bit machine: */ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; stream.next_out = dest; stream.avail_out = (uInt)*destLen; if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; err = inflateInit(&stream); if (err != Z_OK) return err; err = inflate(&stream, Z_FINISH); if (err != Z_STREAM_END) { inflateEnd(&stream); if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) return Z_DATA_ERROR; return err; } *destLen = stream.total_out; err = inflateEnd(&stream); return err; } /* eof */ Rglpk/src/GLPK/zlib/deflate.c0000644000176000001440000021150212245352174015423 0ustar ripleyusers/* deflate.c */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* deflate.c -- compress data using the deflation algorithm * Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * ALGORITHM * * The "deflation" process depends on being able to identify portions * of the input text which are identical to earlier input (within a * sliding window trailing behind the input currently being processed). * * The most straightforward technique turns out to be the fastest for * most input files: try all possible matches and select the longest. * The key feature of this algorithm is that insertions into the string * dictionary are very simple and thus fast, and deletions are avoided * completely. Insertions are performed at each input character, whereas * string matches are performed only when the previous match ends. So it * is preferable to spend more time in matches to allow very fast string * insertions and avoid deletions. The matching algorithm for small * strings is inspired from that of Rabin & Karp. A brute force approach * is used to find longer strings when a small match has been found. * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze * (by Leonid Broukhis). * A previous version of this file used a more sophisticated algorithm * (by Fiala and Greene) which is guaranteed to run in linear amortized * time, but has a larger average cost, uses more memory and is patented. * However the F&G algorithm may be faster for some highly redundant * files if the parameter max_chain_length (described below) is too large. * * ACKNOWLEDGEMENTS * * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and * I found it in 'freeze' written by Leonid Broukhis. * Thanks to many people for bug reports and testing. * * REFERENCES * * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". * Available in http://tools.ietf.org/html/rfc1951 * * A description of the Rabin and Karp algorithm is given in the book * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. * * Fiala,E.R., and Greene,D.H. * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 * */ #include "deflate.h" const char deflate_copyright[] = " deflate 1.2.7 Copyright 1995-2012 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ /* =========================================================================== * Function prototypes. */ typedef enum { need_more, /* block not completed, need more input or more output */ block_done, /* block flush performed */ finish_started, /* finish started, need only more output at next deflate */ finish_done /* finish done, accept no more input or output */ } block_state; typedef block_state (*compress_func)(deflate_state *s, int flush); /* Compression function. Returns the block state after the call. */ static void fill_window(deflate_state *s); static block_state deflate_stored(deflate_state *s, int flush); static block_state deflate_fast(deflate_state *s, int flush); #ifndef FASTEST static block_state deflate_slow(deflate_state *s, int flush); #endif static block_state deflate_rle(deflate_state *s, int flush); static block_state deflate_huff(deflate_state *s, int flush); static void lm_init(deflate_state *s); static void putShortMSB(deflate_state *s, uInt b); static void flush_pending(z_streamp strm); static int read_buf(z_streamp strm, Bytef *buf, unsigned size); static uInt longest_match(deflate_state *s, IPos cur_match); #ifdef DEBUG static void check_match(deflate_state *s, IPos start, IPos match, int length); #endif /* =========================================================================== * Local data */ #define NIL 0 /* Tail of hash chains */ #ifndef TOO_FAR # define TOO_FAR 4096 #endif /* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ /* Values for max_lazy_match, good_match and max_chain_length, depending on * the desired pack level (0..9). The values given below have been tuned to * exclude worst case performance for pathological files. Better values may be * found for specific files. */ typedef struct config_s { ush good_length; /* reduce lazy search above this match length */ ush max_lazy; /* do not perform lazy search above this match length */ ush nice_length; /* quit search above this match length */ ush max_chain; compress_func func; } config; #ifdef FASTEST static const config configuration_table[2] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ /* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ #else static const config configuration_table[10] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ /* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ /* 2 */ {4, 5, 16, 8, deflate_fast}, /* 3 */ {4, 6, 32, 32, deflate_fast}, /* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ /* 5 */ {8, 16, 32, 32, deflate_slow}, /* 6 */ {8, 16, 128, 128, deflate_slow}, /* 7 */ {8, 32, 128, 256, deflate_slow}, /* 8 */ {32, 128, 258, 1024, deflate_slow}, /* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ #endif /* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 * For deflate_fast() (levels <= 3) good is ignored and lazy has a different * meaning. */ #define EQUAL 0 /* result of memcmp for equal strings */ #ifndef NO_DUMMY_DECL struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ #endif /* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ #define RANK(f) (((f) << 1) - ((f) > 4 ? 9 : 0)) /* =========================================================================== * Update a hash value with the given input byte * IN assertion: all calls to to UPDATE_HASH are made with consecutive * input characters, so that a running hash key can be computed from the * previous key instead of complete recalculation each time. */ #define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) /* =========================================================================== * Insert string str in the dictionary and set match_head to the previous head * of the hash chain (the most recent string with same hash key). Return * the previous length of the hash chain. * If this file is compiled with -DFASTEST, the compression level is forced * to 1, and no hash chains are maintained. * IN assertion: all calls to to INSERT_STRING are made with consecutive * input characters and the first MIN_MATCH bytes of str are valid * (except for the last MIN_MATCH-1 bytes of the input file). */ #ifdef FASTEST #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ match_head = s->head[s->ins_h], \ s->head[s->ins_h] = (Pos)(str)) #else #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ s->head[s->ins_h] = (Pos)(str)) #endif /* =========================================================================== * Initialize the hash table (avoiding 64K overflow for 16 bit systems). * prev[] will be initialized on the fly. */ #define CLEAR_HASH(s) \ s->head[s->hash_size-1] = NIL; \ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); /* ========================================================================= */ int deflateInit_(z_streamp strm, int level, const char *version, int stream_size) { return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, version, stream_size); /* To do: ignore strm->next_in if we use it as window */ } /* ========================================================================= */ int deflateInit2_(z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size) { deflate_state *s; int wrap = 1; static const char my_version[] = ZLIB_VERSION; ushf *overlay; /* We overlay pending_buf and d_buf+l_buf. This works since the average * output size for (length,distance) codes is <= 24 bits. */ if (version == Z_NULL || version[0] != my_version[0] || stream_size != sizeof(z_stream)) { return Z_VERSION_ERROR; } if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; if (strm->zalloc == (alloc_func)0) { #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; #endif } if (strm->zfree == (free_func)0) #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zfree = zcfree; #endif #ifdef FASTEST if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif if (windowBits < 0) { /* suppress zlib wrapper */ wrap = 0; windowBits = -windowBits; } #ifdef GZIP else if (windowBits > 15) { wrap = 2; /* write gzip wrapper instead */ windowBits -= 16; } #endif if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); if (s == Z_NULL) return Z_MEM_ERROR; strm->state = (struct internal_state *)s; s->strm = strm; s->wrap = wrap; s->gzhead = Z_NULL; s->w_bits = windowBits; s->w_size = 1 << s->w_bits; s->w_mask = s->w_size - 1; s->hash_bits = memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); s->high_water = 0; /* nothing written to s->window yet */ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); s->pending_buf = (uchf *) overlay; s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || s->pending_buf == Z_NULL) { s->status = FINISH_STATE; strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); deflateEnd (strm); return Z_MEM_ERROR; } s->d_buf = overlay + s->lit_bufsize/sizeof(ush); s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; s->level = level; s->strategy = strategy; s->method = (Byte)method; return deflateReset(strm); } /* ========================================================================= */ int deflateSetDictionary(z_streamp strm, const Bytef *dictionary, uInt dictLength) { deflate_state *s; uInt str, n; int wrap; unsigned avail; unsigned char *next; if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL) return Z_STREAM_ERROR; s = strm->state; wrap = s->wrap; if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) return Z_STREAM_ERROR; /* when using zlib wrappers, compute Adler-32 for provided dictionary */ if (wrap == 1) strm->adler = adler32(strm->adler, dictionary, dictLength); s->wrap = 0; /* avoid computing Adler-32 in read_buf */ /* if dictionary would fill window, just replace the history */ if (dictLength >= s->w_size) { if (wrap == 0) { /* already empty otherwise */ CLEAR_HASH(s); s->strstart = 0; s->block_start = 0L; s->insert = 0; } dictionary += dictLength - s->w_size; /* use the tail */ dictLength = s->w_size; } /* insert dictionary into window and hash */ avail = strm->avail_in; next = strm->next_in; strm->avail_in = dictLength; strm->next_in = (Bytef *)dictionary; fill_window(s); while (s->lookahead >= MIN_MATCH) { str = s->strstart; n = s->lookahead - (MIN_MATCH-1); do { UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); #ifndef FASTEST s->prev[str & s->w_mask] = s->head[s->ins_h]; #endif s->head[s->ins_h] = (Pos)str; str++; } while (--n); s->strstart = str; s->lookahead = MIN_MATCH-1; fill_window(s); } s->strstart += s->lookahead; s->block_start = (long)s->strstart; s->insert = s->lookahead; s->lookahead = 0; s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; strm->next_in = next; strm->avail_in = avail; s->wrap = wrap; return Z_OK; } /* ========================================================================= */ int deflateResetKeep(z_streamp strm) { deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { return Z_STREAM_ERROR; } strm->total_in = strm->total_out = 0; strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ strm->data_type = Z_UNKNOWN; s = (deflate_state *)strm->state; s->pending = 0; s->pending_out = s->pending_buf; if (s->wrap < 0) { s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ } s->status = s->wrap ? INIT_STATE : BUSY_STATE; strm->adler = #ifdef GZIP s->wrap == 2 ? crc32(0L, Z_NULL, 0) : #endif adler32(0L, Z_NULL, 0); s->last_flush = Z_NO_FLUSH; _tr_init(s); return Z_OK; } /* ========================================================================= */ int deflateReset(z_streamp strm) { int ret; ret = deflateResetKeep(strm); if (ret == Z_OK) lm_init(strm->state); return ret; } /* ========================================================================= */ int deflateSetHeader(z_streamp strm, gz_headerp head) { if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; if (strm->state->wrap != 2) return Z_STREAM_ERROR; strm->state->gzhead = head; return Z_OK; } /* ========================================================================= */ int deflatePending(z_streamp strm, unsigned *pending, int *bits) { if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; if (pending != Z_NULL) *pending = strm->state->pending; if (bits != Z_NULL) *bits = strm->state->bi_valid; return Z_OK; } /* ========================================================================= */ int deflatePrime(z_streamp strm, int bits, int value) { deflate_state *s; int put; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; s = strm->state; if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3)) return Z_BUF_ERROR; do { put = Buf_size - s->bi_valid; if (put > bits) put = bits; s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); s->bi_valid += put; _tr_flush_bits(s); value >>= put; bits -= put; } while (bits); return Z_OK; } /* ========================================================================= */ int deflateParams(z_streamp strm, int level, int strategy) { deflate_state *s; compress_func func; int err = Z_OK; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; s = strm->state; #ifdef FASTEST if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } func = configuration_table[s->level].func; if ((strategy != s->strategy || func != configuration_table[level].func) && strm->total_in != 0) { /* Flush the last buffer: */ err = deflate(strm, Z_BLOCK); } if (s->level != level) { s->level = level; s->max_lazy_match = configuration_table[level].max_lazy; s->good_match = configuration_table[level].good_length; s->nice_match = configuration_table[level].nice_length; s->max_chain_length = configuration_table[level].max_chain; } s->strategy = strategy; return err; } /* ========================================================================= */ int deflateTune(z_streamp strm, int good_length, int max_lazy, int nice_length, int max_chain) { deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; s = strm->state; s->good_match = good_length; s->max_lazy_match = max_lazy; s->nice_match = nice_length; s->max_chain_length = max_chain; return Z_OK; } /* ========================================================================= * For the default windowBits of 15 and memLevel of 8, this function returns * a close to exact, as well as small, upper bound on the compressed size. * They are coded as constants here for a reason--if the #define's are * changed, then this function needs to be changed as well. The return * value for 15 and 8 only works for those exact settings. * * For any setting other than those defaults for windowBits and memLevel, * the value returned is a conservative worst case for the maximum expansion * resulting from using fixed blocks instead of stored blocks, which deflate * can emit on compressed data for some combinations of the parameters. * * This function could be more sophisticated to provide closer upper bounds for * every combination of windowBits and memLevel. But even the conservative * upper bound of about 14% expansion does not seem onerous for output buffer * allocation. */ uLong deflateBound(z_streamp strm, uLong sourceLen) { deflate_state *s; uLong complen, wraplen; Bytef *str; /* conservative upper bound for compressed data */ complen = sourceLen + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; /* if can't get parameters, return conservative bound plus zlib wrapper */ if (strm == Z_NULL || strm->state == Z_NULL) return complen + 6; /* compute wrapper length */ s = strm->state; switch (s->wrap) { case 0: /* raw deflate */ wraplen = 0; break; case 1: /* zlib wrapper */ wraplen = 6 + (s->strstart ? 4 : 0); break; case 2: /* gzip wrapper */ wraplen = 18; if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ if (s->gzhead->extra != Z_NULL) wraplen += 2 + s->gzhead->extra_len; str = s->gzhead->name; if (str != Z_NULL) do { wraplen++; } while (*str++); str = s->gzhead->comment; if (str != Z_NULL) do { wraplen++; } while (*str++); if (s->gzhead->hcrc) wraplen += 2; } break; default: /* for compiler happiness */ wraplen = 6; } /* if not default parameters, return conservative bound */ if (s->w_bits != 15 || s->hash_bits != 8 + 7) return complen + wraplen; /* default settings: return tight bound for that case */ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13 - 6 + wraplen; } /* ========================================================================= * Put a short in the pending buffer. The 16-bit value is put in MSB order. * IN assertion: the stream state is correct and there is enough room in * pending_buf. */ static void putShortMSB(deflate_state *s, uInt b) { put_byte(s, (Byte)(b >> 8)); put_byte(s, (Byte)(b & 0xff)); } /* ========================================================================= * Flush as much pending output as possible. All deflate() output goes * through this function so some applications may wish to modify it * to avoid allocating a large strm->next_out buffer and copying into it. * (See also read_buf()). */ static void flush_pending(z_streamp strm) { unsigned len; deflate_state *s = strm->state; _tr_flush_bits(s); len = s->pending; if (len > strm->avail_out) len = strm->avail_out; if (len == 0) return; zmemcpy(strm->next_out, s->pending_out, len); strm->next_out += len; s->pending_out += len; strm->total_out += len; strm->avail_out -= len; s->pending -= len; if (s->pending == 0) { s->pending_out = s->pending_buf; } } /* ========================================================================= */ int deflate(z_streamp strm, int flush) { int old_flush; /* value of flush param for previous deflate call */ deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL || flush > Z_BLOCK || flush < 0) { return Z_STREAM_ERROR; } s = strm->state; if (strm->next_out == Z_NULL || (strm->next_in == Z_NULL && strm->avail_in != 0) || (s->status == FINISH_STATE && flush != Z_FINISH)) { ERR_RETURN(strm, Z_STREAM_ERROR); } if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); s->strm = strm; /* just in case */ old_flush = s->last_flush; s->last_flush = flush; /* Write the header */ if (s->status == INIT_STATE) { #ifdef GZIP if (s->wrap == 2) { strm->adler = crc32(0L, Z_NULL, 0); put_byte(s, 31); put_byte(s, 139); put_byte(s, 8); if (s->gzhead == Z_NULL) { put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, s->level == 9 ? 2 : (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); put_byte(s, OS_CODE); s->status = BUSY_STATE; } else { put_byte(s, (s->gzhead->text ? 1 : 0) + (s->gzhead->hcrc ? 2 : 0) + (s->gzhead->extra == Z_NULL ? 0 : 4) + (s->gzhead->name == Z_NULL ? 0 : 8) + (s->gzhead->comment == Z_NULL ? 0 : 16) ); put_byte(s, (Byte)(s->gzhead->time & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); put_byte(s, s->level == 9 ? 2 : (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); put_byte(s, s->gzhead->os & 0xff); if (s->gzhead->extra != Z_NULL) { put_byte(s, s->gzhead->extra_len & 0xff); put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); } if (s->gzhead->hcrc) strm->adler = crc32(strm->adler, s->pending_buf, s->pending); s->gzindex = 0; s->status = EXTRA_STATE; } } else #endif { uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; uInt level_flags; if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) level_flags = 0; else if (s->level < 6) level_flags = 1; else if (s->level == 6) level_flags = 2; else level_flags = 3; header |= (level_flags << 6); if (s->strstart != 0) header |= PRESET_DICT; header += 31 - (header % 31); s->status = BUSY_STATE; putShortMSB(s, header); /* Save the adler32 of the preset dictionary: */ if (s->strstart != 0) { putShortMSB(s, (uInt)(strm->adler >> 16)); putShortMSB(s, (uInt)(strm->adler & 0xffff)); } strm->adler = adler32(0L, Z_NULL, 0); } } #ifdef GZIP if (s->status == EXTRA_STATE) { if (s->gzhead->extra != Z_NULL) { uInt beg = s->pending; /* start of bytes to update crc */ while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { if (s->pending == s->pending_buf_size) { if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); flush_pending(strm); beg = s->pending; if (s->pending == s->pending_buf_size) break; } put_byte(s, s->gzhead->extra[s->gzindex]); s->gzindex++; } if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); if (s->gzindex == s->gzhead->extra_len) { s->gzindex = 0; s->status = NAME_STATE; } } else s->status = NAME_STATE; } if (s->status == NAME_STATE) { if (s->gzhead->name != Z_NULL) { uInt beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) { if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); flush_pending(strm); beg = s->pending; if (s->pending == s->pending_buf_size) { val = 1; break; } } val = s->gzhead->name[s->gzindex++]; put_byte(s, val); } while (val != 0); if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); if (val == 0) { s->gzindex = 0; s->status = COMMENT_STATE; } } else s->status = COMMENT_STATE; } if (s->status == COMMENT_STATE) { if (s->gzhead->comment != Z_NULL) { uInt beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) { if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); flush_pending(strm); beg = s->pending; if (s->pending == s->pending_buf_size) { val = 1; break; } } val = s->gzhead->comment[s->gzindex++]; put_byte(s, val); } while (val != 0); if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); if (val == 0) s->status = HCRC_STATE; } else s->status = HCRC_STATE; } if (s->status == HCRC_STATE) { if (s->gzhead->hcrc) { if (s->pending + 2 > s->pending_buf_size) flush_pending(strm); if (s->pending + 2 <= s->pending_buf_size) { put_byte(s, (Byte)(strm->adler & 0xff)); put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); strm->adler = crc32(0L, Z_NULL, 0); s->status = BUSY_STATE; } } else s->status = BUSY_STATE; } #endif /* Flush as much pending output as possible */ if (s->pending != 0) { flush_pending(strm); if (strm->avail_out == 0) { /* Since avail_out is 0, deflate will be called again with * more output space, but possibly with both pending and * avail_in equal to zero. There won't be anything to do, * but this is not an error situation so make sure we * return OK instead of BUF_ERROR at next call of deflate: */ s->last_flush = -1; return Z_OK; } /* Make sure there is something to do and avoid duplicate consecutive * flushes. For repeated and useless calls with Z_FINISH, we keep * returning Z_STREAM_END instead of Z_BUF_ERROR. */ } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && flush != Z_FINISH) { ERR_RETURN(strm, Z_BUF_ERROR); } /* User must not provide more input after the first FINISH: */ if (s->status == FINISH_STATE && strm->avail_in != 0) { ERR_RETURN(strm, Z_BUF_ERROR); } /* Start a new block or continue the current one. */ if (strm->avail_in != 0 || s->lookahead != 0 || (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { block_state bstate; bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : (s->strategy == Z_RLE ? deflate_rle(s, flush) : (*(configuration_table[s->level].func))(s, flush)); if (bstate == finish_started || bstate == finish_done) { s->status = FINISH_STATE; } if (bstate == need_more || bstate == finish_started) { if (strm->avail_out == 0) { s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ } return Z_OK; /* If flush != Z_NO_FLUSH && avail_out == 0, the next call * of deflate should use the same flush parameter to make sure * that the flush is complete. So we don't have to output an * empty block here, this will be done at next call. This also * ensures that for a very small output buffer, we emit at most * one empty block. */ } if (bstate == block_done) { if (flush == Z_PARTIAL_FLUSH) { _tr_align(s); } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ _tr_stored_block(s, (char*)0, 0L, 0); /* For a full flush, this empty block will be recognized * as a special marker by inflate_sync(). */ if (flush == Z_FULL_FLUSH) { CLEAR_HASH(s); /* forget history */ if (s->lookahead == 0) { s->strstart = 0; s->block_start = 0L; s->insert = 0; } } } flush_pending(strm); if (strm->avail_out == 0) { s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ return Z_OK; } } } Assert(strm->avail_out > 0, "bug2"); if (flush != Z_FINISH) return Z_OK; if (s->wrap <= 0) return Z_STREAM_END; /* Write the trailer */ #ifdef GZIP if (s->wrap == 2) { put_byte(s, (Byte)(strm->adler & 0xff)); put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); put_byte(s, (Byte)(strm->total_in & 0xff)); put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); } else #endif { putShortMSB(s, (uInt)(strm->adler >> 16)); putShortMSB(s, (uInt)(strm->adler & 0xffff)); } flush_pending(strm); /* If avail_out is zero, the application will call deflate again * to flush the rest. */ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ return s->pending != 0 ? Z_OK : Z_STREAM_END; } /* ========================================================================= */ int deflateEnd(z_streamp strm) { int status; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; status = strm->state->status; if (status != INIT_STATE && status != EXTRA_STATE && status != NAME_STATE && status != COMMENT_STATE && status != HCRC_STATE && status != BUSY_STATE && status != FINISH_STATE) { return Z_STREAM_ERROR; } /* Deallocate in reverse order of allocations: */ TRY_FREE(strm, strm->state->pending_buf); TRY_FREE(strm, strm->state->head); TRY_FREE(strm, strm->state->prev); TRY_FREE(strm, strm->state->window); ZFREE(strm, strm->state); strm->state = Z_NULL; return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; } /* ========================================================================= * Copy the source state to the destination state. * To simplify the source, this is not supported for 16-bit MSDOS (which * doesn't have enough memory anyway to duplicate compression states). */ int deflateCopy(z_streamp dest, z_streamp source) { #if 0 /* by mao; #ifdef MAXSEG_64K */ return Z_STREAM_ERROR; #else deflate_state *ds; deflate_state *ss; ushf *overlay; if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { return Z_STREAM_ERROR; } ss = source->state; zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); if (ds == Z_NULL) return Z_MEM_ERROR; dest->state = (struct internal_state *) ds; zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); ds->strm = dest; ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); ds->pending_buf = (uchf *) overlay; if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || ds->pending_buf == Z_NULL) { deflateEnd (dest); return Z_MEM_ERROR; } /* following zmemcpy do not work for 16-bit MSDOS */ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; ds->l_desc.dyn_tree = ds->dyn_ltree; ds->d_desc.dyn_tree = ds->dyn_dtree; ds->bl_desc.dyn_tree = ds->bl_tree; return Z_OK; #endif /* MAXSEG_64K */ } /* =========================================================================== * Read a new buffer from the current input stream, update the adler32 * and total number of bytes read. All deflate() input goes through * this function so some applications may wish to modify it to avoid * allocating a large strm->next_in buffer and copying from it. * (See also flush_pending()). */ static int read_buf(z_streamp strm, Bytef *buf, unsigned size) { unsigned len = strm->avail_in; if (len > size) len = size; if (len == 0) return 0; strm->avail_in -= len; zmemcpy(buf, strm->next_in, len); if (strm->state->wrap == 1) { strm->adler = adler32(strm->adler, buf, len); } #ifdef GZIP else if (strm->state->wrap == 2) { strm->adler = crc32(strm->adler, buf, len); } #endif strm->next_in += len; strm->total_in += len; return (int)len; } /* =========================================================================== * Initialize the "longest match" routines for a new zlib stream */ static void lm_init(deflate_state *s) { s->window_size = (ulg)2L*s->w_size; CLEAR_HASH(s); /* Set the default configuration parameters: */ s->max_lazy_match = configuration_table[s->level].max_lazy; s->good_match = configuration_table[s->level].good_length; s->nice_match = configuration_table[s->level].nice_length; s->max_chain_length = configuration_table[s->level].max_chain; s->strstart = 0; s->block_start = 0L; s->lookahead = 0; s->insert = 0; s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; s->ins_h = 0; #ifndef FASTEST #if 0 /* by mao; #ifdef ASMV */ match_init(); /* initialize the asm code */ #endif #endif } #ifndef FASTEST /* =========================================================================== * Set match_start to the longest match starting at the given string and * return its length. Matches shorter or equal to prev_length are discarded, * in which case the result is equal to prev_length and match_start is * garbage. * IN assertions: cur_match is the head of the hash chain for the current * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 * OUT assertion: the match length is not greater than s->lookahead. */ #if 1 /* by mao; #ifndef ASMV */ /* For 80x86 and 680x0, an optimized version will be provided in match.asm or * match.S. The code will be functionally equivalent. */ static uInt longest_match(deflate_state *s, IPos cur_match) { unsigned chain_length = s->max_chain_length;/* max hash chain length */ register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ int best_len = s->prev_length; /* best match length so far */ int nice_match = s->nice_match; /* stop if match long enough */ IPos limit = s->strstart > (IPos)MAX_DIST(s) ? s->strstart - (IPos)MAX_DIST(s) : NIL; /* Stop when cur_match becomes <= limit. To simplify the code, * we prevent matches with the string of window index 0. */ Posf *prev = s->prev; uInt wmask = s->w_mask; #ifdef UNALIGNED_OK /* Compare two bytes at a time. Note: this is not always beneficial. * Try with and without -DUNALIGNED_OK to check. */ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; register ush scan_start = *(ushf*)scan; register ush scan_end = *(ushf*)(scan+best_len-1); #else register Bytef *strend = s->window + s->strstart + MAX_MATCH; register Byte scan_end1 = scan[best_len-1]; register Byte scan_end = scan[best_len]; #endif /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); /* Do not waste too much time if we already have a good match: */ if (s->prev_length >= s->good_match) { chain_length >>= 2; } /* Do not look for matches beyond the end of the input. This is necessary * to make deflate deterministic. */ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); do { Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Skip to next match if the match length cannot increase * or if the match length is less than 2. Note that the checks below * for insufficient lookahead only occur occasionally for performance * reasons. Therefore uninitialized memory will be accessed, and * conditional jumps will be made that depend on those values. * However the length of the match is limited to the lookahead, so * the output of deflate is not affected by the uninitialized values. */ #if (defined(UNALIGNED_OK) && MAX_MATCH == 258) /* This code assumes sizeof(unsigned short) == 2. Do not use * UNALIGNED_OK if your compiler uses a different size. */ if (*(ushf*)(match+best_len-1) != scan_end || *(ushf*)match != scan_start) continue; /* It is not necessary to compare scan[2] and match[2] since they are * always equal when the other bytes match, given that the hash keys * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at * strstart+3, +5, ... up to strstart+257. We check for insufficient * lookahead only every 4th comparison; the 128th check will be made * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is * necessary to put more guard bytes at the end of the window, or * to check more often for insufficient lookahead. */ Assert(scan[2] == match[2], "scan[2]?"); scan++, match++; do { } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && scan < strend); /* The funny "do {}" generates better code on most compilers */ /* Here, scan <= window+strstart+257 */ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); if (*scan == *match) scan++; len = (MAX_MATCH - 1) - (int)(strend-scan); scan = strend - (MAX_MATCH-1); #else /* UNALIGNED_OK */ if (match[best_len] != scan_end || match[best_len-1] != scan_end1 || *match != *scan || *++match != scan[1]) continue; /* The check at best_len-1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match++; Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart+258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); scan = strend - MAX_MATCH; #endif /* UNALIGNED_OK */ if (len > best_len) { s->match_start = cur_match; best_len = len; if (len >= nice_match) break; #ifdef UNALIGNED_OK scan_end = *(ushf*)(scan+best_len-1); #else scan_end1 = scan[best_len-1]; scan_end = scan[best_len]; #endif } } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length != 0); if ((uInt)best_len <= s->lookahead) return (uInt)best_len; return s->lookahead; } #endif /* ASMV */ #else /* FASTEST */ /* --------------------------------------------------------------------------- * Optimized version for FASTEST only */ static uInt longest_match(deflate_state *s, IPos cur_match) { register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ register Bytef *strend = s->window + s->strstart + MAX_MATCH; /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Return failure if the match length is less than 2: */ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; /* The check at best_len-1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match += 2; Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart+258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); if (len < MIN_MATCH) return MIN_MATCH - 1; s->match_start = cur_match; return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; } #endif /* FASTEST */ #ifdef DEBUG /* =========================================================================== * Check that the match at match_start is indeed a match. */ static void check_match(deflate_state *s, IPos start, IPos match, int length) { /* check that the match is indeed a match */ if (zmemcmp(s->window + match, s->window + start, length) != EQUAL) { fprintf(stderr, " start %u, match %u, length %d\n", start, match, length); do { fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); } while (--length != 0); z_error("invalid match"); } if (z_verbose > 1) { fprintf(stderr,"\\[%d,%d]", start-match, length); do { putc(s->window[start++], stderr); } while (--length != 0); } } #else # define check_match(s, start, match, length) #endif /* DEBUG */ /* =========================================================================== * Fill the window when the lookahead becomes insufficient. * Updates strstart and lookahead. * * IN assertion: lookahead < MIN_LOOKAHEAD * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD * At least one byte has been read, or avail_in == 0; reads are * performed for at least two bytes (required for the zip translate_eol * option -- not supported here). */ static void fill_window(deflate_state *s) { register unsigned n, m; register Posf *p; unsigned more; /* Amount of free space at the end of the window. */ uInt wsize = s->w_size; Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); do { more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); /* Deal with !@#$% 64K limit: */ if (sizeof(int) <= 2) { if (more == 0 && s->strstart == 0 && s->lookahead == 0) { more = wsize; } else if (more == (unsigned)(-1)) { /* Very unlikely, but possible on 16 bit machine if * strstart == 0 && lookahead == 1 (input done a byte at time) */ more--; } } /* If the window is almost full and there is insufficient lookahead, * move the upper half to the lower one to make room in the upper half. */ if (s->strstart >= wsize+MAX_DIST(s)) { zmemcpy(s->window, s->window+wsize, (unsigned)wsize); s->match_start -= wsize; s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ s->block_start -= (long) wsize; /* Slide the hash table (could be avoided with 32 bit values at the expense of memory usage). We slide even when level == 0 to keep the hash table consistent if we switch back to level > 0 later. (Using level 0 permanently is not an optimal usage of zlib, so we don't care about this pathological case.) */ n = s->hash_size; p = &s->head[n]; do { m = *--p; *p = (Pos)(m >= wsize ? m-wsize : NIL); } while (--n); n = wsize; #ifndef FASTEST p = &s->prev[n]; do { m = *--p; *p = (Pos)(m >= wsize ? m-wsize : NIL); /* If n is not on any hash chain, prev[n] is garbage but * its value will never be used. */ } while (--n); #endif more += wsize; } if (s->strm->avail_in == 0) break; /* If there was no sliding: * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && * more == window_size - lookahead - strstart * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) * => more >= window_size - 2*WSIZE + 2 * In the BIG_MEM or MMAP case (not yet supported), * window_size == input_size + MIN_LOOKAHEAD && * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. * Otherwise, window_size == 2*WSIZE so more >= 2. * If there was sliding, more >= WSIZE. So in all cases, more >= 2. */ Assert(more >= 2, "more < 2"); n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); s->lookahead += n; /* Initialize the hash value now that we have some input: */ if (s->lookahead + s->insert >= MIN_MATCH) { uInt str = s->strstart - s->insert; s->ins_h = s->window[str]; UPDATE_HASH(s, s->ins_h, s->window[str + 1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif while (s->insert) { UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); #ifndef FASTEST s->prev[str & s->w_mask] = s->head[s->ins_h]; #endif s->head[s->ins_h] = (Pos)str; str++; s->insert--; if (s->lookahead + s->insert < MIN_MATCH) break; } } /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, * but this is not important since only literal bytes will be emitted. */ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); /* If the WIN_INIT bytes after the end of the current data have never been * written, then zero those bytes in order to avoid memory check reports of * the use of uninitialized (or uninitialised as Julian writes) bytes by * the longest match routines. Update the high water mark for the next * time through here. WIN_INIT is set to MAX_MATCH since the longest match * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. */ if (s->high_water < s->window_size) { ulg curr = s->strstart + (ulg)(s->lookahead); ulg init; if (s->high_water < curr) { /* Previous high water mark below current data -- zero WIN_INIT * bytes or up to end of window, whichever is less. */ init = s->window_size - curr; if (init > WIN_INIT) init = WIN_INIT; zmemzero(s->window + curr, (unsigned)init); s->high_water = curr + init; } else if (s->high_water < (ulg)curr + WIN_INIT) { /* High water mark at or above current data, but below current data * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up * to end of window, whichever is less. */ init = (ulg)curr + WIN_INIT - s->high_water; if (init > s->window_size - s->high_water) init = s->window_size - s->high_water; zmemzero(s->window + s->high_water, (unsigned)init); s->high_water += init; } } Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, "not enough room for search"); } /* =========================================================================== * Flush the current block, with given end-of-file flag. * IN assertion: strstart is set to the end of the current match. */ #define FLUSH_BLOCK_ONLY(s, last) { \ _tr_flush_block(s, (s->block_start >= 0L ? \ (charf *)&s->window[(unsigned)s->block_start] : \ (charf *)Z_NULL), \ (ulg)((long)s->strstart - s->block_start), \ (last)); \ s->block_start = s->strstart; \ flush_pending(s->strm); \ Tracev((stderr,"[FLUSH]")); \ } /* Same but force premature exit if necessary. */ #define FLUSH_BLOCK(s, last) { \ FLUSH_BLOCK_ONLY(s, last); \ if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ } /* =========================================================================== * Copy without compression as much as possible from the input stream, return * the current block state. * This function does not insert new strings in the dictionary since * uncompressible data is probably not useful. This function is used * only for the level=0 compression option. * NOTE: this function should be optimized to avoid extra copying from * window to pending_buf. */ static block_state deflate_stored(deflate_state *s, int flush) { /* Stored blocks are limited to 0xffff bytes, pending_buf is limited * to pending_buf_size, and each stored block has a 5 byte header: */ ulg max_block_size = 0xffff; ulg max_start; if (max_block_size > s->pending_buf_size - 5) { max_block_size = s->pending_buf_size - 5; } /* Copy as much as possible from input to output: */ for (;;) { /* Fill the window as much as possible: */ if (s->lookahead <= 1) { Assert(s->strstart < s->w_size+MAX_DIST(s) || s->block_start >= (long)s->w_size, "slide too late"); fill_window(s); if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; if (s->lookahead == 0) break; /* flush the current block */ } Assert(s->block_start >= 0L, "block gone"); s->strstart += s->lookahead; s->lookahead = 0; /* Emit a stored block if pending_buf will be full: */ max_start = s->block_start + max_block_size; if (s->strstart == 0 || (ulg)s->strstart >= max_start) { /* strstart == 0 is possible when wraparound on 16-bit machine */ s->lookahead = (uInt)(s->strstart - max_start); s->strstart = (uInt)max_start; FLUSH_BLOCK(s, 0); } /* Flush if we may have to slide, otherwise block_start may become * negative and the data will be gone: */ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { FLUSH_BLOCK(s, 0); } } s->insert = 0; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if ((long)s->strstart > s->block_start) FLUSH_BLOCK(s, 0); return block_done; } /* =========================================================================== * Compress as much as possible from the input stream, return the current * block state. * This function does not perform lazy evaluation of matches and inserts * new strings in the dictionary only for unmatched strings or for short * matches. It is used only for the fast compression options. */ static block_state deflate_fast(deflate_state *s, int flush) { IPos hash_head; /* head of the hash chain */ int bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } /* Find the longest match, discarding those <= prev_length. * At this point we have always match_length < MIN_MATCH */ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */ } if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->match_start, s->match_length); _tr_tally_dist(s, s->strstart - s->match_start, s->match_length - MIN_MATCH, bflush); s->lookahead -= s->match_length; /* Insert new strings in the hash table only if the match length * is not too large. This saves time but degrades compression. */ #ifndef FASTEST if (s->match_length <= s->max_insert_length && s->lookahead >= MIN_MATCH) { s->match_length--; /* string at strstart already in table */ do { s->strstart++; INSERT_STRING(s, s->strstart, hash_head); /* strstart never exceeds WSIZE-MAX_MATCH, so there are * always MIN_MATCH bytes ahead. */ } while (--s->match_length != 0); s->strstart++; } else #endif { s->strstart += s->match_length; s->match_length = 0; s->ins_h = s->window[s->strstart]; UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not * matter since it will be recomputed at next deflate call. */ } } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } #ifndef FASTEST /* =========================================================================== * Same as above, but achieves better compression. We use a lazy * evaluation for matches: a match is finally adopted only if there is * no better match at the next window position. */ static block_state deflate_slow(deflate_state *s, int flush) { IPos hash_head; /* head of hash chain */ int bflush; /* set if current block must be flushed */ /* Process the input block. */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } /* Find the longest match, discarding those <= prev_length. */ s->prev_length = s->match_length, s->prev_match = s->match_start; s->match_length = MIN_MATCH-1; if (hash_head != NIL && s->prev_length < s->max_lazy_match && s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */ if (s->match_length <= 5 && (s->strategy == Z_FILTERED #if TOO_FAR <= 32767 || (s->match_length == MIN_MATCH && s->strstart - s->match_start > TOO_FAR) #endif )) { /* If prev_match is also MIN_MATCH, match_start is garbage * but we will ignore the current match anyway. */ s->match_length = MIN_MATCH-1; } } /* If there was a match at the previous step and the current * match is not better, output the previous match: */ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; /* Do not insert strings in hash table beyond this. */ check_match(s, s->strstart-1, s->prev_match, s->prev_length); _tr_tally_dist(s, s->strstart -1 - s->prev_match, s->prev_length - MIN_MATCH, bflush); /* Insert in hash table all strings up to the end of the match. * strstart-1 and strstart are already inserted. If there is not * enough lookahead, the last two strings are not inserted in * the hash table. */ s->lookahead -= s->prev_length-1; s->prev_length -= 2; do { if (++s->strstart <= max_insert) { INSERT_STRING(s, s->strstart, hash_head); } } while (--s->prev_length != 0); s->match_available = 0; s->match_length = MIN_MATCH-1; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } else if (s->match_available) { /* If there was no match at the previous position, output a * single literal. If there was a match but the current match * is longer, truncate the previous match to a single literal. */ Tracevv((stderr,"%c", s->window[s->strstart-1])); _tr_tally_lit(s, s->window[s->strstart-1], bflush); if (bflush) { FLUSH_BLOCK_ONLY(s, 0); } s->strstart++; s->lookahead--; if (s->strm->avail_out == 0) return need_more; } else { /* There is no previous match to compare with, wait for * the next step to decide. */ s->match_available = 1; s->strstart++; s->lookahead--; } } Assert (flush != Z_NO_FLUSH, "no flush?"); if (s->match_available) { Tracevv((stderr,"%c", s->window[s->strstart-1])); _tr_tally_lit(s, s->window[s->strstart-1], bflush); s->match_available = 0; } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } #endif /* FASTEST */ /* =========================================================================== * For Z_RLE, simply look for runs of bytes, generate matches only of distance * one. Do not maintain a hash table. (It will be regenerated if this run of * deflate switches away from Z_RLE.) */ static block_state deflate_rle(deflate_state *s, int flush) { int bflush; /* set if current block must be flushed */ uInt prev; /* byte at distance one to match */ Bytef *scan, *strend; /* scan goes up to strend for length of run */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the longest run, plus one for the unrolled loop. */ if (s->lookahead <= MAX_MATCH) { fill_window(s); if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* See how many times the previous byte repeats */ s->match_length = 0; if (s->lookahead >= MIN_MATCH && s->strstart > 0) { scan = s->window + s->strstart - 1; prev = *scan; if (prev == *++scan && prev == *++scan && prev == *++scan) { strend = s->window + s->strstart + MAX_MATCH; do { } while (prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && scan < strend); s->match_length = MAX_MATCH - (int)(strend - scan); if (s->match_length > s->lookahead) s->match_length = s->lookahead; } Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); } /* Emit match if have run of MIN_MATCH or longer, else emit literal */ if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->strstart - 1, s->match_length); _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); s->lookahead -= s->match_length; s->strstart += s->match_length; s->match_length = 0; } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } s->insert = 0; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } /* =========================================================================== * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. * (It will be regenerated if this run of deflate switches away from Huffman.) */ static block_state deflate_huff(deflate_state *s, int flush) { int bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we have a literal to write. */ if (s->lookahead == 0) { fill_window(s); if (s->lookahead == 0) { if (flush == Z_NO_FLUSH) return need_more; break; /* flush the current block */ } } /* Output a literal byte */ s->match_length = 0; Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } s->insert = 0; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } /* eof */ Rglpk/src/GLPK/zlib/inffast.h0000644000176000001440000000104512245352174015455 0ustar ripleyusers/* inffast.h */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* inffast.h -- header to use inffast.c * Copyright (C) 1995-2003, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ void inflate_fast(z_streamp strm, unsigned start); /* eof */ Rglpk/src/GLPK/zlib/crc32.c0000644000176000001440000003132512245352174014736 0ustar ripleyusers/* crc32.c */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* crc32.c -- compute the CRC-32 of a data stream * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * Thanks to Rodney Brown for his contribution of faster * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing * tables for updating the shift register in one step with three exclusive-ors * instead of four steps with four exclusive-ors. This results in about a * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. */ /* Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore protection on the static variables used to control the first-use generation of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should first call get_crc_table() to initialize the tables before allowing more than one thread to use crc32(). DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h. */ #ifdef MAKECRCH # include # ifndef DYNAMIC_CRC_TABLE # define DYNAMIC_CRC_TABLE # endif /* !DYNAMIC_CRC_TABLE */ #endif /* MAKECRCH */ #include "zutil.h" /* for STDC definitions */ /* Definitions for doing the crc four data bytes at a time. */ #if !defined(NOBYFOUR) # define BYFOUR #endif #ifdef BYFOUR static unsigned long crc32_little(unsigned long, const unsigned char *, unsigned); static unsigned long crc32_big(unsigned long, const unsigned char *, unsigned); # define TBLS 8 #else # define TBLS 1 #endif /* BYFOUR */ /* Local functions for crc concatenation */ static unsigned long gf2_matrix_times(unsigned long *mat, unsigned long vec); static void gf2_matrix_square(unsigned long *square, unsigned long *mat); static uLong crc32_combine_(uLong crc1, uLong crc2, z_off64_t len2); #ifdef DYNAMIC_CRC_TABLE static volatile int crc_table_empty = 1; static z_crc_t crc_table[TBLS][256]; static void make_crc_table(void); #ifdef MAKECRCH static void write_table(FILE *, const z_crc_t *); #endif /* MAKECRCH */ /* Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. Polynomials over GF(2) are represented in binary, one bit per coefficient, with the lowest powers in the most significant bit. Then adding polynomials is just exclusive-or, and multiplying a polynomial by x is a right shift by one. If we call the above polynomial p, and represent a byte as the polynomial q, also with the lowest power in the most significant bit (so the byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, where a mod b means the remainder after dividing a by b. This calculation is done using the shift-register method of multiplying and taking the remainder. The register is initialized to zero, and for each incoming bit, x^32 is added mod p to the register if the bit is a one (where x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by x (which is shifting right by one and adding x^32 mod p if the bit shifted out is a one). We start with the highest power (least significant bit) of q and repeat for all eight bits of q. The first table is simply the CRC of all possible eight bit values. This is all the information needed to generate CRCs on data a byte at a time for all combinations of CRC register values and incoming bytes. The remaining tables allow for word-at-a-time CRC calculation for both big-endian and little- endian machines, where a word is four bytes. */ static void make_crc_table(void) { z_crc_t c; int n, k; z_crc_t poly; /* polynomial exclusive-or pattern */ /* terms of polynomial defining this crc (except x^32): */ static volatile int first = 1; /* flag to limit concurrent making */ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; /* See if another task is already doing this (not thread-safe, but better than nothing -- significantly reduces duration of vulnerability in case the advice about DYNAMIC_CRC_TABLE is ignored) */ if (first) { first = 0; /* make exclusive-or pattern from polynomial (0xedb88320UL) */ poly = 0; for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++) poly |= (z_crc_t)1 << (31 - p[n]); /* generate a crc for every 8-bit value */ for (n = 0; n < 256; n++) { c = (z_crc_t)n; for (k = 0; k < 8; k++) c = c & 1 ? poly ^ (c >> 1) : c >> 1; crc_table[0][n] = c; } #ifdef BYFOUR /* generate crc for each value followed by one, two, and three zeros, and then the byte reversal of those as well as the first table */ for (n = 0; n < 256; n++) { c = crc_table[0][n]; crc_table[4][n] = ZSWAP32(c); for (k = 1; k < 4; k++) { c = crc_table[0][c & 0xff] ^ (c >> 8); crc_table[k][n] = c; crc_table[k + 4][n] = ZSWAP32(c); } } #endif /* BYFOUR */ crc_table_empty = 0; } else { /* not first */ /* wait for the other guy to finish (not efficient, but rare) */ while (crc_table_empty) ; } #ifdef MAKECRCH /* write out CRC tables to crc32.h */ { FILE *out; out = fopen("crc32.h", "w"); if (out == NULL) return; fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); fprintf(out, "static const z_crc_t "); fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); write_table(out, crc_table[0]); # ifdef BYFOUR fprintf(out, "#ifdef BYFOUR\n"); for (k = 1; k < 8; k++) { fprintf(out, " },\n {\n"); write_table(out, crc_table[k]); } fprintf(out, "#endif\n"); # endif /* BYFOUR */ fprintf(out, " }\n};\n"); fclose(out); } #endif /* MAKECRCH */ } #ifdef MAKECRCH static void write_table(FILE *out, const z_crc_t *table) { int n; for (n = 0; n < 256; n++) fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", (unsigned long)(table[n]), n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); } #endif /* MAKECRCH */ #else /* !DYNAMIC_CRC_TABLE */ /* ======================================================================== * Tables of CRC-32s of all single-byte values, made by make_crc_table(). */ #include "crc32.h" #endif /* DYNAMIC_CRC_TABLE */ /* ========================================================================= * This function can be used by asm versions of crc32() */ const z_crc_t *get_crc_table(void) { #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */ return (const z_crc_t *)crc_table; } /* ========================================================================= */ #define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) #define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 /* ========================================================================= */ unsigned long crc32(unsigned long crc, const unsigned char *buf, uInt len) { if (buf == Z_NULL) return 0UL; #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */ #ifdef BYFOUR if (sizeof(void *) == sizeof(ptrdiff_t)) { z_crc_t endian; endian = 1; if (*((unsigned char *)(&endian))) return crc32_little(crc, buf, len); else return crc32_big(crc, buf, len); } #endif /* BYFOUR */ crc = crc ^ 0xffffffffUL; while (len >= 8) { DO8; len -= 8; } if (len) do { DO1; } while (--len); return crc ^ 0xffffffffUL; } #ifdef BYFOUR /* ========================================================================= */ #define DOLIT4 c ^= *buf4++; \ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] #define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 /* ========================================================================= */ static unsigned long crc32_little(unsigned long crc, const unsigned char *buf, unsigned len) { register z_crc_t c; register const z_crc_t *buf4; c = (z_crc_t)crc; c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); len--; } buf4 = (const z_crc_t *)(const void *)buf; while (len >= 32) { DOLIT32; len -= 32; } while (len >= 4) { DOLIT4; len -= 4; } buf = (const unsigned char *)buf4; if (len) do { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); } while (--len); c = ~c; return (unsigned long)c; } /* ========================================================================= */ #define DOBIG4 c ^= *++buf4; \ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] #define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 /* ========================================================================= */ static unsigned long crc32_big(unsigned long crc, const unsigned char *buf, unsigned len) { register z_crc_t c; register const z_crc_t *buf4; c = ZSWAP32((z_crc_t)crc); c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); len--; } buf4 = (const z_crc_t *)(const void *)buf; buf4--; while (len >= 32) { DOBIG32; len -= 32; } while (len >= 4) { DOBIG4; len -= 4; } buf4++; buf = (const unsigned char *)buf4; if (len) do { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); } while (--len); c = ~c; return (unsigned long)(ZSWAP32(c)); } #endif /* BYFOUR */ #define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ /* ========================================================================= */ static unsigned long gf2_matrix_times(unsigned long *mat, unsigned long vec) { unsigned long sum; sum = 0; while (vec) { if (vec & 1) sum ^= *mat; vec >>= 1; mat++; } return sum; } /* ========================================================================= */ static void gf2_matrix_square(unsigned long *square, unsigned long *mat) { int n; for (n = 0; n < GF2_DIM; n++) square[n] = gf2_matrix_times(mat, mat[n]); } /* ========================================================================= */ static uLong crc32_combine_(uLong crc1, uLong crc2, z_off64_t len2) { int n; unsigned long row; unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ /* degenerate case (also disallow negative lengths) */ if (len2 <= 0) return crc1; /* put operator for one zero bit in odd */ odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ row = 1; for (n = 1; n < GF2_DIM; n++) { odd[n] = row; row <<= 1; } /* put operator for two zero bits in even */ gf2_matrix_square(even, odd); /* put operator for four zero bits in odd */ gf2_matrix_square(odd, even); /* apply len2 zeros to crc1 (first square will put the operator for one zero byte, eight zero bits, in even) */ do { /* apply zeros operator for this bit of len2 */ gf2_matrix_square(even, odd); if (len2 & 1) crc1 = gf2_matrix_times(even, crc1); len2 >>= 1; /* if no more bits set, then done */ if (len2 == 0) break; /* another iteration of the loop with odd and even swapped */ gf2_matrix_square(odd, even); if (len2 & 1) crc1 = gf2_matrix_times(odd, crc1); len2 >>= 1; /* if no more bits set, then done */ } while (len2 != 0); /* return combined crc */ crc1 ^= crc2; return crc1; } /* ========================================================================= */ uLong crc32_combine(uLong crc1, uLong crc2, z_off_t len2) { return crc32_combine_(crc1, crc2, len2); } uLong crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2) { return crc32_combine_(crc1, crc2, len2); } /* eof */ Rglpk/src/GLPK/zlib/trees.h0000644000176000001440000002040012245352174015141 0ustar ripleyusers/* header created automatically with -DGEN_TREES_H */ static const ct_data static_ltree[L_CODES+2] = { {{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, {{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, {{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, {{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, {{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, {{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, {{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, {{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, {{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, {{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, {{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, {{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, {{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, {{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, {{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, {{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, {{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, {{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, {{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, {{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, {{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, {{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, {{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, {{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, {{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, {{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, {{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, {{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, {{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, {{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, {{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, {{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, {{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, {{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, {{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, {{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, {{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, {{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, {{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, {{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, {{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, {{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, {{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, {{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, {{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, {{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, {{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, {{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, {{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, {{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, {{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, {{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, {{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, {{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, {{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, {{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, {{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, {{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} }; static const ct_data static_dtree[D_CODES] = { {{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, {{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, {{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, {{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, {{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, {{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} }; const uch _dist_code[DIST_CODE_LEN] = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 }; const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 }; static const int base_length[LENGTH_CODES] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0 }; static const int base_dist[D_CODES] = { 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 }; Rglpk/src/GLPK/zlib/trees.c0000644000176000001440000012554612245352174015155 0ustar ripleyusers/* trees.c */ /* Modified by Andrew Makhorin , June 2013. */ /* For original code see . */ /* trees.c -- output deflated data using Huffman coding * Copyright (C) 1995-2012 Jean-loup Gailly * detect_data_type() function provided freely by Cosmin Truta, 2006 * For conditions of distribution and use, see copyright notice in zlib.h */ /* * ALGORITHM * * The "deflation" process uses several Huffman trees. The more * common source values are represented by shorter bit sequences. * * Each code tree is stored in a compressed form which is itself * a Huffman encoding of the lengths of all the code strings (in * ascending order by source values). The actual code strings are * reconstructed from the lengths in the inflate process, as described * in the deflate specification. * * REFERENCES * * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc * * Storer, James A. * Data Compression: Methods and Theory, pp. 49-50. * Computer Science Press, 1988. ISBN 0-7167-8156-5. * * Sedgewick, R. * Algorithms, p290. * Addison-Wesley, 1983. ISBN 0-201-06672-6. */ #include "deflate.h" #ifdef DEBUG # include #endif /* =========================================================================== * Constants */ #define MAX_BL_BITS 7 /* Bit length codes must not exceed MAX_BL_BITS bits */ #define END_BLOCK 256 /* end of block literal code */ #define REP_3_6 16 /* repeat previous bit length 3-6 times (2 bits of repeat count) */ #define REPZ_3_10 17 /* repeat a zero length 3-10 times (3 bits of repeat count) */ #define REPZ_11_138 18 /* repeat a zero length 11-138 times (7 bits of repeat count) */ static const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; static const int extra_dbits[D_CODES] /* extra bits for each distance code */ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; static const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; static const uch bl_order[BL_CODES] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; /* The lengths of the bit length codes are sent in order of decreasing * probability, to avoid transmitting the lengths for unused bit length codes. */ /* =========================================================================== * Local data. These are initialized only once. */ #define DIST_CODE_LEN 512 /* see definition of array dist_code below */ #if defined(GEN_TREES_H) static ct_data static_ltree[L_CODES+2]; /* The static literal tree. Since the bit lengths are imposed, there is no * need for the L_CODES extra codes used during heap construction. However * The codes 286 and 287 are needed to build a canonical tree (see _tr_init * below). */ static ct_data static_dtree[D_CODES]; /* The static distance tree. (Actually a trivial tree since all codes use * 5 bits.) */ uch _dist_code[DIST_CODE_LEN]; /* Distance codes. The first 256 values correspond to the distances * 3 .. 258, the last 256 values correspond to the top 8 bits of * the 15 bit distances. */ uch _length_code[MAX_MATCH-MIN_MATCH+1]; /* length code for each normalized match length (0 == MIN_MATCH) */ static int base_length[LENGTH_CODES]; /* First normalized length for each code (0 = MIN_MATCH) */ static int base_dist[D_CODES]; /* First normalized distance for each code (0 = distance of 1) */ #else # include "trees.h" #endif /* GEN_TREES_H */ struct static_tree_desc_s { const ct_data *static_tree; /* static tree or NULL */ const intf *extra_bits; /* extra bits for each code or NULL */ int extra_base; /* base index for extra_bits */ int elems; /* max number of elements in the tree */ int max_length; /* max bit length for the codes */ }; static static_tree_desc static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; static static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; static static_tree_desc static_bl_desc = {(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; /* =========================================================================== * Local (static) routines in this file. */ static void tr_static_init (void); static void init_block (deflate_state *s); static void pqdownheap (deflate_state *s, ct_data *tree, int k); static void gen_bitlen (deflate_state *s, tree_desc *desc); static void gen_codes (ct_data *tree, int max_code, ushf *bl_count); static void build_tree (deflate_state *s, tree_desc *desc); static void scan_tree (deflate_state *s, ct_data *tree, int max_code); static void send_tree (deflate_state *s, ct_data *tree, int max_code); static int build_bl_tree (deflate_state *s); static void send_all_trees (deflate_state *s, int lcodes, int dcodes, int blcodes); static void compress_block (deflate_state *s, ct_data *ltree, ct_data *dtree); static int detect_data_type (deflate_state *s); static unsigned bi_reverse (unsigned value, int length); static void bi_windup (deflate_state *s); static void bi_flush (deflate_state *s); static void copy_block (deflate_state *s, charf *buf, unsigned len, int header); #ifdef GEN_TREES_H static void gen_trees_header (void); #endif #ifndef DEBUG # define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) /* Send a code of the given tree. c and tree must not have side effects */ #else /* DEBUG */ # define send_code(s, c, tree) \ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ send_bits(s, tree[c].Code, tree[c].Len); } #endif /* =========================================================================== * Output a short LSB first on the stream. * IN assertion: there is enough room in pendingBuf. */ #define put_short(s, w) { \ put_byte(s, (uch)((w) & 0xff)); \ put_byte(s, (uch)((ush)(w) >> 8)); \ } /* =========================================================================== * Send a value on a given number of bits. * IN assertion: length <= 16 and value fits in length bits. */ #ifdef DEBUG static void send_bits(deflate_state *s, int value, int length); static void send_bits(deflate_state *s, int value, int length) /* value = value to send */ /* length = number of bits */ { Tracevv((stderr," l %2d v %4x ", length, value)); Assert(length > 0 && length <= 15, "invalid length"); s->bits_sent += (ulg)length; /* If not enough room in bi_buf, use (valid) bits from bi_buf and * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) * unused bits in value. */ if (s->bi_valid > (int)Buf_size - length) { s->bi_buf |= (ush)value << s->bi_valid; put_short(s, s->bi_buf); s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); s->bi_valid += length - Buf_size; } else { s->bi_buf |= (ush)value << s->bi_valid; s->bi_valid += length; } } #else /* !DEBUG */ #define send_bits(s, value, length) \ { int len = length;\ if (s->bi_valid > (int)Buf_size - len) {\ int val = value;\ s->bi_buf |= (ush)val << s->bi_valid;\ put_short(s, s->bi_buf);\ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ s->bi_valid += len - Buf_size;\ } else {\ s->bi_buf |= (ush)(value) << s->bi_valid;\ s->bi_valid += len;\ }\ } #endif /* DEBUG */ /* the arguments must not have side effects */ /* =========================================================================== * Initialize the various 'constant' tables. */ static void tr_static_init(void) { #if defined(GEN_TREES_H) static int static_init_done = 0; int n; /* iterates over tree elements */ int bits; /* bit counter */ int length; /* length value */ int code; /* code value */ int dist; /* distance index */ ush bl_count[MAX_BITS+1]; /* number of codes at each bit length for an optimal tree */ if (static_init_done) return; /* For some embedded targets, global variables are not initialized: */ #ifdef NO_INIT_GLOBAL_POINTERS static_l_desc.static_tree = static_ltree; static_l_desc.extra_bits = extra_lbits; static_d_desc.static_tree = static_dtree; static_d_desc.extra_bits = extra_dbits; static_bl_desc.extra_bits = extra_blbits; #endif /* Initialize the mapping length (0..255) -> length code (0..28) */ length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { base_length[code] = length; for (n = 0; n < (1< dist code (0..29) */ dist = 0; for (code = 0 ; code < 16; code++) { base_dist[code] = dist; for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ for ( ; code < D_CODES; code++) { base_dist[code] = dist << 7; for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { _dist_code[256 + dist++] = (uch)code; } } Assert (dist == 256, "tr_static_init: 256+dist != 512"); /* Construct the codes of the static literal tree */ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; n = 0; while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; /* Codes 286 and 287 do not exist, but we must include them in the * tree construction to get a canonical Huffman tree (longest code * all ones) */ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); /* The static distance tree is trivial: */ for (n = 0; n < D_CODES; n++) { static_dtree[n].Len = 5; static_dtree[n].Code = bi_reverse((unsigned)n, 5); } static_init_done = 1; # ifdef GEN_TREES_H gen_trees_header(); # endif #endif /* defined(GEN_TREES_H) */ } #ifdef GEN_TREES_H /* by mao */ void maketrees(void) { tr_static_init(); return; } #endif /* =========================================================================== * Genererate the file trees.h describing the static trees. */ #ifdef GEN_TREES_H # ifndef DEBUG # include # endif # define SEPARATOR(i, last, width) \ ((i) == (last)? "\n};\n\n" : \ ((i) % (width) == (width)-1 ? ",\n" : ", ")) void gen_trees_header(void) { FILE *header = fopen("trees.h", "w"); int i; Assert (header != NULL, "Can't open trees.h"); fprintf(header, "/* header created automatically with -DGEN_TREES_H */\n\n"); fprintf(header, "static const ct_data static_ltree[L_CODES+2] = {\n"); for (i = 0; i < L_CODES+2; i++) { fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); } fprintf(header, "static const ct_data static_dtree[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); } fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); for (i = 0; i < DIST_CODE_LEN; i++) { fprintf(header, "%2u%s", _dist_code[i], SEPARATOR(i, DIST_CODE_LEN-1, 20)); } fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { fprintf(header, "%2u%s", _length_code[i], SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); } fprintf(header, "static const int base_length[LENGTH_CODES] = {\n"); for (i = 0; i < LENGTH_CODES; i++) { fprintf(header, "%1u%s", base_length[i], SEPARATOR(i, LENGTH_CODES-1, 20)); } fprintf(header, "static const int base_dist[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { fprintf(header, "%5u%s", base_dist[i], SEPARATOR(i, D_CODES-1, 10)); } fclose(header); } #endif /* GEN_TREES_H */ /* =========================================================================== * Initialize the tree data structures for a new zlib stream. */ void _tr_init(deflate_state *s) { tr_static_init(); s->l_desc.dyn_tree = s->dyn_ltree; s->l_desc.stat_desc = &static_l_desc; s->d_desc.dyn_tree = s->dyn_dtree; s->d_desc.stat_desc = &static_d_desc; s->bl_desc.dyn_tree = s->bl_tree; s->bl_desc.stat_desc = &static_bl_desc; s->bi_buf = 0; s->bi_valid = 0; #ifdef DEBUG s->compressed_len = 0L; s->bits_sent = 0L; #endif /* Initialize the first block of the first file: */ init_block(s); } /* =========================================================================== * Initialize a new block. */ static void init_block(deflate_state *s) { int n; /* iterates over tree elements */ /* Initialize the trees. */ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; s->dyn_ltree[END_BLOCK].Freq = 1; s->opt_len = s->static_len = 0L; s->last_lit = s->matches = 0; } #define SMALLEST 1 /* Index within the heap array of least frequent node in the Huffman tree */ /* =========================================================================== * Remove the smallest element from the heap and recreate the heap with * one less element. Updates heap and heap_len. */ #define pqremove(s, tree, top) \ {\ top = s->heap[SMALLEST]; \ s->heap[SMALLEST] = s->heap[s->heap_len--]; \ pqdownheap(s, tree, SMALLEST); \ } /* =========================================================================== * Compares to subtrees, using the tree depth as tie breaker when * the subtrees have equal frequency. This minimizes the worst case length. */ #define smaller(tree, n, m, depth) \ (tree[n].Freq < tree[m].Freq || \ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) /* =========================================================================== * Restore the heap property by moving down the tree starting at node k, * exchanging a node with the smallest of its two sons if necessary, stopping * when the heap property is re-established (each father smaller than its * two sons). */ static void pqdownheap(deflate_state *s, ct_data *tree, int k) /* tree = the tree to restore */ /* k = node to move down */ { int v = s->heap[k]; int j = k << 1; /* left son of k */ while (j <= s->heap_len) { /* Set j to the smallest of the two sons: */ if (j < s->heap_len && smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { j++; } /* Exit if v is smaller than both sons */ if (smaller(tree, v, s->heap[j], s->depth)) break; /* Exchange v with the smallest son */ s->heap[k] = s->heap[j]; k = j; /* And continue down the tree, setting j to the left son of k */ j <<= 1; } s->heap[k] = v; } /* =========================================================================== * Compute the optimal bit lengths for a tree and update the total bit length * for the current block. * IN assertion: the fields freq and dad are set, heap[heap_max] and * above are the tree nodes sorted by increasing frequency. * OUT assertions: the field len is set to the optimal bit length, the * array bl_count contains the frequencies for each bit length. * The length opt_len is updated; static_len is also updated if stree is * not null. */ static void gen_bitlen(deflate_state *s, tree_desc *desc) { ct_data *tree = desc->dyn_tree; int max_code = desc->max_code; const ct_data *stree = desc->stat_desc->static_tree; const intf *extra = desc->stat_desc->extra_bits; int base = desc->stat_desc->extra_base; int max_length = desc->stat_desc->max_length; int h; /* heap index */ int n, m; /* iterate over the tree elements */ int bits; /* bit length */ int xbits; /* extra bits */ ush f; /* frequency */ int overflow = 0; /* number of elements with bit length too large */ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; /* In a first pass, compute the optimal bit lengths (which may * overflow in the case of the bit length tree). */ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ for (h = s->heap_max+1; h < HEAP_SIZE; h++) { n = s->heap[h]; bits = tree[tree[n].Dad].Len + 1; if (bits > max_length) bits = max_length, overflow++; tree[n].Len = (ush)bits; /* We overwrite tree[n].Dad which is no longer needed */ if (n > max_code) continue; /* not a leaf node */ s->bl_count[bits]++; xbits = 0; if (n >= base) xbits = extra[n-base]; f = tree[n].Freq; s->opt_len += (ulg)f * (bits + xbits); if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); } if (overflow == 0) return; Trace((stderr,"\nbit length overflow\n")); /* This happens for example on obj2 and pic of the Calgary corpus */ /* Find the first bit length which could increase: */ do { bits = max_length-1; while (s->bl_count[bits] == 0) bits--; s->bl_count[bits]--; /* move one leaf down the tree */ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ s->bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] */ overflow -= 2; } while (overflow > 0); /* Now recompute all bit lengths, scanning in increasing frequency. * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all * lengths instead of fixing only the wrong ones. This idea is taken * from 'ar' written by Haruhiko Okumura.) */ for (bits = max_length; bits != 0; bits--) { n = s->bl_count[bits]; while (n != 0) { m = s->heap[--h]; if (m > max_code) continue; if ((unsigned) tree[m].Len != (unsigned) bits) { Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); s->opt_len += ((long)bits - (long)tree[m].Len) *(long)tree[m].Freq; tree[m].Len = (ush)bits; } n--; } } } /* =========================================================================== * Generate the codes for a given tree and bit counts (which need not be * optimal). * IN assertion: the array bl_count contains the bit length statistics for * the given tree and the field len is set for all tree elements. * OUT assertion: the field code is set for all tree elements of non * zero code length. */ static void gen_codes(ct_data *tree, int max_code, ushf *bl_count) /* tree = the tree to decorate */ /* max_code = largest code with non zero frequency */ /* bl_count = number of codes at each bit length */ { ush next_code[MAX_BITS+1]; /* next code value for each bit length */ ush code = 0; /* running code value */ int bits; /* bit index */ int n; /* code index */ /* The distribution counts are first used to generate the code values * without bit reversal. */ for (bits = 1; bits <= MAX_BITS; bits++) { next_code[bits] = code = (code + bl_count[bits-1]) << 1; } /* Check that the bit counts in bl_count are consistent. The last code * must be all ones. */ Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; const ct_data *stree = desc->stat_desc->static_tree; int elems = desc->stat_desc->elems; int n, m; /* iterate over heap elements */ int max_code = -1; /* largest code with non zero frequency */ int node; /* new node being created */ /* Construct the initial heap, with least frequent element in * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. * heap[0] is not used. */ s->heap_len = 0, s->heap_max = HEAP_SIZE; for (n = 0; n < elems; n++) { if (tree[n].Freq != 0) { s->heap[++(s->heap_len)] = max_code = n; s->depth[n] = 0; } else { tree[n].Len = 0; } } /* The pkzip format requires that at least one distance code exists, * and that at least one bit should be sent even if there is only one * possible code. So to avoid special checks later on we force at least * two codes of non zero frequency. */ while (s->heap_len < 2) { node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); tree[node].Freq = 1; s->depth[node] = 0; s->opt_len--; if (stree) s->static_len -= stree[node].Len; /* node is 0 or 1 so it does not have extra bits */ } desc->max_code = max_code; /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, * establish sub-heaps of increasing lengths: */ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); /* Construct the Huffman tree by repeatedly combining the least two * frequent nodes. */ node = elems; /* next internal node of the tree */ do { pqremove(s, tree, n); /* n = node of least frequency */ m = s->heap[SMALLEST]; /* m = node of next least frequency */ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ s->heap[--(s->heap_max)] = m; /* Create a new node father of n and m */ tree[node].Freq = tree[n].Freq + tree[m].Freq; s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? s->depth[n] : s->depth[m]) + 1); tree[n].Dad = tree[m].Dad = (ush)node; #ifdef DUMP_BL_TREE if (tree == s->bl_tree) { fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); } #endif /* and insert the new node in the heap */ s->heap[SMALLEST] = node++; pqdownheap(s, tree, SMALLEST); } while (s->heap_len >= 2); s->heap[--(s->heap_max)] = s->heap[SMALLEST]; /* At this point, the fields freq and dad are set. We can now * generate the bit lengths. */ gen_bitlen(s, (tree_desc *)desc); /* The field len is now set, we can generate the bit codes */ gen_codes ((ct_data *)tree, max_code, s->bl_count); } /* =========================================================================== * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ static void scan_tree(deflate_state *s, ct_data *tree, int max_code) /* tree = the tree to be scanned */ /* max_code = and its largest code of non zero frequency */ { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ if (nextlen == 0) max_count = 138, min_count = 3; tree[max_code+1].Len = (ush)0xffff; /* guard */ for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n+1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { s->bl_tree[curlen].Freq += count; } else if (curlen != 0) { if (curlen != prevlen) s->bl_tree[curlen].Freq++; s->bl_tree[REP_3_6].Freq++; } else if (count <= 10) { s->bl_tree[REPZ_3_10].Freq++; } else { s->bl_tree[REPZ_11_138].Freq++; } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } /* =========================================================================== * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ static void send_tree(deflate_state *s, ct_data *tree, int max_code) /* tree = the tree to be scanned */ /* max_code = and its largest code of non zero frequency */ { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ /* tree[max_code+1].Len = -1; */ /* guard already set */ if (nextlen == 0) max_count = 138, min_count = 3; for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n+1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { do { send_code(s, curlen, s->bl_tree); } while (--count != 0); } else if (curlen != 0) { if (curlen != prevlen) { send_code(s, curlen, s->bl_tree); count--; } Assert(count >= 3 && count <= 6, " 3_6?"); send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); } else if (count <= 10) { send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); } else { send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } /* =========================================================================== * Construct the Huffman tree for the bit lengths and return the index in * bl_order of the last bit length code to send. */ static int build_bl_tree(deflate_state *s) { int max_blindex; /* index of last bit length code of non zero freq */ /* Determine the bit length frequencies for literal and distance trees */ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); /* Build the bit length tree: */ build_tree(s, (tree_desc *)(&(s->bl_desc))); /* opt_len now includes the length of the tree representations, except * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. */ /* Determine the number of bit length codes to send. The pkzip format * requires that at least 4 bit length codes be sent. (appnote.txt says * 3 but the actual value used is 4.) */ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ s->opt_len += 3*(max_blindex+1) + 5+5+4; Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", s->opt_len, s->static_len)); return max_blindex; } /* =========================================================================== * Send the header for a block using dynamic Huffman trees: the counts, the * lengths of the bit length codes, the literal tree and the distance tree. * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. */ static void send_all_trees(deflate_state *s, int lcodes, int dcodes, int blcodes) /* lcodes, dcodes, blcodes = number of codes for each tree */ { int rank; /* index in bl_order */ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); Tracev((stderr, "\nbl counts: ")); send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ send_bits(s, dcodes-1, 5); send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { Tracev((stderr, "\nbl code %2d ", bl_order[rank])); send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); } Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); } /* =========================================================================== * Send a stored block */ void _tr_stored_block(deflate_state *s, charf *buf, ulg stored_len, int last) /* buf = input block */ /* stored_len = length of input block */ /* last = one if this is the last block for a file */ { send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ #ifdef DEBUG s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; #endif copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ } /* =========================================================================== * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) */ void _tr_flush_bits(deflate_state *s) { bi_flush(s); } /* =========================================================================== * Send one empty static block to give enough lookahead for inflate. * This takes 10 bits, of which 7 may remain in the bit buffer. */ void _tr_align(deflate_state *s) { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); #ifdef DEBUG s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ #endif bi_flush(s); } /* =========================================================================== * Determine the best encoding for the current block: dynamic trees, static * trees or store, and output the encoded block to the zip file. */ void _tr_flush_block(deflate_state *s, charf *buf, ulg stored_len, int last) /* buf = input block, or NULL if too old */ /* stored_len = length of input block */ /* last = one if this is the last block for a file */ { ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ int max_blindex = 0; /* index of last bit length code of non zero freq */ /* Build the Huffman trees unless a stored block is forced */ if (s->level > 0) { /* Check if the file is binary or text */ if (s->strm->data_type == Z_UNKNOWN) s->strm->data_type = detect_data_type(s); /* Construct the literal and distance trees */ build_tree(s, (tree_desc *)(&(s->l_desc))); Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, s->static_len)); build_tree(s, (tree_desc *)(&(s->d_desc))); Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, s->static_len)); /* At this point, opt_len and static_len are the total bit lengths of * the compressed block data, excluding the tree representations. */ /* Build the bit length tree for the above two trees, and get the index * in bl_order of the last bit length code to send. */ max_blindex = build_bl_tree(s); /* Determine the best encoding. Compute the block lengths in bytes. */ opt_lenb = (s->opt_len+3+7)>>3; static_lenb = (s->static_len+3+7)>>3; Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, s->last_lit)); if (static_lenb <= opt_lenb) opt_lenb = static_lenb; } else { Assert(buf != (char*)0, "lost buf"); opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ } #ifdef FORCE_STORED if (buf != (char*)0) { /* force stored block */ #else if (stored_len+4 <= opt_lenb && buf != (char*)0) { /* 4: two words for the lengths */ #endif /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. * Otherwise we can't have processed more than WSIZE input bytes since * the last block flush, because compression would have been * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to * transform a block into a stored block. */ _tr_stored_block(s, buf, stored_len, last); #ifdef FORCE_STATIC } else if (static_lenb >= 0) { /* force static trees */ #else } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { #endif send_bits(s, (STATIC_TREES<<1)+last, 3); compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); #ifdef DEBUG s->compressed_len += 3 + s->static_len; #endif } else { send_bits(s, (DYN_TREES<<1)+last, 3); send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, max_blindex+1); compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); #ifdef DEBUG s->compressed_len += 3 + s->opt_len; #endif } Assert (s->compressed_len == s->bits_sent, "bad compressed size"); /* The above check is made mod 2^32, for files larger than 512 MB * and uLong implemented on 32 bits. */ init_block(s); if (last) { bi_windup(s); #ifdef DEBUG s->compressed_len += 7; /* align on byte boundary */ #endif } Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, s->compressed_len-7*last)); } /* =========================================================================== * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ int _tr_tally(deflate_state *s, unsigned dist, unsigned lc) /* dist = distance of matched string */ /* lc = match length-MIN_MATCH or unmatched char (if dist==0) */ { s->d_buf[s->last_lit] = (ush)dist; s->l_buf[s->last_lit++] = (uch)lc; if (dist == 0) { /* lc is the unmatched char */ s->dyn_ltree[lc].Freq++; } else { s->matches++; /* Here, lc is the match length - MIN_MATCH */ dist--; /* dist = match distance - 1 */ Assert((ush)dist < (ush)MAX_DIST(s) && (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; s->dyn_dtree[d_code(dist)].Freq++; } #ifdef TRUNCATE_BLOCK /* Try to guess if it is profitable to stop the current block here */ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { /* Compute an upper bound for the compressed length */ ulg out_length = (ulg)s->last_lit*8L; ulg in_length = (ulg)((long)s->strstart - s->block_start); int dcode; for (dcode = 0; dcode < D_CODES; dcode++) { out_length += (ulg)s->dyn_dtree[dcode].Freq * (5L+extra_dbits[dcode]); } out_length >>= 3; Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", s->last_lit, in_length, out_length, 100L - out_length*100L/in_length)); if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; } #endif return (s->last_lit == s->lit_bufsize-1); /* We avoid equality with lit_bufsize because of wraparound at 64K * on 16 bit machines and because stored blocks are restricted to * 64K-1 bytes. */ } /* =========================================================================== * Send the block data compressed using the given Huffman trees */ static void compress_block(deflate_state *s, ct_data *ltree, ct_data *dtree) /* ltree = literal tree */ /* dtree = distance tree */ { unsigned dist; /* distance of matched string */ int lc; /* match length or unmatched char (if dist == 0) */ unsigned lx = 0; /* running index in l_buf */ unsigned code; /* the code to send */ int extra; /* number of extra bits to send */ if (s->last_lit != 0) do { dist = s->d_buf[lx]; lc = s->l_buf[lx++]; if (dist == 0) { send_code(s, lc, ltree); /* send a literal byte */ Tracecv(isgraph(lc), (stderr," '%c' ", lc)); } else { /* Here, lc is the match length - MIN_MATCH */ code = _length_code[lc]; send_code(s, code+LITERALS+1, ltree); /* send the length code */ extra = extra_lbits[code]; if (extra != 0) { lc -= base_length[code]; send_bits(s, lc, extra); /* send the extra length bits */ } dist--; /* dist is now the match distance - 1 */ code = d_code(dist); Assert (code < D_CODES, "bad d_code"); send_code(s, code, dtree); /* send the distance code */ extra = extra_dbits[code]; if (extra != 0) { dist -= base_dist[code]; send_bits(s, dist, extra); /* send the extra distance bits */ } } /* literal or match pair ? */ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, "pendingBuf overflow"); } while (lx < s->last_lit); send_code(s, END_BLOCK, ltree); } /* =========================================================================== * Check if the data type is TEXT or BINARY, using the following algorithm: * - TEXT if the two conditions below are satisfied: * a) There are no non-portable control characters belonging to the * "black list" (0..6, 14..25, 28..31). * b) There is at least one printable character belonging to the * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). * - BINARY otherwise. * - The following partially-portable control characters form a * "gray list" that is ignored in this detection algorithm: * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). * IN assertion: the fields Freq of dyn_ltree are set. */ static int detect_data_type(deflate_state *s) { /* black_mask is the bit mask of black-listed bytes * set bits 0..6, 14..25, and 28..31 * 0xf3ffc07f = binary 11110011111111111100000001111111 */ unsigned long black_mask = 0xf3ffc07fUL; int n; /* Check for non-textual ("black-listed") bytes. */ for (n = 0; n <= 31; n++, black_mask >>= 1) if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0)) return Z_BINARY; /* Check for textual ("white-listed") bytes. */ if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 || s->dyn_ltree[13].Freq != 0) return Z_TEXT; for (n = 32; n < LITERALS; n++) if (s->dyn_ltree[n].Freq != 0) return Z_TEXT; /* There are no "black-listed" or "white-listed" bytes: * this stream either is empty or has tolerated ("gray-listed") bytes only. */ return Z_BINARY; } /* =========================================================================== * Reverse the first len bits of a code, using straightforward code (a faster * method would use a table) * IN assertion: 1 <= len <= 15 */ static unsigned bi_reverse(unsigned code, int len) /* code = the value to invert */ /* len = its bit length */ { register unsigned res = 0; do { res |= code & 1; code >>= 1, res <<= 1; } while (--len > 0); return res >> 1; } /* =========================================================================== * Flush the bit buffer, keeping at most 7 bits in it. */ static void bi_flush(deflate_state *s) { if (s->bi_valid == 16) { put_short(s, s->bi_buf); s->bi_buf = 0; s->bi_valid = 0; } else if (s->bi_valid >= 8) { put_byte(s, (Byte)s->bi_buf); s->bi_buf >>= 8; s->bi_valid -= 8; } } /* =========================================================================== * Flush the bit buffer and align the output on a byte boundary */ static void bi_windup(deflate_state *s) { if (s->bi_valid > 8) { put_short(s, s->bi_buf); } else if (s->bi_valid > 0) { put_byte(s, (Byte)s->bi_buf); } s->bi_buf = 0; s->bi_valid = 0; #ifdef DEBUG s->bits_sent = (s->bits_sent+7) & ~7; #endif } /* =========================================================================== * Copy a stored block, storing first the length and its * one's complement if requested. */ static void copy_block(deflate_state *s, charf *buf, unsigned len, int header) /* buf = the input data */ /* len = its length */ /* header = true if block header must be written */ { bi_windup(s); /* align on byte boundary */ if (header) { put_short(s, (ush)len); put_short(s, (ush)~len); #ifdef DEBUG s->bits_sent += 2*16; #endif } #ifdef DEBUG s->bits_sent += (ulg)len<<3; #endif while (len--) { put_byte(s, *buf++); } } /* eof */ Rglpk/src/GLPK/zlib/zio.h0000644000176000001440000000111312245352174014620 0ustar ripleyusers/* zio.h (simulation of POSIX low-level I/O functions) */ /* Written by Andrew Makhorin , June 2013 * For conditions of distribution and use, see copyright notice in * zlib.h */ #ifndef ZIO_H #define ZIO_H #include "zsymb.h" #define O_RDONLY 0x00 #define O_WRONLY 0x01 #define O_CREAT 0x10 #define O_TRUNC 0x20 #define O_APPEND 0x40 int open(const char *path, int oflag, ...); long read(int fd, void *buf, unsigned long cnt); long write(int fd, const void *buf, unsigned long cnt); long lseek(int fd, long offset, int whence); int close(int fd); #endif /* eof */ Rglpk/src/GLPK/zlib/inffixed.h0000644000176000001440000001427412245352174015627 0ustar ripleyusers /* inffixed.h -- table for decoding fixed codes * Generated automatically by makefixed(). */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of this library and is subject to change. Applications should only use zlib.h. */ static const code lenfix[512] = { {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, {0,9,255} }; static const code distfix[32] = { {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, {22,5,193},{64,5,0} }; Rglpk/src/GLPK/glpk.h0000644000176000001440000010716112245352174014026 0ustar ripleyusers/* glpk.h */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPK_H #define GLPK_H #include #include #ifdef __cplusplus extern "C" { #endif /* library version numbers: */ #define GLP_MAJOR_VERSION 4 #define GLP_MINOR_VERSION 52 typedef struct glp_prob glp_prob; /* LP/MIP problem object */ /* optimization direction flag: */ #define GLP_MIN 1 /* minimization */ #define GLP_MAX 2 /* maximization */ /* kind of structural variable: */ #define GLP_CV 1 /* continuous variable */ #define GLP_IV 2 /* integer variable */ #define GLP_BV 3 /* binary variable */ /* type of auxiliary/structural variable: */ #define GLP_FR 1 /* free (unbounded) variable */ #define GLP_LO 2 /* variable with lower bound */ #define GLP_UP 3 /* variable with upper bound */ #define GLP_DB 4 /* double-bounded variable */ #define GLP_FX 5 /* fixed variable */ /* status of auxiliary/structural variable: */ #define GLP_BS 1 /* basic variable */ #define GLP_NL 2 /* non-basic variable on lower bound */ #define GLP_NU 3 /* non-basic variable on upper bound */ #define GLP_NF 4 /* non-basic free (unbounded) variable */ #define GLP_NS 5 /* non-basic fixed variable */ /* scaling options: */ #define GLP_SF_GM 0x01 /* perform geometric mean scaling */ #define GLP_SF_EQ 0x10 /* perform equilibration scaling */ #define GLP_SF_2N 0x20 /* round scale factors to power of two */ #define GLP_SF_SKIP 0x40 /* skip if problem is well scaled */ #define GLP_SF_AUTO 0x80 /* choose scaling options automatically */ /* solution indicator: */ #define GLP_SOL 1 /* basic solution */ #define GLP_IPT 2 /* interior-point solution */ #define GLP_MIP 3 /* mixed integer solution */ /* solution status: */ #define GLP_UNDEF 1 /* solution is undefined */ #define GLP_FEAS 2 /* solution is feasible */ #define GLP_INFEAS 3 /* solution is infeasible */ #define GLP_NOFEAS 4 /* no feasible solution exists */ #define GLP_OPT 5 /* solution is optimal */ #define GLP_UNBND 6 /* solution is unbounded */ typedef struct { /* basis factorization control parameters */ int msg_lev; /* (reserved) */ int type; /* factorization type: */ #define GLP_BF_FT 1 /* LUF + Forrest-Tomlin */ #define GLP_BF_BG 2 /* LUF + Schur compl. + Bartels-Golub */ #define GLP_BF_GR 3 /* LUF + Schur compl. + Givens rotation */ int lu_size; /* luf.sv_size */ double piv_tol; /* luf.piv_tol */ int piv_lim; /* luf.piv_lim */ int suhl; /* luf.suhl */ double eps_tol; /* luf.eps_tol */ double max_gro; /* luf.max_gro */ int nfs_max; /* fhv.hh_max */ double upd_tol; /* fhv.upd_tol */ int nrs_max; /* lpf.n_max */ int rs_size; /* lpf.v_size */ double foo_bar[38]; /* (reserved) */ } glp_bfcp; typedef struct { /* simplex method control parameters */ int msg_lev; /* message level: */ #define GLP_MSG_OFF 0 /* no output */ #define GLP_MSG_ERR 1 /* warning and error messages only */ #define GLP_MSG_ON 2 /* normal output */ #define GLP_MSG_ALL 3 /* full output */ #define GLP_MSG_DBG 4 /* debug output */ int meth; /* simplex method option: */ #define GLP_PRIMAL 1 /* use primal simplex */ #define GLP_DUALP 2 /* use dual; if it fails, use primal */ #define GLP_DUAL 3 /* use dual simplex */ int pricing; /* pricing technique: */ #define GLP_PT_STD 0x11 /* standard (Dantzig rule) */ #define GLP_PT_PSE 0x22 /* projected steepest edge */ int r_test; /* ratio test technique: */ #define GLP_RT_STD 0x11 /* standard (textbook) */ #define GLP_RT_HAR 0x22 /* two-pass Harris' ratio test */ double tol_bnd; /* spx.tol_bnd */ double tol_dj; /* spx.tol_dj */ double tol_piv; /* spx.tol_piv */ double obj_ll; /* spx.obj_ll */ double obj_ul; /* spx.obj_ul */ int it_lim; /* spx.it_lim */ int tm_lim; /* spx.tm_lim (milliseconds) */ int out_frq; /* spx.out_frq */ int out_dly; /* spx.out_dly (milliseconds) */ int presolve; /* enable/disable using LP presolver */ double foo_bar[36]; /* (reserved) */ } glp_smcp; typedef struct { /* interior-point solver control parameters */ int msg_lev; /* message level (see glp_smcp) */ int ord_alg; /* ordering algorithm: */ #define GLP_ORD_NONE 0 /* natural (original) ordering */ #define GLP_ORD_QMD 1 /* quotient minimum degree (QMD) */ #define GLP_ORD_AMD 2 /* approx. minimum degree (AMD) */ #define GLP_ORD_SYMAMD 3 /* approx. minimum degree (SYMAMD) */ double foo_bar[48]; /* (reserved) */ } glp_iptcp; typedef struct glp_tree glp_tree; /* branch-and-bound tree */ typedef struct { /* integer optimizer control parameters */ int msg_lev; /* message level (see glp_smcp) */ int br_tech; /* branching technique: */ #define GLP_BR_FFV 1 /* first fractional variable */ #define GLP_BR_LFV 2 /* last fractional variable */ #define GLP_BR_MFV 3 /* most fractional variable */ #define GLP_BR_DTH 4 /* heuristic by Driebeck and Tomlin */ #define GLP_BR_PCH 5 /* hybrid pseudocost heuristic */ int bt_tech; /* backtracking technique: */ #define GLP_BT_DFS 1 /* depth first search */ #define GLP_BT_BFS 2 /* breadth first search */ #define GLP_BT_BLB 3 /* best local bound */ #define GLP_BT_BPH 4 /* best projection heuristic */ double tol_int; /* mip.tol_int */ double tol_obj; /* mip.tol_obj */ int tm_lim; /* mip.tm_lim (milliseconds) */ int out_frq; /* mip.out_frq (milliseconds) */ int out_dly; /* mip.out_dly (milliseconds) */ void (*cb_func)(glp_tree *T, void *info); /* mip.cb_func */ void *cb_info; /* mip.cb_info */ int cb_size; /* mip.cb_size */ int pp_tech; /* preprocessing technique: */ #define GLP_PP_NONE 0 /* disable preprocessing */ #define GLP_PP_ROOT 1 /* preprocessing only on root level */ #define GLP_PP_ALL 2 /* preprocessing on all levels */ double mip_gap; /* relative MIP gap tolerance */ int mir_cuts; /* MIR cuts (GLP_ON/GLP_OFF) */ int gmi_cuts; /* Gomory's cuts (GLP_ON/GLP_OFF) */ int cov_cuts; /* cover cuts (GLP_ON/GLP_OFF) */ int clq_cuts; /* clique cuts (GLP_ON/GLP_OFF) */ int presolve; /* enable/disable using MIP presolver */ int binarize; /* try to binarize integer variables */ int fp_heur; /* feasibility pump heuristic */ #if 1 /* 25/V-2013 */ int ps_heur; /* proximity search heuristic */ #endif #if 1 /* 29/VI-2013 */ int ps_tm_lim; /* proxy time limit, milliseconds */ #endif #if 1 /* 11/VII-2013 */ int use_sol; /* use existing solution */ const char *save_sol; /* filename to save every new solution */ #endif #if 1 /* 28/V-2010 */ int alien; /* use alien solver */ #endif double foo_bar[25]; /* (reserved) */ } glp_iocp; typedef struct { /* additional row attributes */ int level; /* subproblem level at which the row was added */ int origin; /* row origin flag: */ #define GLP_RF_REG 0 /* regular constraint */ #define GLP_RF_LAZY 1 /* "lazy" constraint */ #define GLP_RF_CUT 2 /* cutting plane constraint */ int klass; /* row class descriptor: */ #define GLP_RF_GMI 1 /* Gomory's mixed integer cut */ #define GLP_RF_MIR 2 /* mixed integer rounding cut */ #define GLP_RF_COV 3 /* mixed cover cut */ #define GLP_RF_CLQ 4 /* clique cut */ double foo_bar[7]; /* (reserved) */ } glp_attr; /* enable/disable flag: */ #define GLP_ON 1 /* enable something */ #define GLP_OFF 0 /* disable something */ /* reason codes: */ #define GLP_IROWGEN 0x01 /* request for row generation */ #define GLP_IBINGO 0x02 /* better integer solution found */ #define GLP_IHEUR 0x03 /* request for heuristic solution */ #define GLP_ICUTGEN 0x04 /* request for cut generation */ #define GLP_IBRANCH 0x05 /* request for branching */ #define GLP_ISELECT 0x06 /* request for subproblem selection */ #define GLP_IPREPRO 0x07 /* request for preprocessing */ /* branch selection indicator: */ #define GLP_NO_BRNCH 0 /* select no branch */ #define GLP_DN_BRNCH 1 /* select down-branch */ #define GLP_UP_BRNCH 2 /* select up-branch */ /* return codes: */ #define GLP_EBADB 0x01 /* invalid basis */ #define GLP_ESING 0x02 /* singular matrix */ #define GLP_ECOND 0x03 /* ill-conditioned matrix */ #define GLP_EBOUND 0x04 /* invalid bounds */ #define GLP_EFAIL 0x05 /* solver failed */ #define GLP_EOBJLL 0x06 /* objective lower limit reached */ #define GLP_EOBJUL 0x07 /* objective upper limit reached */ #define GLP_EITLIM 0x08 /* iteration limit exceeded */ #define GLP_ETMLIM 0x09 /* time limit exceeded */ #define GLP_ENOPFS 0x0A /* no primal feasible solution */ #define GLP_ENODFS 0x0B /* no dual feasible solution */ #define GLP_EROOT 0x0C /* root LP optimum not provided */ #define GLP_ESTOP 0x0D /* search terminated by application */ #define GLP_EMIPGAP 0x0E /* relative mip gap tolerance reached */ #define GLP_ENOFEAS 0x0F /* no primal/dual feasible solution */ #define GLP_ENOCVG 0x10 /* no convergence */ #define GLP_EINSTAB 0x11 /* numerical instability */ #define GLP_EDATA 0x12 /* invalid data */ #define GLP_ERANGE 0x13 /* result out of range */ /* condition indicator: */ #define GLP_KKT_PE 1 /* primal equalities */ #define GLP_KKT_PB 2 /* primal bounds */ #define GLP_KKT_DE 3 /* dual equalities */ #define GLP_KKT_DB 4 /* dual bounds */ #define GLP_KKT_CS 5 /* complementary slackness */ /* MPS file format: */ #define GLP_MPS_DECK 1 /* fixed (ancient) */ #define GLP_MPS_FILE 2 /* free (modern) */ typedef struct { /* MPS format control parameters */ int blank; /* character code to replace blanks in symbolic names */ char *obj_name; /* objective row name */ double tol_mps; /* zero tolerance for MPS data */ double foo_bar[17]; /* (reserved for use in the future) */ } glp_mpscp; typedef struct { /* CPLEX LP format control parameters */ double foo_bar[20]; /* (reserved for use in the future) */ } glp_cpxcp; typedef struct glp_tran glp_tran; /* MathProg translator workspace */ glp_prob *glp_create_prob(void); /* create problem object */ void glp_set_prob_name(glp_prob *P, const char *name); /* assign (change) problem name */ void glp_set_obj_name(glp_prob *P, const char *name); /* assign (change) objective function name */ void glp_set_obj_dir(glp_prob *P, int dir); /* set (change) optimization direction flag */ int glp_add_rows(glp_prob *P, int nrs); /* add new rows to problem object */ int glp_add_cols(glp_prob *P, int ncs); /* add new columns to problem object */ void glp_set_row_name(glp_prob *P, int i, const char *name); /* assign (change) row name */ void glp_set_col_name(glp_prob *P, int j, const char *name); /* assign (change) column name */ void glp_set_row_bnds(glp_prob *P, int i, int type, double lb, double ub); /* set (change) row bounds */ void glp_set_col_bnds(glp_prob *P, int j, int type, double lb, double ub); /* set (change) column bounds */ void glp_set_obj_coef(glp_prob *P, int j, double coef); /* set (change) obj. coefficient or constant term */ void glp_set_mat_row(glp_prob *P, int i, int len, const int ind[], const double val[]); /* set (replace) row of the constraint matrix */ void glp_set_mat_col(glp_prob *P, int j, int len, const int ind[], const double val[]); /* set (replace) column of the constraint matrix */ void glp_load_matrix(glp_prob *P, int ne, const int ia[], const int ja[], const double ar[]); /* load (replace) the whole constraint matrix */ int glp_check_dup(int m, int n, int ne, const int ia[], const int ja[]); /* check for duplicate elements in sparse matrix */ void glp_sort_matrix(glp_prob *P); /* sort elements of the constraint matrix */ void glp_del_rows(glp_prob *P, int nrs, const int num[]); /* delete specified rows from problem object */ void glp_del_cols(glp_prob *P, int ncs, const int num[]); /* delete specified columns from problem object */ void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names); /* copy problem object content */ void glp_erase_prob(glp_prob *P); /* erase problem object content */ void glp_delete_prob(glp_prob *P); /* delete problem object */ const char *glp_get_prob_name(glp_prob *P); /* retrieve problem name */ const char *glp_get_obj_name(glp_prob *P); /* retrieve objective function name */ int glp_get_obj_dir(glp_prob *P); /* retrieve optimization direction flag */ int glp_get_num_rows(glp_prob *P); /* retrieve number of rows */ int glp_get_num_cols(glp_prob *P); /* retrieve number of columns */ const char *glp_get_row_name(glp_prob *P, int i); /* retrieve row name */ const char *glp_get_col_name(glp_prob *P, int j); /* retrieve column name */ int glp_get_row_type(glp_prob *P, int i); /* retrieve row type */ double glp_get_row_lb(glp_prob *P, int i); /* retrieve row lower bound */ double glp_get_row_ub(glp_prob *P, int i); /* retrieve row upper bound */ int glp_get_col_type(glp_prob *P, int j); /* retrieve column type */ double glp_get_col_lb(glp_prob *P, int j); /* retrieve column lower bound */ double glp_get_col_ub(glp_prob *P, int j); /* retrieve column upper bound */ double glp_get_obj_coef(glp_prob *P, int j); /* retrieve obj. coefficient or constant term */ int glp_get_num_nz(glp_prob *P); /* retrieve number of constraint coefficients */ int glp_get_mat_row(glp_prob *P, int i, int ind[], double val[]); /* retrieve row of the constraint matrix */ int glp_get_mat_col(glp_prob *P, int j, int ind[], double val[]); /* retrieve column of the constraint matrix */ void glp_create_index(glp_prob *P); /* create the name index */ int glp_find_row(glp_prob *P, const char *name); /* find row by its name */ int glp_find_col(glp_prob *P, const char *name); /* find column by its name */ void glp_delete_index(glp_prob *P); /* delete the name index */ void glp_set_rii(glp_prob *P, int i, double rii); /* set (change) row scale factor */ void glp_set_sjj(glp_prob *P, int j, double sjj); /* set (change) column scale factor */ double glp_get_rii(glp_prob *P, int i); /* retrieve row scale factor */ double glp_get_sjj(glp_prob *P, int j); /* retrieve column scale factor */ void glp_scale_prob(glp_prob *P, int flags); /* scale problem data */ void glp_unscale_prob(glp_prob *P); /* unscale problem data */ void glp_set_row_stat(glp_prob *P, int i, int stat); /* set (change) row status */ void glp_set_col_stat(glp_prob *P, int j, int stat); /* set (change) column status */ void glp_std_basis(glp_prob *P); /* construct standard initial LP basis */ void glp_adv_basis(glp_prob *P, int flags); /* construct advanced initial LP basis */ void glp_cpx_basis(glp_prob *P); /* construct Bixby's initial LP basis */ int glp_simplex(glp_prob *P, const glp_smcp *parm); /* solve LP problem with the simplex method */ int glp_exact(glp_prob *P, const glp_smcp *parm); /* solve LP problem in exact arithmetic */ void glp_init_smcp(glp_smcp *parm); /* initialize simplex method control parameters */ int glp_get_status(glp_prob *P); /* retrieve generic status of basic solution */ int glp_get_prim_stat(glp_prob *P); /* retrieve status of primal basic solution */ int glp_get_dual_stat(glp_prob *P); /* retrieve status of dual basic solution */ double glp_get_obj_val(glp_prob *P); /* retrieve objective value (basic solution) */ int glp_get_row_stat(glp_prob *P, int i); /* retrieve row status */ double glp_get_row_prim(glp_prob *P, int i); /* retrieve row primal value (basic solution) */ double glp_get_row_dual(glp_prob *P, int i); /* retrieve row dual value (basic solution) */ int glp_get_col_stat(glp_prob *P, int j); /* retrieve column status */ double glp_get_col_prim(glp_prob *P, int j); /* retrieve column primal value (basic solution) */ double glp_get_col_dual(glp_prob *P, int j); /* retrieve column dual value (basic solution) */ int glp_get_unbnd_ray(glp_prob *P); /* determine variable causing unboundedness */ int glp_interior(glp_prob *P, const glp_iptcp *parm); /* solve LP problem with the interior-point method */ void glp_init_iptcp(glp_iptcp *parm); /* initialize interior-point solver control parameters */ int glp_ipt_status(glp_prob *P); /* retrieve status of interior-point solution */ double glp_ipt_obj_val(glp_prob *P); /* retrieve objective value (interior point) */ double glp_ipt_row_prim(glp_prob *P, int i); /* retrieve row primal value (interior point) */ double glp_ipt_row_dual(glp_prob *P, int i); /* retrieve row dual value (interior point) */ double glp_ipt_col_prim(glp_prob *P, int j); /* retrieve column primal value (interior point) */ double glp_ipt_col_dual(glp_prob *P, int j); /* retrieve column dual value (interior point) */ void glp_set_col_kind(glp_prob *P, int j, int kind); /* set (change) column kind */ int glp_get_col_kind(glp_prob *P, int j); /* retrieve column kind */ int glp_get_num_int(glp_prob *P); /* retrieve number of integer columns */ int glp_get_num_bin(glp_prob *P); /* retrieve number of binary columns */ int glp_intopt(glp_prob *P, const glp_iocp *parm); /* solve MIP problem with the branch-and-bound method */ void glp_init_iocp(glp_iocp *parm); /* initialize integer optimizer control parameters */ int glp_mip_status(glp_prob *P); /* retrieve status of MIP solution */ double glp_mip_obj_val(glp_prob *P); /* retrieve objective value (MIP solution) */ double glp_mip_row_val(glp_prob *P, int i); /* retrieve row value (MIP solution) */ double glp_mip_col_val(glp_prob *P, int j); /* retrieve column value (MIP solution) */ void glp_check_kkt(glp_prob *P, int sol, int cond, double *ae_max, int *ae_ind, double *re_max, int *re_ind); /* check feasibility/optimality conditions */ int glp_print_sol(glp_prob *P, const char *fname); /* write basic solution in printable format */ int glp_read_sol(glp_prob *P, const char *fname); /* read basic solution from text file */ int glp_write_sol(glp_prob *P, const char *fname); /* write basic solution to text file */ int glp_print_ranges(glp_prob *P, int len, const int list[], int flags, const char *fname); /* print sensitivity analysis report */ int glp_print_ipt(glp_prob *P, const char *fname); /* write interior-point solution in printable format */ int glp_read_ipt(glp_prob *P, const char *fname); /* read interior-point solution from text file */ int glp_write_ipt(glp_prob *P, const char *fname); /* write interior-point solution to text file */ int glp_print_mip(glp_prob *P, const char *fname); /* write MIP solution in printable format */ int glp_read_mip(glp_prob *P, const char *fname); /* read MIP solution from text file */ int glp_write_mip(glp_prob *P, const char *fname); /* write MIP solution to text file */ int glp_bf_exists(glp_prob *P); /* check if the basis factorization exists */ int glp_factorize(glp_prob *P); /* compute the basis factorization */ int glp_bf_updated(glp_prob *P); /* check if the basis factorization has been updated */ void glp_get_bfcp(glp_prob *P, glp_bfcp *parm); /* retrieve basis factorization control parameters */ void glp_set_bfcp(glp_prob *P, const glp_bfcp *parm); /* change basis factorization control parameters */ int glp_get_bhead(glp_prob *P, int k); /* retrieve the basis header information */ int glp_get_row_bind(glp_prob *P, int i); /* retrieve row index in the basis header */ int glp_get_col_bind(glp_prob *P, int j); /* retrieve column index in the basis header */ void glp_ftran(glp_prob *P, double x[]); /* perform forward transformation (solve system B*x = b) */ void glp_btran(glp_prob *P, double x[]); /* perform backward transformation (solve system B'*x = b) */ int glp_warm_up(glp_prob *P); /* "warm up" LP basis */ int glp_eval_tab_row(glp_prob *P, int k, int ind[], double val[]); /* compute row of the simplex tableau */ int glp_eval_tab_col(glp_prob *P, int k, int ind[], double val[]); /* compute column of the simplex tableau */ int glp_transform_row(glp_prob *P, int len, int ind[], double val[]); /* transform explicitly specified row */ int glp_transform_col(glp_prob *P, int len, int ind[], double val[]); /* transform explicitly specified column */ int glp_prim_rtest(glp_prob *P, int len, const int ind[], const double val[], int dir, double eps); /* perform primal ratio test */ int glp_dual_rtest(glp_prob *P, int len, const int ind[], const double val[], int dir, double eps); /* perform dual ratio test */ void glp_analyze_bound(glp_prob *P, int k, double *value1, int *var1, double *value2, int *var2); /* analyze active bound of non-basic variable */ void glp_analyze_coef(glp_prob *P, int k, double *coef1, int *var1, double *value1, double *coef2, int *var2, double *value2); /* analyze objective coefficient at basic variable */ int glp_ios_reason(glp_tree *T); /* determine reason for calling the callback routine */ glp_prob *glp_ios_get_prob(glp_tree *T); /* access the problem object */ void glp_ios_tree_size(glp_tree *T, int *a_cnt, int *n_cnt, int *t_cnt); /* determine size of the branch-and-bound tree */ int glp_ios_curr_node(glp_tree *T); /* determine current active subproblem */ int glp_ios_next_node(glp_tree *T, int p); /* determine next active subproblem */ int glp_ios_prev_node(glp_tree *T, int p); /* determine previous active subproblem */ int glp_ios_up_node(glp_tree *T, int p); /* determine parent subproblem */ int glp_ios_node_level(glp_tree *T, int p); /* determine subproblem level */ double glp_ios_node_bound(glp_tree *T, int p); /* determine subproblem local bound */ int glp_ios_best_node(glp_tree *T); /* find active subproblem with best local bound */ double glp_ios_mip_gap(glp_tree *T); /* compute relative MIP gap */ void *glp_ios_node_data(glp_tree *T, int p); /* access subproblem application-specific data */ void glp_ios_row_attr(glp_tree *T, int i, glp_attr *attr); /* retrieve additional row attributes */ int glp_ios_pool_size(glp_tree *T); /* determine current size of the cut pool */ int glp_ios_add_row(glp_tree *T, const char *name, int klass, int flags, int len, const int ind[], const double val[], int type, double rhs); /* add row (constraint) to the cut pool */ void glp_ios_del_row(glp_tree *T, int i); /* remove row (constraint) from the cut pool */ void glp_ios_clear_pool(glp_tree *T); /* remove all rows (constraints) from the cut pool */ int glp_ios_can_branch(glp_tree *T, int j); /* check if can branch upon specified variable */ void glp_ios_branch_upon(glp_tree *T, int j, int sel); /* choose variable to branch upon */ void glp_ios_select_node(glp_tree *T, int p); /* select subproblem to continue the search */ int glp_ios_heur_sol(glp_tree *T, const double x[]); /* provide solution found by heuristic */ void glp_ios_terminate(glp_tree *T); /* terminate the solution process */ void glp_init_mpscp(glp_mpscp *parm); /* initialize MPS format control parameters */ int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm, const char *fname); /* read problem data in MPS format */ int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm, const char *fname); /* write problem data in MPS format */ void glp_init_cpxcp(glp_cpxcp *parm); /* initialize CPLEX LP format control parameters */ int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname); /* read problem data in CPLEX LP format */ int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname); /* write problem data in CPLEX LP format */ int glp_read_prob(glp_prob *P, int flags, const char *fname); /* read problem data in GLPK format */ int glp_write_prob(glp_prob *P, int flags, const char *fname); /* write problem data in GLPK format */ glp_tran *glp_mpl_alloc_wksp(void); /* allocate the MathProg translator workspace */ int glp_mpl_read_model(glp_tran *tran, const char *fname, int skip); /* read and translate model section */ int glp_mpl_read_data(glp_tran *tran, const char *fname); /* read and translate data section */ int glp_mpl_generate(glp_tran *tran, const char *fname); /* generate the model */ void glp_mpl_build_prob(glp_tran *tran, glp_prob *prob); /* build LP/MIP problem instance from the model */ int glp_mpl_postsolve(glp_tran *tran, glp_prob *prob, int sol); /* postsolve the model */ void glp_mpl_free_wksp(glp_tran *tran); /* free the MathProg translator workspace */ int glp_main(int argc, const char *argv[]); /* stand-alone LP/MIP solver */ int glp_read_cnfsat(glp_prob *P, const char *fname); /* read CNF-SAT problem data in DIMACS format */ int glp_check_cnfsat(glp_prob *P); /* check for CNF-SAT problem instance */ int glp_write_cnfsat(glp_prob *P, const char *fname); /* write CNF-SAT problem data in DIMACS format */ int glp_minisat1(glp_prob *P); /* solve CNF-SAT problem with MiniSat solver */ int glp_intfeas1(glp_prob *P, int use_bound, int obj_bound); /* solve integer feasibility problem */ int glp_init_env(void); /* initialize GLPK environment */ const char *glp_version(void); /* determine library version */ int glp_free_env(void); /* free GLPK environment */ void glp_puts(const char *s); /* write string on terminal */ void glp_printf(const char *fmt, ...); /* write formatted output on terminal */ void glp_vprintf(const char *fmt, va_list arg); /* write formatted output on terminal */ int glp_term_out(int flag); /* enable/disable terminal output */ void glp_term_hook(int (*func)(void *info, const char *s), void *info); /* install hook to intercept terminal output */ int glp_open_tee(const char *name); /* start copying terminal output to text file */ int glp_close_tee(void); /* stop copying terminal output to text file */ #ifndef GLP_ERRFUNC_DEFINED #define GLP_ERRFUNC_DEFINED typedef void (*glp_errfunc)(const char *fmt, ...); #endif #define glp_error glp_error_(__FILE__, __LINE__) glp_errfunc glp_error_(const char *file, int line); /* display fatal error message and terminate execution */ #define glp_assert(expr) \ ((void)((expr) || (glp_assert_(#expr, __FILE__, __LINE__), 1))) void glp_assert_(const char *expr, const char *file, int line); /* check for logical condition */ void glp_error_hook(void (*func)(void *info), void *info); /* install hook to intercept abnormal termination */ #define glp_malloc(size) glp_alloc(1, size) /* allocate memory block (obsolete) */ #define glp_calloc(n, size) glp_alloc(n, size) /* allocate memory block (obsolete) */ void *glp_alloc(int n, int size); /* allocate memory block */ void *glp_realloc(void *ptr, int n, int size); /* reallocate memory block */ void glp_free(void *ptr); /* free (deallocate) memory block */ void glp_mem_limit(int limit); /* set memory usage limit */ void glp_mem_usage(int *count, int *cpeak, size_t *total, size_t *tpeak); /* get memory usage information */ typedef struct glp_graph glp_graph; typedef struct glp_vertex glp_vertex; typedef struct glp_arc glp_arc; struct glp_graph { /* graph descriptor */ void *pool; /* DMP *pool; */ /* memory pool to store graph components */ char *name; /* graph name (1 to 255 chars); NULL means no name is assigned to the graph */ int nv_max; /* length of the vertex list (enlarged automatically) */ int nv; /* number of vertices in the graph, 0 <= nv <= nv_max */ int na; /* number of arcs in the graph, na >= 0 */ glp_vertex **v; /* glp_vertex *v[1+nv_max]; */ /* v[i], 1 <= i <= nv, is a pointer to i-th vertex */ void *index; /* AVL *index; */ /* vertex index to find vertices by their names; NULL means the index does not exist */ int v_size; /* size of data associated with each vertex (0 to 256 bytes) */ int a_size; /* size of data associated with each arc (0 to 256 bytes) */ }; struct glp_vertex { /* vertex descriptor */ int i; /* vertex ordinal number, 1 <= i <= nv */ char *name; /* vertex name (1 to 255 chars); NULL means no name is assigned to the vertex */ void *entry; /* AVLNODE *entry; */ /* pointer to corresponding entry in the vertex index; NULL means that either the index does not exist or the vertex has no name assigned */ void *data; /* pointer to data associated with the vertex */ void *temp; /* working pointer */ glp_arc *in; /* pointer to the (unordered) list of incoming arcs */ glp_arc *out; /* pointer to the (unordered) list of outgoing arcs */ }; struct glp_arc { /* arc descriptor */ glp_vertex *tail; /* pointer to the tail endpoint */ glp_vertex *head; /* pointer to the head endpoint */ void *data; /* pointer to data associated with the arc */ void *temp; /* working pointer */ glp_arc *t_prev; /* pointer to previous arc having the same tail endpoint */ glp_arc *t_next; /* pointer to next arc having the same tail endpoint */ glp_arc *h_prev; /* pointer to previous arc having the same head endpoint */ glp_arc *h_next; /* pointer to next arc having the same head endpoint */ }; glp_graph *glp_create_graph(int v_size, int a_size); /* create graph */ void glp_set_graph_name(glp_graph *G, const char *name); /* assign (change) graph name */ int glp_add_vertices(glp_graph *G, int nadd); /* add new vertices to graph */ void glp_set_vertex_name(glp_graph *G, int i, const char *name); /* assign (change) vertex name */ glp_arc *glp_add_arc(glp_graph *G, int i, int j); /* add new arc to graph */ void glp_del_vertices(glp_graph *G, int ndel, const int num[]); /* delete vertices from graph */ void glp_del_arc(glp_graph *G, glp_arc *a); /* delete arc from graph */ void glp_erase_graph(glp_graph *G, int v_size, int a_size); /* erase graph content */ void glp_delete_graph(glp_graph *G); /* delete graph */ void glp_create_v_index(glp_graph *G); /* create vertex name index */ int glp_find_vertex(glp_graph *G, const char *name); /* find vertex by its name */ void glp_delete_v_index(glp_graph *G); /* delete vertex name index */ int glp_read_graph(glp_graph *G, const char *fname); /* read graph from plain text file */ int glp_write_graph(glp_graph *G, const char *fname); /* write graph to plain text file */ void glp_mincost_lp(glp_prob *P, glp_graph *G, int names, int v_rhs, int a_low, int a_cap, int a_cost); /* convert minimum cost flow problem to LP */ int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low, int a_cap, int a_cost, double *sol, int a_x, int v_pi); /* find minimum-cost flow with out-of-kilter algorithm */ int glp_mincost_relax4(glp_graph *G, int v_rhs, int a_low, int a_cap, int a_cost, int crash, double *sol, int a_x, int a_rc); /* find minimum-cost flow with Bertsekas-Tseng relaxation method */ void glp_maxflow_lp(glp_prob *P, glp_graph *G, int names, int s, int t, int a_cap); /* convert maximum flow problem to LP */ int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap, double *sol, int a_x, int v_cut); /* find maximal flow with Ford-Fulkerson algorithm */ int glp_check_asnprob(glp_graph *G, int v_set); /* check correctness of assignment problem data */ /* assignment problem formulation: */ #define GLP_ASN_MIN 1 /* perfect matching (minimization) */ #define GLP_ASN_MAX 2 /* perfect matching (maximization) */ #define GLP_ASN_MMP 3 /* maximum matching */ int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names, int v_set, int a_cost); /* convert assignment problem to LP */ int glp_asnprob_okalg(int form, glp_graph *G, int v_set, int a_cost, double *sol, int a_x); /* solve assignment problem with out-of-kilter algorithm */ int glp_asnprob_hall(glp_graph *G, int v_set, int a_x); /* find bipartite matching of maximum cardinality */ double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls); /* solve critical path problem */ int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap, int a_cost, const char *fname); /* read min-cost flow problem data in DIMACS format */ int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap, int a_cost, const char *fname); /* write min-cost flow problem data in DIMACS format */ int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap, const char *fname); /* read maximum flow problem data in DIMACS format */ int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap, const char *fname); /* write maximum flow problem data in DIMACS format */ int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, const char *fname); /* read assignment problem data in DIMACS format */ int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, const char *fname); /* write assignment problem data in DIMACS format */ int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname); /* read graph in DIMACS clique/coloring format */ int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname); /* write graph in DIMACS clique/coloring format */ int glp_netgen(glp_graph *G, int v_rhs, int a_cap, int a_cost, const int parm[1+15]); /* Klingman's network problem generator */ void glp_netgen_prob(int nprob, int parm[1+15]); /* Klingman's standard network problem instance */ int glp_gridgen(glp_graph *G, int v_rhs, int a_cap, int a_cost, const int parm[1+14]); /* grid-like network problem generator */ int glp_rmfgen(glp_graph *G, int *s, int *t, int a_cap, const int parm[1+5]); /* Goldfarb's maximum flow problem generator */ int glp_weak_comp(glp_graph *G, int v_num); /* find all weakly connected components of graph */ int glp_strong_comp(glp_graph *G, int v_num); /* find all strongly connected components of graph */ int glp_top_sort(glp_graph *G, int v_num); /* topological sorting of acyclic digraph */ int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol, int v_set); /* find maximum weight clique with exact algorithm */ #ifdef __cplusplus } #endif #endif /* eof */ Rglpk/src/GLPK/glpapi11.c0000644000176000001440000012706412245352174014506 0ustar ripleyusers/* glpapi11.c (utility routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #if 1 /* 11/VI-2013 */ #include "env2.h" #endif #include "glpapi.h" #include "glpsdf.h" int glp_print_sol(glp_prob *P, const char *fname) { /* write basic solution in printable format */ XFILE *fp; GLPROW *row; GLPCOL *col; int i, j, t, ae_ind, re_ind, ret; double ae_max, re_max; xprintf("Writing basic solution to `%s'...\n", fname); fp = xfopen(fname, "w"); if (fp == NULL) { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } xfprintf(fp, "%-12s%s\n", "Problem:", P->name == NULL ? "" : P->name); xfprintf(fp, "%-12s%d\n", "Rows:", P->m); xfprintf(fp, "%-12s%d\n", "Columns:", P->n); xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz); t = glp_get_status(P); xfprintf(fp, "%-12s%s\n", "Status:", t == GLP_OPT ? "OPTIMAL" : t == GLP_FEAS ? "FEASIBLE" : t == GLP_INFEAS ? "INFEASIBLE (INTERMEDIATE)" : t == GLP_NOFEAS ? "INFEASIBLE (FINAL)" : t == GLP_UNBND ? "UNBOUNDED" : t == GLP_UNDEF ? "UNDEFINED" : "???"); xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:", P->obj == NULL ? "" : P->obj, P->obj == NULL ? "" : " = ", P->obj_val, P->dir == GLP_MIN ? "MINimum" : P->dir == GLP_MAX ? "MAXimum" : "???"); xfprintf(fp, "\n"); xfprintf(fp, " No. Row name St Activity Lower bound " " Upper bound Marginal\n"); xfprintf(fp, "------ ------------ -- ------------- ------------- " "------------- -------------\n"); for (i = 1; i <= P->m; i++) { row = P->row[i]; xfprintf(fp, "%6d ", i); if (row->name == NULL || strlen(row->name) <= 12) xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name); else xfprintf(fp, "%s\n%20s", row->name, ""); xfprintf(fp, "%s ", row->stat == GLP_BS ? "B " : row->stat == GLP_NL ? "NL" : row->stat == GLP_NU ? "NU" : row->stat == GLP_NF ? "NF" : row->stat == GLP_NS ? "NS" : "??"); xfprintf(fp, "%13.6g ", fabs(row->prim) <= 1e-9 ? 0.0 : row->prim); if (row->type == GLP_LO || row->type == GLP_DB || row->type == GLP_FX) xfprintf(fp, "%13.6g ", row->lb); else xfprintf(fp, "%13s ", ""); if (row->type == GLP_UP || row->type == GLP_DB) xfprintf(fp, "%13.6g ", row->ub); else xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : ""); if (row->stat != GLP_BS) { if (fabs(row->dual) <= 1e-9) xfprintf(fp, "%13s", "< eps"); else xfprintf(fp, "%13.6g ", row->dual); } xfprintf(fp, "\n"); } xfprintf(fp, "\n"); xfprintf(fp, " No. Column name St Activity Lower bound " " Upper bound Marginal\n"); xfprintf(fp, "------ ------------ -- ------------- ------------- " "------------- -------------\n"); for (j = 1; j <= P->n; j++) { col = P->col[j]; xfprintf(fp, "%6d ", j); if (col->name == NULL || strlen(col->name) <= 12) xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name); else xfprintf(fp, "%s\n%20s", col->name, ""); xfprintf(fp, "%s ", col->stat == GLP_BS ? "B " : col->stat == GLP_NL ? "NL" : col->stat == GLP_NU ? "NU" : col->stat == GLP_NF ? "NF" : col->stat == GLP_NS ? "NS" : "??"); xfprintf(fp, "%13.6g ", fabs(col->prim) <= 1e-9 ? 0.0 : col->prim); if (col->type == GLP_LO || col->type == GLP_DB || col->type == GLP_FX) xfprintf(fp, "%13.6g ", col->lb); else xfprintf(fp, "%13s ", ""); if (col->type == GLP_UP || col->type == GLP_DB) xfprintf(fp, "%13.6g ", col->ub); else xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : ""); if (col->stat != GLP_BS) { if (fabs(col->dual) <= 1e-9) xfprintf(fp, "%13s", "< eps"); else xfprintf(fp, "%13.6g ", col->dual); } xfprintf(fp, "\n"); } xfprintf(fp, "\n"); xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n"); xfprintf(fp, "\n"); glp_check_kkt(P, GLP_SOL, GLP_KKT_PE, &ae_max, &ae_ind, &re_max, &re_ind); xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n", ae_max, ae_ind); xfprintf(fp, " max.rel.err = %.2e on row %d\n", re_max, re_ind); xfprintf(fp, "%8s%s\n", "", re_max <= 1e-9 ? "High quality" : re_max <= 1e-6 ? "Medium quality" : re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG"); xfprintf(fp, "\n"); glp_check_kkt(P, GLP_SOL, GLP_KKT_PB, &ae_max, &ae_ind, &re_max, &re_ind); xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n", ae_max, ae_ind <= P->m ? "row" : "column", ae_ind <= P->m ? ae_ind : ae_ind - P->m); xfprintf(fp, " max.rel.err = %.2e on %s %d\n", re_max, re_ind <= P->m ? "row" : "column", re_ind <= P->m ? re_ind : re_ind - P->m); xfprintf(fp, "%8s%s\n", "", re_max <= 1e-9 ? "High quality" : re_max <= 1e-6 ? "Medium quality" : re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL" "E"); xfprintf(fp, "\n"); glp_check_kkt(P, GLP_SOL, GLP_KKT_DE, &ae_max, &ae_ind, &re_max, &re_ind); xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n", ae_max, ae_ind == 0 ? 0 : ae_ind - P->m); xfprintf(fp, " max.rel.err = %.2e on column %d\n", re_max, re_ind == 0 ? 0 : re_ind - P->m); xfprintf(fp, "%8s%s\n", "", re_max <= 1e-9 ? "High quality" : re_max <= 1e-6 ? "Medium quality" : re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG"); xfprintf(fp, "\n"); glp_check_kkt(P, GLP_SOL, GLP_KKT_DB, &ae_max, &ae_ind, &re_max, &re_ind); xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n", ae_max, ae_ind <= P->m ? "row" : "column", ae_ind <= P->m ? ae_ind : ae_ind - P->m); xfprintf(fp, " max.rel.err = %.2e on %s %d\n", re_max, re_ind <= P->m ? "row" : "column", re_ind <= P->m ? re_ind : re_ind - P->m); xfprintf(fp, "%8s%s\n", "", re_max <= 1e-9 ? "High quality" : re_max <= 1e-6 ? "Medium quality" : re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE") ; xfprintf(fp, "\n"); xfprintf(fp, "End of output\n"); xfflush(fp); if (xferror(fp)) { xprintf("Write error on `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } ret = 0; done: if (fp != NULL) xfclose(fp); return ret; } /*********************************************************************** * NAME * * glp_read_sol - read basic solution from text file * * SYNOPSIS * * int glp_read_sol(glp_prob *lp, const char *fname); * * DESCRIPTION * * The routine glp_read_sol reads basic solution from a text file whose * name is specified by the parameter fname into the problem object. * * For the file format see description of the routine glp_write_sol. * * RETURNS * * On success the routine returns zero, otherwise non-zero. */ int glp_read_sol(glp_prob *lp, const char *fname) { glp_data *data; jmp_buf jump; int i, j, k, ret = 0; xprintf("Reading basic solution from `%s'...\n", fname); data = glp_sdf_open_file(fname); if (data == NULL) { ret = 1; goto done; } if (setjmp(jump)) { ret = 1; goto done; } glp_sdf_set_jump(data, jump); /* number of rows, number of columns */ k = glp_sdf_read_int(data); if (k != lp->m) glp_sdf_error(data, "wrong number of rows\n"); k = glp_sdf_read_int(data); if (k != lp->n) glp_sdf_error(data, "wrong number of columns\n"); /* primal status, dual status, objective value */ k = glp_sdf_read_int(data); if (!(k == GLP_UNDEF || k == GLP_FEAS || k == GLP_INFEAS || k == GLP_NOFEAS)) glp_sdf_error(data, "invalid primal status\n"); lp->pbs_stat = k; k = glp_sdf_read_int(data); if (!(k == GLP_UNDEF || k == GLP_FEAS || k == GLP_INFEAS || k == GLP_NOFEAS)) glp_sdf_error(data, "invalid dual status\n"); lp->dbs_stat = k; lp->obj_val = glp_sdf_read_num(data); /* rows (auxiliary variables) */ for (i = 1; i <= lp->m; i++) { GLPROW *row = lp->row[i]; /* status, primal value, dual value */ k = glp_sdf_read_int(data); if (!(k == GLP_BS || k == GLP_NL || k == GLP_NU || k == GLP_NF || k == GLP_NS)) glp_sdf_error(data, "invalid row status\n"); glp_set_row_stat(lp, i, k); row->prim = glp_sdf_read_num(data); row->dual = glp_sdf_read_num(data); } /* columns (structural variables) */ for (j = 1; j <= lp->n; j++) { GLPCOL *col = lp->col[j]; /* status, primal value, dual value */ k = glp_sdf_read_int(data); if (!(k == GLP_BS || k == GLP_NL || k == GLP_NU || k == GLP_NF || k == GLP_NS)) glp_sdf_error(data, "invalid column status\n"); glp_set_col_stat(lp, j, k); col->prim = glp_sdf_read_num(data); col->dual = glp_sdf_read_num(data); } xprintf("%d lines were read\n", glp_sdf_line(data)); done: if (ret) lp->pbs_stat = lp->dbs_stat = GLP_UNDEF; if (data != NULL) glp_sdf_close_file(data); return ret; } /*********************************************************************** * NAME * * glp_write_sol - write basic solution to text file * * SYNOPSIS * * int glp_write_sol(glp_prob *lp, const char *fname); * * DESCRIPTION * * The routine glp_write_sol writes the current basic solution to a * text file whose name is specified by the parameter fname. This file * can be read back with the routine glp_read_sol. * * RETURNS * * On success the routine returns zero, otherwise non-zero. * * FILE FORMAT * * The file created by the routine glp_write_sol is a plain text file, * which contains the following information: * * m n * p_stat d_stat obj_val * r_stat[1] r_prim[1] r_dual[1] * . . . * r_stat[m] r_prim[m] r_dual[m] * c_stat[1] c_prim[1] c_dual[1] * . . . * c_stat[n] c_prim[n] c_dual[n] * * where: * m is the number of rows (auxiliary variables); * n is the number of columns (structural variables); * p_stat is the primal status of the basic solution (GLP_UNDEF = 1, * GLP_FEAS = 2, GLP_INFEAS = 3, or GLP_NOFEAS = 4); * d_stat is the dual status of the basic solution (GLP_UNDEF = 1, * GLP_FEAS = 2, GLP_INFEAS = 3, or GLP_NOFEAS = 4); * obj_val is the objective value; * r_stat[i], i = 1,...,m, is the status of i-th row (GLP_BS = 1, * GLP_NL = 2, GLP_NU = 3, GLP_NF = 4, or GLP_NS = 5); * r_prim[i], i = 1,...,m, is the primal value of i-th row; * r_dual[i], i = 1,...,m, is the dual value of i-th row; * c_stat[j], j = 1,...,n, is the status of j-th column (GLP_BS = 1, * GLP_NL = 2, GLP_NU = 3, GLP_NF = 4, or GLP_NS = 5); * c_prim[j], j = 1,...,n, is the primal value of j-th column; * c_dual[j], j = 1,...,n, is the dual value of j-th column. */ int glp_write_sol(glp_prob *lp, const char *fname) { XFILE *fp; int i, j, ret = 0; xprintf("Writing basic solution to `%s'...\n", fname); fp = xfopen(fname, "w"); if (fp == NULL) { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } /* number of rows, number of columns */ xfprintf(fp, "%d %d\n", lp->m, lp->n); /* primal status, dual status, objective value */ xfprintf(fp, "%d %d %.*g\n", lp->pbs_stat, lp->dbs_stat, DBL_DIG, lp->obj_val); /* rows (auxiliary variables) */ for (i = 1; i <= lp->m; i++) { GLPROW *row = lp->row[i]; /* status, primal value, dual value */ xfprintf(fp, "%d %.*g %.*g\n", row->stat, DBL_DIG, row->prim, DBL_DIG, row->dual); } /* columns (structural variables) */ for (j = 1; j <= lp->n; j++) { GLPCOL *col = lp->col[j]; /* status, primal value, dual value */ xfprintf(fp, "%d %.*g %.*g\n", col->stat, DBL_DIG, col->prim, DBL_DIG, col->dual); } xfflush(fp); if (xferror(fp)) { xprintf("Write error on `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } xprintf("%d lines were written\n", 2 + lp->m + lp->n); done: if (fp != NULL) xfclose(fp); return ret; } /**********************************************************************/ static char *format(char buf[13+1], double x) { /* format floating-point number in MPS/360-like style */ if (x == -DBL_MAX) strcpy(buf, " -Inf"); else if (x == +DBL_MAX) strcpy(buf, " +Inf"); else if (fabs(x) <= 999999.99998) { sprintf(buf, "%13.5f", x); #if 1 if (strcmp(buf, " 0.00000") == 0 || strcmp(buf, " -0.00000") == 0) strcpy(buf, " . "); else if (memcmp(buf, " 0.", 8) == 0) memcpy(buf, " .", 8); else if (memcmp(buf, " -0.", 8) == 0) memcpy(buf, " -.", 8); #endif } else sprintf(buf, "%13.6g", x); return buf; } int glp_print_ranges(glp_prob *P, int len, const int list[], int flags, const char *fname) { /* print sensitivity analysis report */ XFILE *fp = NULL; GLPROW *row; GLPCOL *col; int m, n, pass, k, t, numb, type, stat, var1, var2, count, page, ret; double lb, ub, slack, coef, prim, dual, value1, value2, coef1, coef2, obj1, obj2; const char *name, *limit; char buf[13+1]; /* sanity checks */ if (P == NULL || P->magic != GLP_PROB_MAGIC) xerror("glp_print_ranges: P = %p; invalid problem object\n", P); m = P->m, n = P->n; if (len < 0) xerror("glp_print_ranges: len = %d; invalid list length\n", len); if (len > 0) { if (list == NULL) xerror("glp_print_ranges: list = %p: invalid parameter\n", list); for (t = 1; t <= len; t++) { k = list[t]; if (!(1 <= k && k <= m+n)) xerror("glp_print_ranges: list[%d] = %d; row/column numb" "er out of range\n", t, k); } } if (flags != 0) xerror("glp_print_ranges: flags = %d; invalid parameter\n", flags); if (fname == NULL) xerror("glp_print_ranges: fname = %p; invalid parameter\n", fname); if (glp_get_status(P) != GLP_OPT) { xprintf("glp_print_ranges: optimal basic solution required\n"); ret = 1; goto done; } if (!glp_bf_exists(P)) { xprintf("glp_print_ranges: basis factorization required\n"); ret = 2; goto done; } /* start reporting */ xprintf("Write sensitivity analysis report to `%s'...\n", fname); fp = xfopen(fname, "w"); if (fp == NULL) { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg()); ret = 3; goto done; } page = count = 0; for (pass = 1; pass <= 2; pass++) for (t = 1; t <= (len == 0 ? m+n : len); t++) { if (t == 1) count = 0; k = (len == 0 ? t : list[t]); if (pass == 1 && k > m || pass == 2 && k <= m) continue; if (count == 0) { xfprintf(fp, "GLPK %-4s - SENSITIVITY ANALYSIS REPORT%73sPa" "ge%4d\n", glp_version(), "", ++page); xfprintf(fp, "\n"); xfprintf(fp, "%-12s%s\n", "Problem:", P->name == NULL ? "" : P->name); xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:", P->obj == NULL ? "" : P->obj, P->obj == NULL ? "" : " = ", P->obj_val, P->dir == GLP_MIN ? "MINimum" : P->dir == GLP_MAX ? "MAXimum" : "???"); xfprintf(fp, "\n"); xfprintf(fp, "%6s %-12s %2s %13s %13s %13s %13s %13s %13s " "%s\n", "No.", pass == 1 ? "Row name" : "Column name", "St", "Activity", pass == 1 ? "Slack" : "Obj coef", "Lower bound", "Activity", "Obj coef", "Obj value at", "Limiting"); xfprintf(fp, "%6s %-12s %2s %13s %13s %13s %13s %13s %13s " "%s\n", "", "", "", "", "Marginal", "Upper bound", "range", "range", "break point", "variable"); xfprintf(fp, "------ ------------ -- ------------- --------" "----- ------------- ------------- ------------- ------" "------- ------------\n"); } if (pass == 1) { numb = k; xassert(1 <= numb && numb <= m); row = P->row[numb]; name = row->name; type = row->type; lb = glp_get_row_lb(P, numb); ub = glp_get_row_ub(P, numb); coef = 0.0; stat = row->stat; prim = row->prim; if (type == GLP_FR) slack = - prim; else if (type == GLP_LO) slack = lb - prim; else if (type == GLP_UP || type == GLP_DB || type == GLP_FX) slack = ub - prim; dual = row->dual; } else { numb = k - m; xassert(1 <= numb && numb <= n); col = P->col[numb]; name = col->name; lb = glp_get_col_lb(P, numb); ub = glp_get_col_ub(P, numb); coef = col->coef; stat = col->stat; prim = col->prim; slack = 0.0; dual = col->dual; } if (stat != GLP_BS) { glp_analyze_bound(P, k, &value1, &var1, &value2, &var2); if (stat == GLP_NF) coef1 = coef2 = coef; else if (stat == GLP_NS) coef1 = -DBL_MAX, coef2 = +DBL_MAX; else if (stat == GLP_NL && P->dir == GLP_MIN || stat == GLP_NU && P->dir == GLP_MAX) coef1 = coef - dual, coef2 = +DBL_MAX; else coef1 = -DBL_MAX, coef2 = coef - dual; if (value1 == -DBL_MAX) { if (dual < -1e-9) obj1 = +DBL_MAX; else if (dual > +1e-9) obj1 = -DBL_MAX; else obj1 = P->obj_val; } else obj1 = P->obj_val + dual * (value1 - prim); if (value2 == +DBL_MAX) { if (dual < -1e-9) obj2 = -DBL_MAX; else if (dual > +1e-9) obj2 = +DBL_MAX; else obj2 = P->obj_val; } else obj2 = P->obj_val + dual * (value2 - prim); } else { glp_analyze_coef(P, k, &coef1, &var1, &value1, &coef2, &var2, &value2); if (coef1 == -DBL_MAX) { if (prim < -1e-9) obj1 = +DBL_MAX; else if (prim > +1e-9) obj1 = -DBL_MAX; else obj1 = P->obj_val; } else obj1 = P->obj_val + (coef1 - coef) * prim; if (coef2 == +DBL_MAX) { if (prim < -1e-9) obj2 = -DBL_MAX; else if (prim > +1e-9) obj2 = +DBL_MAX; else obj2 = P->obj_val; } else obj2 = P->obj_val + (coef2 - coef) * prim; } /*** first line ***/ /* row/column number */ xfprintf(fp, "%6d", numb); /* row/column name */ xfprintf(fp, " %-12.12s", name == NULL ? "" : name); if (name != NULL && strlen(name) > 12) xfprintf(fp, "%s\n%6s %12s", name+12, "", ""); /* row/column status */ xfprintf(fp, " %2s", stat == GLP_BS ? "BS" : stat == GLP_NL ? "NL" : stat == GLP_NU ? "NU" : stat == GLP_NF ? "NF" : stat == GLP_NS ? "NS" : "??"); /* row/column activity */ xfprintf(fp, " %s", format(buf, prim)); /* row slack, column objective coefficient */ xfprintf(fp, " %s", format(buf, k <= m ? slack : coef)); /* row/column lower bound */ xfprintf(fp, " %s", format(buf, lb)); /* row/column activity range */ xfprintf(fp, " %s", format(buf, value1)); /* row/column objective coefficient range */ xfprintf(fp, " %s", format(buf, coef1)); /* objective value at break point */ xfprintf(fp, " %s", format(buf, obj1)); /* limiting variable name */ if (var1 != 0) { if (var1 <= m) limit = glp_get_row_name(P, var1); else limit = glp_get_col_name(P, var1 - m); if (limit != NULL) xfprintf(fp, " %s", limit); } xfprintf(fp, "\n"); /*** second line ***/ xfprintf(fp, "%6s %-12s %2s %13s", "", "", "", ""); /* row/column reduced cost */ xfprintf(fp, " %s", format(buf, dual)); /* row/column upper bound */ xfprintf(fp, " %s", format(buf, ub)); /* row/column activity range */ xfprintf(fp, " %s", format(buf, value2)); /* row/column objective coefficient range */ xfprintf(fp, " %s", format(buf, coef2)); /* objective value at break point */ xfprintf(fp, " %s", format(buf, obj2)); /* limiting variable name */ if (var2 != 0) { if (var2 <= m) limit = glp_get_row_name(P, var2); else limit = glp_get_col_name(P, var2 - m); if (limit != NULL) xfprintf(fp, " %s", limit); } xfprintf(fp, "\n"); xfprintf(fp, "\n"); /* print 10 items per page */ count = (count + 1) % 10; } xfprintf(fp, "End of report\n"); xfflush(fp); if (xferror(fp)) { xprintf("Write error on `%s' - %s\n", fname, xerrmsg()); ret = 4; goto done; } ret = 0; done: if (fp != NULL) xfclose(fp); return ret; } /**********************************************************************/ int glp_print_ipt(glp_prob *P, const char *fname) { /* write interior-point solution in printable format */ XFILE *fp; GLPROW *row; GLPCOL *col; int i, j, t, ae_ind, re_ind, ret; double ae_max, re_max; xprintf("Writing interior-point solution to `%s'...\n", fname); fp = xfopen(fname, "w"); if (fp == NULL) { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } xfprintf(fp, "%-12s%s\n", "Problem:", P->name == NULL ? "" : P->name); xfprintf(fp, "%-12s%d\n", "Rows:", P->m); xfprintf(fp, "%-12s%d\n", "Columns:", P->n); xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz); t = glp_ipt_status(P); xfprintf(fp, "%-12s%s\n", "Status:", t == GLP_OPT ? "OPTIMAL" : t == GLP_UNDEF ? "UNDEFINED" : t == GLP_INFEAS ? "INFEASIBLE (INTERMEDIATE)" : t == GLP_NOFEAS ? "INFEASIBLE (FINAL)" : "???"); xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:", P->obj == NULL ? "" : P->obj, P->obj == NULL ? "" : " = ", P->ipt_obj, P->dir == GLP_MIN ? "MINimum" : P->dir == GLP_MAX ? "MAXimum" : "???"); xfprintf(fp, "\n"); xfprintf(fp, " No. Row name Activity Lower bound " " Upper bound Marginal\n"); xfprintf(fp, "------ ------------ ------------- ------------- " "------------- -------------\n"); for (i = 1; i <= P->m; i++) { row = P->row[i]; xfprintf(fp, "%6d ", i); if (row->name == NULL || strlen(row->name) <= 12) xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name); else xfprintf(fp, "%s\n%20s", row->name, ""); xfprintf(fp, "%3s", ""); xfprintf(fp, "%13.6g ", fabs(row->pval) <= 1e-9 ? 0.0 : row->pval); if (row->type == GLP_LO || row->type == GLP_DB || row->type == GLP_FX) xfprintf(fp, "%13.6g ", row->lb); else xfprintf(fp, "%13s ", ""); if (row->type == GLP_UP || row->type == GLP_DB) xfprintf(fp, "%13.6g ", row->ub); else xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : ""); if (fabs(row->dval) <= 1e-9) xfprintf(fp, "%13s", "< eps"); else xfprintf(fp, "%13.6g ", row->dval); xfprintf(fp, "\n"); } xfprintf(fp, "\n"); xfprintf(fp, " No. Column name Activity Lower bound " " Upper bound Marginal\n"); xfprintf(fp, "------ ------------ ------------- ------------- " "------------- -------------\n"); for (j = 1; j <= P->n; j++) { col = P->col[j]; xfprintf(fp, "%6d ", j); if (col->name == NULL || strlen(col->name) <= 12) xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name); else xfprintf(fp, "%s\n%20s", col->name, ""); xfprintf(fp, "%3s", ""); xfprintf(fp, "%13.6g ", fabs(col->pval) <= 1e-9 ? 0.0 : col->pval); if (col->type == GLP_LO || col->type == GLP_DB || col->type == GLP_FX) xfprintf(fp, "%13.6g ", col->lb); else xfprintf(fp, "%13s ", ""); if (col->type == GLP_UP || col->type == GLP_DB) xfprintf(fp, "%13.6g ", col->ub); else xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : ""); if (fabs(col->dval) <= 1e-9) xfprintf(fp, "%13s", "< eps"); else xfprintf(fp, "%13.6g ", col->dval); xfprintf(fp, "\n"); } xfprintf(fp, "\n"); xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n"); xfprintf(fp, "\n"); glp_check_kkt(P, GLP_IPT, GLP_KKT_PE, &ae_max, &ae_ind, &re_max, &re_ind); xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n", ae_max, ae_ind); xfprintf(fp, " max.rel.err = %.2e on row %d\n", re_max, re_ind); xfprintf(fp, "%8s%s\n", "", re_max <= 1e-9 ? "High quality" : re_max <= 1e-6 ? "Medium quality" : re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG"); xfprintf(fp, "\n"); glp_check_kkt(P, GLP_IPT, GLP_KKT_PB, &ae_max, &ae_ind, &re_max, &re_ind); xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n", ae_max, ae_ind <= P->m ? "row" : "column", ae_ind <= P->m ? ae_ind : ae_ind - P->m); xfprintf(fp, " max.rel.err = %.2e on %s %d\n", re_max, re_ind <= P->m ? "row" : "column", re_ind <= P->m ? re_ind : re_ind - P->m); xfprintf(fp, "%8s%s\n", "", re_max <= 1e-9 ? "High quality" : re_max <= 1e-6 ? "Medium quality" : re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL" "E"); xfprintf(fp, "\n"); glp_check_kkt(P, GLP_IPT, GLP_KKT_DE, &ae_max, &ae_ind, &re_max, &re_ind); xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n", ae_max, ae_ind == 0 ? 0 : ae_ind - P->m); xfprintf(fp, " max.rel.err = %.2e on column %d\n", re_max, re_ind == 0 ? 0 : re_ind - P->m); xfprintf(fp, "%8s%s\n", "", re_max <= 1e-9 ? "High quality" : re_max <= 1e-6 ? "Medium quality" : re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG"); xfprintf(fp, "\n"); glp_check_kkt(P, GLP_IPT, GLP_KKT_DB, &ae_max, &ae_ind, &re_max, &re_ind); xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n", ae_max, ae_ind <= P->m ? "row" : "column", ae_ind <= P->m ? ae_ind : ae_ind - P->m); xfprintf(fp, " max.rel.err = %.2e on %s %d\n", re_max, re_ind <= P->m ? "row" : "column", re_ind <= P->m ? re_ind : re_ind - P->m); xfprintf(fp, "%8s%s\n", "", re_max <= 1e-9 ? "High quality" : re_max <= 1e-6 ? "Medium quality" : re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE") ; xfprintf(fp, "\n"); xfprintf(fp, "End of output\n"); xfflush(fp); if (xferror(fp)) { xprintf("Write error on `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } ret = 0; done: if (fp != NULL) xfclose(fp); return ret; } /*********************************************************************** * NAME * * glp_read_ipt - read interior-point solution from text file * * SYNOPSIS * * int glp_read_ipt(glp_prob *lp, const char *fname); * * DESCRIPTION * * The routine glp_read_ipt reads interior-point solution from a text * file whose name is specified by the parameter fname into the problem * object. * * For the file format see description of the routine glp_write_ipt. * * RETURNS * * On success the routine returns zero, otherwise non-zero. */ int glp_read_ipt(glp_prob *lp, const char *fname) { glp_data *data; jmp_buf jump; int i, j, k, ret = 0; xprintf("Reading interior-point solution from `%s'...\n", fname); data = glp_sdf_open_file(fname); if (data == NULL) { ret = 1; goto done; } if (setjmp(jump)) { ret = 1; goto done; } glp_sdf_set_jump(data, jump); /* number of rows, number of columns */ k = glp_sdf_read_int(data); if (k != lp->m) glp_sdf_error(data, "wrong number of rows\n"); k = glp_sdf_read_int(data); if (k != lp->n) glp_sdf_error(data, "wrong number of columns\n"); /* solution status, objective value */ k = glp_sdf_read_int(data); if (!(k == GLP_UNDEF || k == GLP_OPT)) glp_sdf_error(data, "invalid solution status\n"); lp->ipt_stat = k; lp->ipt_obj = glp_sdf_read_num(data); /* rows (auxiliary variables) */ for (i = 1; i <= lp->m; i++) { GLPROW *row = lp->row[i]; /* primal value, dual value */ row->pval = glp_sdf_read_num(data); row->dval = glp_sdf_read_num(data); } /* columns (structural variables) */ for (j = 1; j <= lp->n; j++) { GLPCOL *col = lp->col[j]; /* primal value, dual value */ col->pval = glp_sdf_read_num(data); col->dval = glp_sdf_read_num(data); } xprintf("%d lines were read\n", glp_sdf_line(data)); done: if (ret) lp->ipt_stat = GLP_UNDEF; if (data != NULL) glp_sdf_close_file(data); return ret; } /*********************************************************************** * NAME * * glp_write_ipt - write interior-point solution to text file * * SYNOPSIS * * int glp_write_ipt(glp_prob *lp, const char *fname); * * DESCRIPTION * * The routine glp_write_ipt writes the current interior-point solution * to a text file whose name is specified by the parameter fname. This * file can be read back with the routine glp_read_ipt. * * RETURNS * * On success the routine returns zero, otherwise non-zero. * * FILE FORMAT * * The file created by the routine glp_write_ipt is a plain text file, * which contains the following information: * * m n * stat obj_val * r_prim[1] r_dual[1] * . . . * r_prim[m] r_dual[m] * c_prim[1] c_dual[1] * . . . * c_prim[n] c_dual[n] * * where: * m is the number of rows (auxiliary variables); * n is the number of columns (structural variables); * stat is the solution status (GLP_UNDEF = 1 or GLP_OPT = 5); * obj_val is the objective value; * r_prim[i], i = 1,...,m, is the primal value of i-th row; * r_dual[i], i = 1,...,m, is the dual value of i-th row; * c_prim[j], j = 1,...,n, is the primal value of j-th column; * c_dual[j], j = 1,...,n, is the dual value of j-th column. */ int glp_write_ipt(glp_prob *lp, const char *fname) { XFILE *fp; int i, j, ret = 0; xprintf("Writing interior-point solution to `%s'...\n", fname); fp = xfopen(fname, "w"); if (fp == NULL) { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } /* number of rows, number of columns */ xfprintf(fp, "%d %d\n", lp->m, lp->n); /* solution status, objective value */ xfprintf(fp, "%d %.*g\n", lp->ipt_stat, DBL_DIG, lp->ipt_obj); /* rows (auxiliary variables) */ for (i = 1; i <= lp->m; i++) { GLPROW *row = lp->row[i]; /* primal value, dual value */ xfprintf(fp, "%.*g %.*g\n", DBL_DIG, row->pval, DBL_DIG, row->dval); } /* columns (structural variables) */ for (j = 1; j <= lp->n; j++) { GLPCOL *col = lp->col[j]; /* primal value, dual value */ xfprintf(fp, "%.*g %.*g\n", DBL_DIG, col->pval, DBL_DIG, col->dval); } xfflush(fp); if (xferror(fp)) { xprintf("Write error on `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } xprintf("%d lines were written\n", 2 + lp->m + lp->n); done: if (fp != NULL) xfclose(fp); return ret; } /**********************************************************************/ int glp_print_mip(glp_prob *P, const char *fname) { /* write MIP solution in printable format */ XFILE *fp; GLPROW *row; GLPCOL *col; int i, j, t, ae_ind, re_ind, ret; double ae_max, re_max; xprintf("Writing MIP solution to `%s'...\n", fname); fp = xfopen(fname, "w"); if (fp == NULL) { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } xfprintf(fp, "%-12s%s\n", "Problem:", P->name == NULL ? "" : P->name); xfprintf(fp, "%-12s%d\n", "Rows:", P->m); xfprintf(fp, "%-12s%d (%d integer, %d binary)\n", "Columns:", P->n, glp_get_num_int(P), glp_get_num_bin(P)); xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz); t = glp_mip_status(P); xfprintf(fp, "%-12s%s\n", "Status:", t == GLP_OPT ? "INTEGER OPTIMAL" : t == GLP_FEAS ? "INTEGER NON-OPTIMAL" : t == GLP_NOFEAS ? "INTEGER EMPTY" : t == GLP_UNDEF ? "INTEGER UNDEFINED" : "???"); xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:", P->obj == NULL ? "" : P->obj, P->obj == NULL ? "" : " = ", P->mip_obj, P->dir == GLP_MIN ? "MINimum" : P->dir == GLP_MAX ? "MAXimum" : "???"); xfprintf(fp, "\n"); xfprintf(fp, " No. Row name Activity Lower bound " " Upper bound\n"); xfprintf(fp, "------ ------------ ------------- ------------- " "-------------\n"); for (i = 1; i <= P->m; i++) { row = P->row[i]; xfprintf(fp, "%6d ", i); if (row->name == NULL || strlen(row->name) <= 12) xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name); else xfprintf(fp, "%s\n%20s", row->name, ""); xfprintf(fp, "%3s", ""); xfprintf(fp, "%13.6g ", fabs(row->mipx) <= 1e-9 ? 0.0 : row->mipx); if (row->type == GLP_LO || row->type == GLP_DB || row->type == GLP_FX) xfprintf(fp, "%13.6g ", row->lb); else xfprintf(fp, "%13s ", ""); if (row->type == GLP_UP || row->type == GLP_DB) xfprintf(fp, "%13.6g ", row->ub); else xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : ""); xfprintf(fp, "\n"); } xfprintf(fp, "\n"); xfprintf(fp, " No. Column name Activity Lower bound " " Upper bound\n"); xfprintf(fp, "------ ------------ ------------- ------------- " "-------------\n"); for (j = 1; j <= P->n; j++) { col = P->col[j]; xfprintf(fp, "%6d ", j); if (col->name == NULL || strlen(col->name) <= 12) xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name); else xfprintf(fp, "%s\n%20s", col->name, ""); xfprintf(fp, "%s ", col->kind == GLP_CV ? " " : col->kind == GLP_IV ? "*" : "?"); xfprintf(fp, "%13.6g ", fabs(col->mipx) <= 1e-9 ? 0.0 : col->mipx); if (col->type == GLP_LO || col->type == GLP_DB || col->type == GLP_FX) xfprintf(fp, "%13.6g ", col->lb); else xfprintf(fp, "%13s ", ""); if (col->type == GLP_UP || col->type == GLP_DB) xfprintf(fp, "%13.6g ", col->ub); else xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : ""); xfprintf(fp, "\n"); } xfprintf(fp, "\n"); xfprintf(fp, "Integer feasibility conditions:\n"); xfprintf(fp, "\n"); glp_check_kkt(P, GLP_MIP, GLP_KKT_PE, &ae_max, &ae_ind, &re_max, &re_ind); xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n", ae_max, ae_ind); xfprintf(fp, " max.rel.err = %.2e on row %d\n", re_max, re_ind); xfprintf(fp, "%8s%s\n", "", re_max <= 1e-9 ? "High quality" : re_max <= 1e-6 ? "Medium quality" : re_max <= 1e-3 ? "Low quality" : "SOLUTION IS WRONG"); xfprintf(fp, "\n"); glp_check_kkt(P, GLP_MIP, GLP_KKT_PB, &ae_max, &ae_ind, &re_max, &re_ind); xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n", ae_max, ae_ind <= P->m ? "row" : "column", ae_ind <= P->m ? ae_ind : ae_ind - P->m); xfprintf(fp, " max.rel.err = %.2e on %s %d\n", re_max, re_ind <= P->m ? "row" : "column", re_ind <= P->m ? re_ind : re_ind - P->m); xfprintf(fp, "%8s%s\n", "", re_max <= 1e-9 ? "High quality" : re_max <= 1e-6 ? "Medium quality" : re_max <= 1e-3 ? "Low quality" : "SOLUTION IS INFEASIBLE"); xfprintf(fp, "\n"); xfprintf(fp, "End of output\n"); xfflush(fp); if (xferror(fp)) { xprintf("Write error on `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } ret = 0; done: if (fp != NULL) xfclose(fp); return ret; } /*********************************************************************** * NAME * * glp_read_mip - read MIP solution from text file * * SYNOPSIS * * int glp_read_mip(glp_prob *mip, const char *fname); * * DESCRIPTION * * The routine glp_read_mip reads MIP solution from a text file whose * name is specified by the parameter fname into the problem object. * * For the file format see description of the routine glp_write_mip. * * RETURNS * * On success the routine returns zero, otherwise non-zero. */ int glp_read_mip(glp_prob *mip, const char *fname) { glp_data *data; jmp_buf jump; int i, j, k, ret = 0; xprintf("Reading MIP solution from `%s'...\n", fname); data = glp_sdf_open_file(fname); if (data == NULL) { ret = 1; goto done; } if (setjmp(jump)) { ret = 1; goto done; } glp_sdf_set_jump(data, jump); /* number of rows, number of columns */ k = glp_sdf_read_int(data); if (k != mip->m) glp_sdf_error(data, "wrong number of rows\n"); k = glp_sdf_read_int(data); if (k != mip->n) glp_sdf_error(data, "wrong number of columns\n"); /* solution status, objective value */ k = glp_sdf_read_int(data); if (!(k == GLP_UNDEF || k == GLP_OPT || k == GLP_FEAS || k == GLP_NOFEAS)) glp_sdf_error(data, "invalid solution status\n"); mip->mip_stat = k; mip->mip_obj = glp_sdf_read_num(data); /* rows (auxiliary variables) */ for (i = 1; i <= mip->m; i++) { GLPROW *row = mip->row[i]; row->mipx = glp_sdf_read_num(data); } /* columns (structural variables) */ for (j = 1; j <= mip->n; j++) { GLPCOL *col = mip->col[j]; col->mipx = glp_sdf_read_num(data); if (col->kind == GLP_IV && col->mipx != floor(col->mipx)) glp_sdf_error(data, "non-integer column value"); } xprintf("%d lines were read\n", glp_sdf_line(data)); done: if (ret) mip->mip_stat = GLP_UNDEF; if (data != NULL) glp_sdf_close_file(data); return ret; } /*********************************************************************** * NAME * * glp_write_mip - write MIP solution to text file * * SYNOPSIS * * int glp_write_mip(glp_prob *mip, const char *fname); * * DESCRIPTION * * The routine glp_write_mip writes the current MIP solution to a text * file whose name is specified by the parameter fname. This file can * be read back with the routine glp_read_mip. * * RETURNS * * On success the routine returns zero, otherwise non-zero. * * FILE FORMAT * * The file created by the routine glp_write_sol is a plain text file, * which contains the following information: * * m n * stat obj_val * r_val[1] * . . . * r_val[m] * c_val[1] * . . . * c_val[n] * * where: * m is the number of rows (auxiliary variables); * n is the number of columns (structural variables); * stat is the solution status (GLP_UNDEF = 1, GLP_FEAS = 2, * GLP_NOFEAS = 4, or GLP_OPT = 5); * obj_val is the objective value; * r_val[i], i = 1,...,m, is the value of i-th row; * c_val[j], j = 1,...,n, is the value of j-th column. */ int glp_write_mip(glp_prob *mip, const char *fname) { XFILE *fp; int i, j, ret = 0; xprintf("Writing MIP solution to `%s'...\n", fname); fp = xfopen(fname, "w"); if (fp == NULL) { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } /* number of rows, number of columns */ xfprintf(fp, "%d %d\n", mip->m, mip->n); /* solution status, objective value */ xfprintf(fp, "%d %.*g\n", mip->mip_stat, DBL_DIG, mip->mip_obj); /* rows (auxiliary variables) */ for (i = 1; i <= mip->m; i++) xfprintf(fp, "%.*g\n", DBL_DIG, mip->row[i]->mipx); /* columns (structural variables) */ for (j = 1; j <= mip->n; j++) xfprintf(fp, "%.*g\n", DBL_DIG, mip->col[j]->mipx); xfflush(fp); if (xferror(fp)) { xprintf("Write error on `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } xprintf("%d lines were written\n", 2 + mip->m + mip->n); done: if (fp != NULL) xfclose(fp); return ret; } /* eof */ Rglpk/src/GLPK/glpapi20.c0000644000176000001440000002302612245352174014477 0ustar ripleyusers/* glpapi20.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpnpp.h" int glp_intfeas1(glp_prob *P, int use_bound, int obj_bound) { /* solve integer feasibility problem */ NPP *npp = NULL; glp_prob *mip = NULL; int *obj_ind = NULL; double *obj_val = NULL; int obj_row = 0; int i, j, k, obj_len, temp, ret; /* check the problem object */ if (P == NULL || P->magic != GLP_PROB_MAGIC) xerror("glp_intfeas1: P = %p; invalid problem object\n", P); if (P->tree != NULL) xerror("glp_intfeas1: operation not allowed\n"); /* integer solution is currently undefined */ P->mip_stat = GLP_UNDEF; P->mip_obj = 0.0; /* check columns (variables) */ for (j = 1; j <= P->n; j++) { GLPCOL *col = P->col[j]; #if 0 /* currently binarization is not yet implemented */ if (!(col->kind == GLP_IV || col->type == GLP_FX)) { xprintf("glp_intfeas1: column %d: non-integer non-fixed var" "iable not allowed\n", j); #else if (!((col->kind == GLP_IV && col->lb == 0.0 && col->ub == 1.0) || col->type == GLP_FX)) { xprintf("glp_intfeas1: column %d: non-binary non-fixed vari" "able not allowed\n", j); #endif ret = GLP_EDATA; goto done; } temp = (int)col->lb; if ((double)temp != col->lb) { if (col->type == GLP_FX) xprintf("glp_intfeas1: column %d: fixed value %g is non-" "integer or out of range\n", j, col->lb); else xprintf("glp_intfeas1: column %d: lower bound %g is non-" "integer or out of range\n", j, col->lb); ret = GLP_EDATA; goto done; } temp = (int)col->ub; if ((double)temp != col->ub) { xprintf("glp_intfeas1: column %d: upper bound %g is non-int" "eger or out of range\n", j, col->ub); ret = GLP_EDATA; goto done; } if (col->type == GLP_DB && col->lb > col->ub) { xprintf("glp_intfeas1: column %d: lower bound %g is greater" " than upper bound %g\n", j, col->lb, col->ub); ret = GLP_EBOUND; goto done; } } /* check rows (constraints) */ for (i = 1; i <= P->m; i++) { GLPROW *row = P->row[i]; GLPAIJ *aij; for (aij = row->ptr; aij != NULL; aij = aij->r_next) { temp = (int)aij->val; if ((double)temp != aij->val) { xprintf("glp_intfeas1: row = %d, column %d: constraint c" "oefficient %g is non-integer or out of range\n", i, aij->col->j, aij->val); ret = GLP_EDATA; goto done; } } temp = (int)row->lb; if ((double)temp != row->lb) { if (row->type == GLP_FX) xprintf("glp_intfeas1: row = %d: fixed value %g is non-i" "nteger or out of range\n", i, row->lb); else xprintf("glp_intfeas1: row = %d: lower bound %g is non-i" "nteger or out of range\n", i, row->lb); ret = GLP_EDATA; goto done; } temp = (int)row->ub; if ((double)temp != row->ub) { xprintf("glp_intfeas1: row = %d: upper bound %g is non-inte" "ger or out of range\n", i, row->ub); ret = GLP_EDATA; goto done; } if (row->type == GLP_DB && row->lb > row->ub) { xprintf("glp_intfeas1: row %d: lower bound %g is greater th" "an upper bound %g\n", i, row->lb, row->ub); ret = GLP_EBOUND; goto done; } } /* check the objective function */ temp = (int)P->c0; if ((double)temp != P->c0) { xprintf("glp_intfeas1: objective constant term %g is non-integ" "er or out of range\n", P->c0); ret = GLP_EDATA; goto done; } for (j = 1; j <= P->n; j++) { temp = (int)P->col[j]->coef; if ((double)temp != P->col[j]->coef) { xprintf("glp_intfeas1: column %d: objective coefficient is " "non-integer or out of range\n", j, P->col[j]->coef); ret = GLP_EDATA; goto done; } } /* save the objective function and set it to zero */ obj_ind = xcalloc(1+P->n, sizeof(int)); obj_val = xcalloc(1+P->n, sizeof(double)); obj_len = 0; obj_ind[0] = 0; obj_val[0] = P->c0; P->c0 = 0.0; for (j = 1; j <= P->n; j++) { if (P->col[j]->coef != 0.0) { obj_len++; obj_ind[obj_len] = j; obj_val[obj_len] = P->col[j]->coef; P->col[j]->coef = 0.0; } } /* add inequality to bound the objective function, if required */ if (!use_bound) xprintf("Will search for ANY feasible solution\n"); else { xprintf("Will search only for solution not worse than %d\n", obj_bound); obj_row = glp_add_rows(P, 1); glp_set_mat_row(P, obj_row, obj_len, obj_ind, obj_val); if (P->dir == GLP_MIN) glp_set_row_bnds(P, obj_row, GLP_UP, 0.0, (double)obj_bound - obj_val[0]); else if (P->dir == GLP_MAX) glp_set_row_bnds(P, obj_row, GLP_LO, (double)obj_bound - obj_val[0], 0.0); else xassert(P != P); } /* create preprocessor workspace */ xprintf("Translating to CNF-SAT...\n"); xprintf("Original problem has %d row%s, %d column%s, and %d non-z" "ero%s\n", P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s", P->nnz, P->nnz == 1 ? "" : "s"); npp = npp_create_wksp(); /* load the original problem into the preprocessor workspace */ npp_load_prob(npp, P, GLP_OFF, GLP_MIP, GLP_OFF); /* perform translation to SAT-CNF problem instance */ ret = npp_sat_encode_prob(npp); if (ret == 0) ; else if (ret == GLP_ENOPFS) xprintf("PROBLEM HAS NO INTEGER FEASIBLE SOLUTION\n"); else if (ret == GLP_ERANGE) xprintf("glp_intfeas1: translation to SAT-CNF failed because o" "f integer overflow\n"); else xassert(ret != ret); if (ret != 0) goto done; /* build SAT-CNF problem instance and try to solve it */ mip = glp_create_prob(); npp_build_prob(npp, mip); ret = glp_minisat1(mip); /* only integer feasible solution can be postprocessed */ if (!(mip->mip_stat == GLP_OPT || mip->mip_stat == GLP_FEAS)) { P->mip_stat = mip->mip_stat; goto done; } /* postprocess the solution found */ npp_postprocess(npp, mip); /* the transformed problem is no longer needed */ glp_delete_prob(mip), mip = NULL; /* store solution to the original problem object */ npp_unload_sol(npp, P); /* change the solution status to 'integer feasible' */ P->mip_stat = GLP_FEAS; /* check integer feasibility */ for (i = 1; i <= P->m; i++) { GLPROW *row; GLPAIJ *aij; double sum; row = P->row[i]; sum = 0.0; for (aij = row->ptr; aij != NULL; aij = aij->r_next) sum += aij->val * aij->col->mipx; xassert(sum == row->mipx); if (row->type == GLP_LO || row->type == GLP_DB || row->type == GLP_FX) xassert(sum >= row->lb); if (row->type == GLP_UP || row->type == GLP_DB || row->type == GLP_FX) xassert(sum <= row->ub); } /* compute value of the original objective function */ P->mip_obj = obj_val[0]; for (k = 1; k <= obj_len; k++) P->mip_obj += obj_val[k] * P->col[obj_ind[k]]->mipx; xprintf("Objective value = %17.9e\n", P->mip_obj); done: /* delete the transformed problem, if it exists */ if (mip != NULL) glp_delete_prob(mip); /* delete the preprocessor workspace, if it exists */ if (npp != NULL) npp_delete_wksp(npp); /* remove inequality used to bound the objective function */ if (obj_row > 0) { int ind[1+1]; ind[1] = obj_row; glp_del_rows(P, 1, ind); } /* restore the original objective function */ if (obj_ind != NULL) { P->c0 = obj_val[0]; for (k = 1; k <= obj_len; k++) P->col[obj_ind[k]]->coef = obj_val[k]; xfree(obj_ind); xfree(obj_val); } return ret; } /* eof */ Rglpk/src/GLPK/glpscf.h0000644000176000001440000001076012245352174014345 0ustar ripleyusers/* glpscf.h (Schur complement factorization) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPSCF_H #define GLPSCF_H /*********************************************************************** * The structure SCF defines the following factorization of a square * nxn matrix C (which is the Schur complement): * * F * C = U * P, * * where F is a square transforming matrix, U is an upper triangular * matrix, P is a permutation matrix. * * It is assumed that matrix C is small and dense, so matrices F and U * are stored in the dense format by rows as follows: * * 1 n n_max 1 n n_max * 1 * * * * * * x x x x 1 * * * * * * x x x x * * * * * * * x x x x . * * * * * x x x x * * * * * * * x x x x . . * * * * x x x x * * * * * * * x x x x . . . * * * x x x x * * * * * * * x x x x . . . . * * x x x x * n * * * * * * x x x x n . . . . . * x x x x * x x x x x x x x x x . . . . . . x x x x * x x x x x x x x x x . . . . . . . x x x * x x x x x x x x x x . . . . . . . . x x * n_max x x x x x x x x x x n_max . . . . . . . . . x * * matrix F matrix U * * where '*' are matrix elements, 'x' are reserved locations. * * Permutation matrix P is stored in row-like format. * * Matrix C normally is not stored. * * REFERENCES * * 1. M.A.Saunders, "LUSOL: A basis package for constrained optimiza- * tion," SCCM, Stanford University, 2006. * * 2. M.A.Saunders, "Notes 5: Basis Updates," CME 318, Stanford Univer- * sity, Spring 2006. * * 3. M.A.Saunders, "Notes 6: LUSOL---a Basis Factorization Package," * ibid. */ typedef struct SCF SCF; struct SCF { /* Schur complement factorization */ int n_max; /* maximal order of matrices C, F, U, P; n_max >= 1 */ int n; /* current order of matrices C, F, U, P; n >= 0 */ double *f; /* double f[1+n_max*n_max]; */ /* matrix F stored by rows */ double *u; /* double u[1+n_max*(n_max+1)/2]; */ /* upper triangle of matrix U stored by rows */ int *p; /* int p[1+n_max]; */ /* matrix P; p[i] = j means that P[i,j] = 1 */ int t_opt; /* type of transformation used to restore triangular structure of matrix U: */ #define SCF_TBG 1 /* Bartels-Golub elimination */ #define SCF_TGR 2 /* Givens plane rotation */ int rank; /* estimated rank of matrices C and U */ double *c; /* double c[1+n_max*n_max]; */ /* matrix C stored in the same format as matrix F and used only for debugging; normally this array is not allocated */ double *w; /* double w[1+n_max]; */ /* working array */ }; /* return codes: */ #define SCF_ESING 1 /* singular matrix */ #define SCF_ELIMIT 2 /* update limit reached */ #define scf_create_it _glp_scf_create_it SCF *scf_create_it(int n_max); /* create Schur complement factorization */ #define scf_update_exp _glp_scf_update_exp int scf_update_exp(SCF *scf, const double x[], const double y[], double z); /* update factorization on expanding C */ #define scf_solve_it _glp_scf_solve_it void scf_solve_it(SCF *scf, int tr, double x[]); /* solve either system C * x = b or C' * x = b */ #define scf_reset_it _glp_scf_reset_it void scf_reset_it(SCF *scf); /* reset factorization for empty matrix C */ #define scf_delete_it _glp_scf_delete_it void scf_delete_it(SCF *scf); /* delete Schur complement factorization */ #endif /* eof */ Rglpk/src/GLPK/glphbm.c0000644000176000001440000004623012245352174014334 0ustar ripleyusers/* glphbm.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #define _GLPSTD_ERRNO #define _GLPSTD_STDIO #include "env.h" #include "glphbm.h" #include "glplib.h" /*********************************************************************** * NAME * * hbm_read_mat - read sparse matrix in Harwell-Boeing format * * SYNOPSIS * * #include "glphbm.h" * HBM *hbm_read_mat(const char *fname); * * DESCRIPTION * * The routine hbm_read_mat reads a sparse matrix in the Harwell-Boeing * format from a text file whose name is the character string fname. * * Detailed description of the Harwell-Boeing format recognised by this * routine is given in the following report: * * I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the Harwell-Boeing * Sparse Matrix Collection (Release I), TR/PA/92/86, October 1992. * * RETURNS * * If no error occured, the routine hbm_read_mat returns a pointer to * a data structure containing the matrix. In case of error the routine * prints an appropriate error message and returns NULL. */ struct dsa { /* working area used by routine hbm_read_mat */ const char *fname; /* name of input text file */ FILE *fp; /* stream assigned to input text file */ int seqn; /* card sequential number */ char card[80+1]; /* card image buffer */ int fmt_p; /* scale factor */ int fmt_k; /* iterator */ int fmt_f; /* format code */ int fmt_w; /* field width */ int fmt_d; /* number of decimal places after point */ }; /*********************************************************************** * read_card - read next data card * * This routine reads the next 80-column card from the input text file * and stores its image into the character string card. If the card was * read successfully, the routine returns zero, otherwise non-zero. */ #if 1 /* 11/III-2012 */ static int read_card(struct dsa *dsa) { int c, len = 0; char buf[255+1]; dsa->seqn++; for (;;) { c = fgetc(dsa->fp); if (c == EOF) { if (ferror(dsa->fp)) xprintf("%s:%d: read error\n", dsa->fname, dsa->seqn); else xprintf("%s:%d: unexpected end-of-file\n", dsa->fname, dsa->seqn); return 1; } else if (c == '\r') /* nop */; else if (c == '\n') break; else if (iscntrl(c)) { xprintf("%s:%d: invalid control character\n", dsa->fname, dsa->seqn, c); return 1; } else { if (len == sizeof(buf)-1) goto err; buf[len++] = (char)c; } } /* remove trailing spaces */ while (len > 80 && buf[len-1] == ' ') len--; buf[len] = '\0'; /* line should not be longer than 80 chars */ if (len > 80) err: { xerror("%s:%d: card image too long\n", dsa->fname, dsa->seqn); return 1; } /* padd by spaces to 80-column card image */ strcpy(dsa->card, buf); memset(&dsa->card[len], ' ', 80 - len); dsa->card[80] = '\0'; return 0; } #endif /*********************************************************************** * scan_int - scan integer value from the current card * * This routine scans an integer value from the current card, where fld * is the name of the field, pos is the position of the field, width is * the width of the field, val points to a location to which the scanned * value should be stored. If the value was scanned successfully, the * routine returns zero, otherwise non-zero. */ static int scan_int(struct dsa *dsa, char *fld, int pos, int width, int *val) { char str[80+1]; xassert(1 <= width && width <= 80); memcpy(str, dsa->card + pos, width), str[width] = '\0'; if (str2int(strspx(str), val)) { xprintf("%s:%d: field `%s' contains invalid value `%s'\n", dsa->fname, dsa->seqn, fld, str); return 1; } return 0; } /*********************************************************************** * parse_fmt - parse Fortran format specification * * This routine parses the Fortran format specification represented as * character string which fmt points to and stores format elements into * appropriate static locations. Should note that not all valid Fortran * format specifications may be recognised. If the format specification * was recognised, the routine returns zero, otherwise non-zero. */ static int parse_fmt(struct dsa *dsa, char *fmt) { int k, s, val; char str[80+1]; /* first character should be left parenthesis */ if (fmt[0] != '(') fail: { xprintf("hbm_read_mat: format `%s' not recognised\n", fmt); return 1; } k = 1; /* optional scale factor */ dsa->fmt_p = 0; if (isdigit((unsigned char)fmt[k])) { s = 0; while (isdigit((unsigned char)fmt[k])) { if (s == 80) goto fail; str[s++] = fmt[k++]; } str[s] = '\0'; if (str2int(str, &val)) goto fail; if (toupper((unsigned char)fmt[k]) != 'P') goto iter; dsa->fmt_p = val, k++; if (!(0 <= dsa->fmt_p && dsa->fmt_p <= 255)) goto fail; /* optional comma may follow scale factor */ if (fmt[k] == ',') k++; } /* optional iterator */ dsa->fmt_k = 1; if (isdigit((unsigned char)fmt[k])) { s = 0; while (isdigit((unsigned char)fmt[k])) { if (s == 80) goto fail; str[s++] = fmt[k++]; } str[s] = '\0'; if (str2int(str, &val)) goto fail; iter: dsa->fmt_k = val; if (!(1 <= dsa->fmt_k && dsa->fmt_k <= 255)) goto fail; } /* format code */ dsa->fmt_f = toupper((unsigned char)fmt[k++]); if (!(dsa->fmt_f == 'D' || dsa->fmt_f == 'E' || dsa->fmt_f == 'F' || dsa->fmt_f == 'G' || dsa->fmt_f == 'I')) goto fail; /* field width */ if (!isdigit((unsigned char)fmt[k])) goto fail; s = 0; while (isdigit((unsigned char)fmt[k])) { if (s == 80) goto fail; str[s++] = fmt[k++]; } str[s] = '\0'; if (str2int(str, &dsa->fmt_w)) goto fail; if (!(1 <= dsa->fmt_w && dsa->fmt_w <= 255)) goto fail; /* optional number of decimal places after point */ dsa->fmt_d = 0; if (fmt[k] == '.') { k++; if (!isdigit((unsigned char)fmt[k])) goto fail; s = 0; while (isdigit((unsigned char)fmt[k])) { if (s == 80) goto fail; str[s++] = fmt[k++]; } str[s] = '\0'; if (str2int(str, &dsa->fmt_d)) goto fail; if (!(0 <= dsa->fmt_d && dsa->fmt_d <= 255)) goto fail; } /* last character should be right parenthesis */ if (!(fmt[k] == ')' && fmt[k+1] == '\0')) goto fail; return 0; } /*********************************************************************** * read_int_array - read array of integer type * * This routine reads an integer array from the input text file, where * name is array name, fmt is Fortran format specification that controls * reading, n is number of array elements, val is array of integer type. * If the array was read successful, the routine returns zero, otherwise * non-zero. */ static int read_int_array(struct dsa *dsa, char *name, char *fmt, int n, int val[]) { int k, pos; char str[80+1]; if (parse_fmt(dsa, fmt)) return 1; if (!(dsa->fmt_f == 'I' && dsa->fmt_w <= 80 && dsa->fmt_k * dsa->fmt_w <= 80)) { xprintf( "%s:%d: can't read array `%s' - invalid format `%s'\n", dsa->fname, dsa->seqn, name, fmt); return 1; } for (k = 1, pos = INT_MAX; k <= n; k++, pos++) { if (pos >= dsa->fmt_k) { if (read_card(dsa)) return 1; pos = 0; } memcpy(str, dsa->card + dsa->fmt_w * pos, dsa->fmt_w); str[dsa->fmt_w] = '\0'; strspx(str); if (str2int(str, &val[k])) { xprintf( "%s:%d: can't read array `%s' - invalid value `%s'\n", dsa->fname, dsa->seqn, name, str); return 1; } } return 0; } /*********************************************************************** * read_real_array - read array of real type * * This routine reads a real array from the input text file, where name * is array name, fmt is Fortran format specification that controls * reading, n is number of array elements, val is array of real type. * If the array was read successful, the routine returns zero, otherwise * non-zero. */ static int read_real_array(struct dsa *dsa, char *name, char *fmt, int n, double val[]) { int k, pos; char str[80+1], *ptr; if (parse_fmt(dsa, fmt)) return 1; if (!(dsa->fmt_f != 'I' && dsa->fmt_w <= 80 && dsa->fmt_k * dsa->fmt_w <= 80)) { xprintf( "%s:%d: can't read array `%s' - invalid format `%s'\n", dsa->fname, dsa->seqn, name, fmt); return 1; } for (k = 1, pos = INT_MAX; k <= n; k++, pos++) { if (pos >= dsa->fmt_k) { if (read_card(dsa)) return 1; pos = 0; } memcpy(str, dsa->card + dsa->fmt_w * pos, dsa->fmt_w); str[dsa->fmt_w] = '\0'; strspx(str); if (strchr(str, '.') == NULL && strcmp(str, "0")) { xprintf("%s(%d): can't read array `%s' - value `%s' has no " "decimal point\n", dsa->fname, dsa->seqn, name, str); return 1; } /* sometimes lower case letters appear */ for (ptr = str; *ptr; ptr++) *ptr = (char)toupper((unsigned char)*ptr); ptr = strchr(str, 'D'); if (ptr != NULL) *ptr = 'E'; /* value may appear with decimal exponent but without letters E or D (for example, -123.456-012), so missing letter should be inserted */ ptr = strchr(str+1, '+'); if (ptr == NULL) ptr = strchr(str+1, '-'); if (ptr != NULL && *(ptr-1) != 'E') { xassert(strlen(str) < 80); memmove(ptr+1, ptr, strlen(ptr)+1); *ptr = 'E'; } if (str2num(str, &val[k])) { xprintf( "%s:%d: can't read array `%s' - invalid value `%s'\n", dsa->fname, dsa->seqn, name, str); return 1; } } return 0; } HBM *hbm_read_mat(const char *fname) { struct dsa _dsa, *dsa = &_dsa; HBM *hbm = NULL; dsa->fname = fname; xprintf("hbm_read_mat: reading matrix from `%s'...\n", dsa->fname); dsa->fp = fopen(dsa->fname, "r"); if (dsa->fp == NULL) { xprintf("hbm_read_mat: unable to open `%s' - %s\n", dsa->fname, strerror(errno)); goto fail; } dsa->seqn = 0; hbm = xmalloc(sizeof(HBM)); memset(hbm, 0, sizeof(HBM)); /* read the first heading card */ if (read_card(dsa)) goto fail; memcpy(hbm->title, dsa->card, 72), hbm->title[72] = '\0'; strtrim(hbm->title); xprintf("%s\n", hbm->title); memcpy(hbm->key, dsa->card+72, 8), hbm->key[8] = '\0'; strspx(hbm->key); xprintf("key = %s\n", hbm->key); /* read the second heading card */ if (read_card(dsa)) goto fail; if (scan_int(dsa, "totcrd", 0, 14, &hbm->totcrd)) goto fail; if (scan_int(dsa, "ptrcrd", 14, 14, &hbm->ptrcrd)) goto fail; if (scan_int(dsa, "indcrd", 28, 14, &hbm->indcrd)) goto fail; if (scan_int(dsa, "valcrd", 42, 14, &hbm->valcrd)) goto fail; if (scan_int(dsa, "rhscrd", 56, 14, &hbm->rhscrd)) goto fail; xprintf("totcrd = %d; ptrcrd = %d; indcrd = %d; valcrd = %d; rhsc" "rd = %d\n", hbm->totcrd, hbm->ptrcrd, hbm->indcrd, hbm->valcrd, hbm->rhscrd); /* read the third heading card */ if (read_card(dsa)) goto fail; memcpy(hbm->mxtype, dsa->card, 3), hbm->mxtype[3] = '\0'; if (strchr("RCP", hbm->mxtype[0]) == NULL || strchr("SUHZR", hbm->mxtype[1]) == NULL || strchr("AE", hbm->mxtype[2]) == NULL) { xprintf("%s:%d: matrix type `%s' not recognised\n", dsa->fname, dsa->seqn, hbm->mxtype); goto fail; } if (scan_int(dsa, "nrow", 14, 14, &hbm->nrow)) goto fail; if (scan_int(dsa, "ncol", 28, 14, &hbm->ncol)) goto fail; if (scan_int(dsa, "nnzero", 42, 14, &hbm->nnzero)) goto fail; if (scan_int(dsa, "neltvl", 56, 14, &hbm->neltvl)) goto fail; xprintf("mxtype = %s; nrow = %d; ncol = %d; nnzero = %d; neltvl =" " %d\n", hbm->mxtype, hbm->nrow, hbm->ncol, hbm->nnzero, hbm->neltvl); /* read the fourth heading card */ if (read_card(dsa)) goto fail; memcpy(hbm->ptrfmt, dsa->card, 16), hbm->ptrfmt[16] = '\0'; strspx(hbm->ptrfmt); memcpy(hbm->indfmt, dsa->card+16, 16), hbm->indfmt[16] = '\0'; strspx(hbm->indfmt); memcpy(hbm->valfmt, dsa->card+32, 20), hbm->valfmt[20] = '\0'; strspx(hbm->valfmt); memcpy(hbm->rhsfmt, dsa->card+52, 20), hbm->rhsfmt[20] = '\0'; strspx(hbm->rhsfmt); xprintf("ptrfmt = %s; indfmt = %s; valfmt = %s; rhsfmt = %s\n", hbm->ptrfmt, hbm->indfmt, hbm->valfmt, hbm->rhsfmt); /* read the fifth heading card (optional) */ if (hbm->rhscrd <= 0) { strcpy(hbm->rhstyp, "???"); hbm->nrhs = 0; hbm->nrhsix = 0; } else { if (read_card(dsa)) goto fail; memcpy(hbm->rhstyp, dsa->card, 3), hbm->rhstyp[3] = '\0'; if (scan_int(dsa, "nrhs", 14, 14, &hbm->nrhs)) goto fail; if (scan_int(dsa, "nrhsix", 28, 14, &hbm->nrhsix)) goto fail; xprintf("rhstyp = `%s'; nrhs = %d; nrhsix = %d\n", hbm->rhstyp, hbm->nrhs, hbm->nrhsix); } /* read matrix structure */ hbm->colptr = xcalloc(1+hbm->ncol+1, sizeof(int)); if (read_int_array(dsa, "colptr", hbm->ptrfmt, hbm->ncol+1, hbm->colptr)) goto fail; hbm->rowind = xcalloc(1+hbm->nnzero, sizeof(int)); if (read_int_array(dsa, "rowind", hbm->indfmt, hbm->nnzero, hbm->rowind)) goto fail; /* read matrix values */ if (hbm->valcrd <= 0) goto done; if (hbm->mxtype[2] == 'A') { /* assembled matrix */ hbm->values = xcalloc(1+hbm->nnzero, sizeof(double)); if (read_real_array(dsa, "values", hbm->valfmt, hbm->nnzero, hbm->values)) goto fail; } else { /* elemental (unassembled) matrix */ hbm->values = xcalloc(1+hbm->neltvl, sizeof(double)); if (read_real_array(dsa, "values", hbm->valfmt, hbm->neltvl, hbm->values)) goto fail; } /* read right-hand sides */ if (hbm->nrhs <= 0) goto done; if (hbm->rhstyp[0] == 'F') { /* dense format */ hbm->nrhsvl = hbm->nrow * hbm->nrhs; hbm->rhsval = xcalloc(1+hbm->nrhsvl, sizeof(double)); if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsvl, hbm->rhsval)) goto fail; } else if (hbm->rhstyp[0] == 'M' && hbm->mxtype[2] == 'A') { /* sparse format */ /* read pointers */ hbm->rhsptr = xcalloc(1+hbm->nrhs+1, sizeof(int)); if (read_int_array(dsa, "rhsptr", hbm->ptrfmt, hbm->nrhs+1, hbm->rhsptr)) goto fail; /* read sparsity pattern */ hbm->rhsind = xcalloc(1+hbm->nrhsix, sizeof(int)); if (read_int_array(dsa, "rhsind", hbm->indfmt, hbm->nrhsix, hbm->rhsind)) goto fail; /* read values */ hbm->rhsval = xcalloc(1+hbm->nrhsix, sizeof(double)); if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsix, hbm->rhsval)) goto fail; } else if (hbm->rhstyp[0] == 'M' && hbm->mxtype[2] == 'E') { /* elemental format */ hbm->rhsval = xcalloc(1+hbm->nrhsvl, sizeof(double)); if (read_real_array(dsa, "rhsval", hbm->rhsfmt, hbm->nrhsvl, hbm->rhsval)) goto fail; } else { xprintf("%s:%d: right-hand side type `%c' not recognised\n", dsa->fname, dsa->seqn, hbm->rhstyp[0]); goto fail; } /* read starting guesses */ if (hbm->rhstyp[1] == 'G') { hbm->nguess = hbm->nrow * hbm->nrhs; hbm->sguess = xcalloc(1+hbm->nguess, sizeof(double)); if (read_real_array(dsa, "sguess", hbm->rhsfmt, hbm->nguess, hbm->sguess)) goto fail; } /* read solution vectors */ if (hbm->rhstyp[2] == 'X') { hbm->nexact = hbm->nrow * hbm->nrhs; hbm->xexact = xcalloc(1+hbm->nexact, sizeof(double)); if (read_real_array(dsa, "xexact", hbm->rhsfmt, hbm->nexact, hbm->xexact)) goto fail; } done: /* reading has been completed */ xprintf("hbm_read_mat: %d cards were read\n", dsa->seqn); fclose(dsa->fp); return hbm; fail: /* something wrong in Danish kingdom */ if (hbm != NULL) { if (hbm->colptr != NULL) xfree(hbm->colptr); if (hbm->rowind != NULL) xfree(hbm->rowind); if (hbm->rhsptr != NULL) xfree(hbm->rhsptr); if (hbm->rhsind != NULL) xfree(hbm->rhsind); if (hbm->values != NULL) xfree(hbm->values); if (hbm->rhsval != NULL) xfree(hbm->rhsval); if (hbm->sguess != NULL) xfree(hbm->sguess); if (hbm->xexact != NULL) xfree(hbm->xexact); xfree(hbm); } if (dsa->fp != NULL) fclose(dsa->fp); return NULL; } /*********************************************************************** * NAME * * hbm_free_mat - free sparse matrix in Harwell-Boeing format * * SYNOPSIS * * #include "glphbm.h" * void hbm_free_mat(HBM *hbm); * * DESCRIPTION * * The hbm_free_mat routine frees all the memory allocated to the data * structure containing a sparse matrix in the Harwell-Boeing format. */ void hbm_free_mat(HBM *hbm) { if (hbm->colptr != NULL) xfree(hbm->colptr); if (hbm->rowind != NULL) xfree(hbm->rowind); if (hbm->rhsptr != NULL) xfree(hbm->rhsptr); if (hbm->rhsind != NULL) xfree(hbm->rhsind); if (hbm->values != NULL) xfree(hbm->values); if (hbm->rhsval != NULL) xfree(hbm->rhsval); if (hbm->sguess != NULL) xfree(hbm->sguess); if (hbm->xexact != NULL) xfree(hbm->xexact); xfree(hbm); return; } /* eof */ Rglpk/src/GLPK/glpios08.c0000644000176000001440000001043312245352174014524 0ustar ripleyusers/* glpios08.c (clique cut generator) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2008, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "cfg.h" #include "glpios.h" void *ios_clq_init(glp_tree *T) { /* initialize clique cut generator */ glp_prob *P = T->mip; CFG *G; int j, n1, n2; xprintf("Constructing conflict graph...\n"); G = cfg_build_graph(P); n1 = n2 = 0; for (j = 1; j <= P->n; j++) { if (G->pos[j]) n1 ++; if (G->neg[j]) n2++; } if (n1 == 0 && n2 == 0) { xprintf("No conflicts found\n"); cfg_delete_graph(G); G = NULL; } else xprintf("Conflict graph has %d + %d = %d vertices\n", n1, n2, G->nv); return G; } void ios_clq_gen(glp_tree *T, void *G_) { /* attempt to generate clique cut */ glp_prob *P = T->mip; int n = P->n; CFG *G = G_; int *pos = G->pos; int *neg = G->neg; int nv = G->nv; int *ref = G->ref; int j, k, v, len, *ind; double rhs, sum, *val; xassert(G->n == n); /* allocate working arrays */ ind = talloc(1+n, int); val = talloc(1+n, double); /* find maximum weight clique in conflict graph */ len = cfg_find_clique(P, G, ind, &sum); #ifdef GLP_DEBUG xprintf("len = %d; sum = %g\n", len, sum); cfg_check_clique(G, len, ind); #endif /* check if clique inequality is violated */ if (sum < 1.07) goto skip; /* expand clique to maximal one */ len = cfg_expand_clique(G, len, ind); #ifdef GLP_DEBUG xprintf("maximal clique size = %d\n", len); cfg_check_clique(G, len, ind); #endif /* construct clique cut (fixed binary variables are removed, so this cut is only locally valid) */ rhs = 1.0; for (j = 1; j <= n; j++) val[j] = 0.0; for (k = 1; k <= len; k++) { /* v is clique vertex */ v = ind[k]; xassert(1 <= v && v <= nv); /* j is number of corresponding binary variable */ j = ref[v]; xassert(1 <= j && j <= n); if (pos[j] == v) { /* v corresponds to x[j] */ if (P->col[j]->type == GLP_FX) { /* x[j] is fixed */ rhs -= P->col[j]->prim; } else { /* x[j] is not fixed */ val[j] += 1.0; } } else if (neg[j] == v) { /* v corresponds to (1 - x[j]) */ if (P->col[j]->type == GLP_FX) { /* x[j] is fixed */ rhs -= (1.0 - P->col[j]->prim); } else { /* x[j] is not fixed */ val[j] -= 1.0; rhs -= 1.0; } } else xassert(v != v); } /* convert cut inequality to sparse format */ len = 0; for (j = 1; j <= n; j++) { if (val[j] != 0.0) { len++; ind[len] = j; val[len] = val[j]; } } /* add cut inequality to local cut pool */ glp_ios_add_row(T, NULL, GLP_RF_CLQ, 0, len, ind, val, GLP_UP, rhs); skip: /* free working arrays */ tfree(ind); tfree(val); return; } void ios_clq_term(void *G_) { /* terminate clique cut generator */ CFG *G = G_; xassert(G != NULL); cfg_delete_graph(G); return; } /* eof */ Rglpk/src/GLPK/luf.c0000644000176000001440000004717512245352174013662 0ustar ripleyusers/* luf.c (sparse LU-factorization) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #include "luf.h" /*********************************************************************** * luf_check_all - check LU-factorization before k-th elimination step * * This routine checks that before performing k-th elimination step, * 1 <= k <= n+1, all components of the LU-factorization are correct. * * In case of k = n+1, i.e. after last elimination step, it is assumed * that rows of F and columns of V are *not* built yet. * * NOTE: For testing/debugging only. */ void luf_check_all(LUF *luf, int k) { int n = luf->n; SVA *sva = luf->sva; int *sv_ind = sva->ind; double *sv_val = sva->val; int fr_ref = luf->fr_ref; int *fr_len = &sva->len[fr_ref-1]; int fc_ref = luf->fc_ref; int *fc_ptr = &sva->ptr[fc_ref-1]; int *fc_len = &sva->len[fc_ref-1]; int vr_ref = luf->vr_ref; int *vr_ptr = &sva->ptr[vr_ref-1]; int *vr_len = &sva->len[vr_ref-1]; int vc_ref = luf->vc_ref; int *vc_ptr = &sva->ptr[vc_ref-1]; int *vc_len = &sva->len[vc_ref-1]; int *pp_ind = luf->pp_ind; int *pp_inv = luf->pp_inv; int *qq_ind = luf->qq_ind; int *qq_inv = luf->qq_inv; int i, ii, i_ptr, i_end, j, jj, j_ptr, j_end; xassert(n > 0); xassert(1 <= k && k <= n+1); /* check permutation matrix P */ for (i = 1; i <= n; i++) { ii = pp_ind[i]; xassert(1 <= ii && ii <= n); xassert(pp_inv[ii] == i); } /* check permutation matrix Q */ for (j = 1; j <= n; j++) { jj = qq_inv[j]; xassert(1 <= jj && jj <= n); xassert(qq_ind[jj] == j); } /* check row-wise representation of matrix F */ for (i = 1; i <= n; i++) xassert(fr_len[i] == 0); /* check column-wise representation of matrix F */ for (j = 1; j <= n; j++) { /* j-th column of F = jj-th column of L */ jj = pp_ind[j]; if (jj < k) { j_ptr = fc_ptr[j]; j_end = j_ptr + fc_len[j]; for (; j_ptr < j_end; j_ptr++) { i = sv_ind[j_ptr]; xassert(1 <= i && i <= n); ii = pp_ind[i]; /* f[i,j] = l[ii,jj] */ xassert(ii > jj); xassert(sv_val[j_ptr] != 0.0); } } else /* jj >= k */ xassert(fc_len[j] == 0); } /* check row-wise representation of matrix V */ for (i = 1; i <= n; i++) { /* i-th row of V = ii-th row of U */ ii = pp_ind[i]; i_ptr = vr_ptr[i]; i_end = i_ptr + vr_len[i]; for (; i_ptr < i_end; i_ptr++) { j = sv_ind[i_ptr]; xassert(1 <= j && j <= n); jj = qq_inv[j]; /* v[i,j] = u[ii,jj] */ if (ii < k) xassert(jj > ii); else /* ii >= k */ { xassert(jj >= k); /* find v[i,j] in j-th column */ j_ptr = vc_ptr[j]; j_end = j_ptr + vc_len[j]; for (; sv_ind[j_ptr] != i; j_ptr++) /* nop */; xassert(j_ptr < j_end); } xassert(sv_val[i_ptr] != 0.0); } } /* check column-wise representation of matrix V */ for (j = 1; j <= n; j++) { /* j-th column of V = jj-th column of U */ jj = qq_inv[j]; if (jj < k) xassert(vc_len[j] == 0); else /* jj >= k */ { j_ptr = vc_ptr[j]; j_end = j_ptr + vc_len[j]; for (; j_ptr < j_end; j_ptr++) { i = sv_ind[j_ptr]; ii = pp_ind[i]; /* v[i,j] = u[ii,jj] */ xassert(ii >= k); /* find v[i,j] in i-th row */ i_ptr = vr_ptr[i]; i_end = i_ptr + vr_len[i]; for (; sv_ind[i_ptr] != j; i_ptr++) /* nop */; xassert(i_ptr < i_end); } } } return; } /*********************************************************************** * luf_build_v_rows - build matrix V in row-wise format * * This routine builds the row-wise representation of matrix V in the * left part of SVA using its column-wise representation. * * NOTE: On entry to the routine all rows of matrix V should have zero * capacity. * * The working array len should have at least 1+n elements (len[0] is * not used). */ void luf_build_v_rows(LUF *luf, int len[/*1+n*/]) { int n = luf->n; SVA *sva = luf->sva; int *sv_ind = sva->ind; double *sv_val = sva->val; int vr_ref = luf->vr_ref; int *vr_ptr = &sva->ptr[vr_ref-1]; int *vr_len = &sva->len[vr_ref-1]; int vc_ref = luf->vc_ref; int *vc_ptr = &sva->ptr[vc_ref-1]; int *vc_len = &sva->len[vc_ref-1]; int i, j, end, nnz, ptr, ptr1; /* calculate the number of non-zeros in each row of matrix V and * the total number of non-zeros */ nnz = 0; for (i = 1; i <= n; i++) len[i] = 0; for (j = 1; j <= n; j++) { nnz += vc_len[j]; for (end = (ptr = vc_ptr[j]) + vc_len[j]; ptr < end; ptr++) len[sv_ind[ptr]]++; } /* we need at least nnz free locations in SVA */ if (sva->r_ptr - sva->m_ptr < nnz) { sva_more_space(sva, nnz); sv_ind = sva->ind; sv_val = sva->val; } /* reserve locations for rows of matrix V */ for (i = 1; i <= n; i++) { if (len[i] > 0) sva_enlarge_cap(sva, vr_ref-1+i, len[i], 0); vr_len[i] = len[i]; } /* walk thru column of matrix V and build its rows */ for (j = 1; j <= n; j++) { for (end = (ptr = vc_ptr[j]) + vc_len[j]; ptr < end; ptr++) { i = sv_ind[ptr]; sv_ind[ptr1 = vr_ptr[i] + (--len[i])] = j; sv_val[ptr1] = sv_val[ptr]; } } return; } /*********************************************************************** * luf_build_f_rows - build matrix F in row-wise format * * This routine builds the row-wise representation of matrix F in the * right part of SVA using its column-wise representation. * * NOTE: On entry to the routine all rows of matrix F should have zero * capacity. * * The working array len should have at least 1+n elements (len[0] is * not used). */ void luf_build_f_rows(LUF *luf, int len[/*1+n*/]) { int n = luf->n; SVA *sva = luf->sva; int *sv_ind = sva->ind; double *sv_val = sva->val; int fr_ref = luf->fr_ref; int *fr_ptr = &sva->ptr[fr_ref-1]; int *fr_len = &sva->len[fr_ref-1]; int fc_ref = luf->fc_ref; int *fc_ptr = &sva->ptr[fc_ref-1]; int *fc_len = &sva->len[fc_ref-1]; int i, j, end, nnz, ptr, ptr1; /* calculate the number of non-zeros in each row of matrix F and * the total number of non-zeros (except diagonal elements) */ nnz = 0; for (i = 1; i <= n; i++) len[i] = 0; for (j = 1; j <= n; j++) { nnz += fc_len[j]; for (end = (ptr = fc_ptr[j]) + fc_len[j]; ptr < end; ptr++) len[sv_ind[ptr]]++; } /* we need at least nnz free locations in SVA */ if (sva->r_ptr - sva->m_ptr < nnz) { sva_more_space(sva, nnz); sv_ind = sva->ind; sv_val = sva->val; } /* reserve locations for rows of matrix F */ for (i = 1; i <= n; i++) { if (len[i] > 0) sva_reserve_cap(sva, fr_ref-1+i, len[i]); fr_len[i] = len[i]; } /* walk through columns of matrix F and build its rows */ for (j = 1; j <= n; j++) { for (end = (ptr = fc_ptr[j]) + fc_len[j]; ptr < end; ptr++) { i = sv_ind[ptr]; sv_ind[ptr1 = fr_ptr[i] + (--len[i])] = j; sv_val[ptr1] = sv_val[ptr]; } } return; } /*********************************************************************** * luf_build_v_cols - build matrix V in column-wise format * * This routine builds the column-wise representation of matrix V in * the left (if the flag updat is set) or right (if the flag updat is * clear) part of SVA using its row-wise representation. * * NOTE: On entry to the routine all columns of matrix V should have * zero capacity. * * The working array len should have at least 1+n elements (len[0] is * not used). */ void luf_build_v_cols(LUF *luf, int updat, int len[/*1+n*/]) { int n = luf->n; SVA *sva = luf->sva; int *sv_ind = sva->ind; double *sv_val = sva->val; int vr_ref = luf->vr_ref; int *vr_ptr = &sva->ptr[vr_ref-1]; int *vr_len = &sva->len[vr_ref-1]; int vc_ref = luf->vc_ref; int *vc_ptr = &sva->ptr[vc_ref-1]; int *vc_len = &sva->len[vc_ref-1]; int i, j, end, nnz, ptr, ptr1; /* calculate the number of non-zeros in each column of matrix V * and the total number of non-zeros (except pivot elements) */ nnz = 0; for (j = 1; j <= n; j++) len[j] = 0; for (i = 1; i <= n; i++) { nnz += vr_len[i]; for (end = (ptr = vr_ptr[i]) + vr_len[i]; ptr < end; ptr++) len[sv_ind[ptr]]++; } /* we need at least nnz free locations in SVA */ if (sva->r_ptr - sva->m_ptr < nnz) { sva_more_space(sva, nnz); sv_ind = sva->ind; sv_val = sva->val; } /* reserve locations for columns of matrix V */ for (j = 1; j <= n; j++) { if (len[j] > 0) { if (updat) sva_enlarge_cap(sva, vc_ref-1+j, len[j], 0); else sva_reserve_cap(sva, vc_ref-1+j, len[j]); } vc_len[j] = len[j]; } /* walk through rows of matrix V and build its columns */ for (i = 1; i <= n; i++) { for (end = (ptr = vr_ptr[i]) + vr_len[i]; ptr < end; ptr++) { j = sv_ind[ptr]; sv_ind[ptr1 = vc_ptr[j] + (--len[j])] = i; sv_val[ptr1] = sv_val[ptr]; } } return; } /*********************************************************************** * luf_check_f_rc - check rows and columns of matrix F * * This routine checks that the row- and column-wise representations * of matrix F are identical. * * NOTE: For testing/debugging only. */ void luf_check_f_rc(LUF *luf) { int n = luf->n; SVA *sva = luf->sva; int *sv_ind = sva->ind; double *sv_val = sva->val; int fr_ref = luf->fr_ref; int *fr_ptr = &sva->ptr[fr_ref-1]; int *fr_len = &sva->len[fr_ref-1]; int fc_ref = luf->fc_ref; int *fc_ptr = &sva->ptr[fc_ref-1]; int *fc_len = &sva->len[fc_ref-1]; int i, i_end, i_ptr, j, j_end, j_ptr; /* walk thru rows of matrix F */ for (i = 1; i <= n; i++) { for (i_end = (i_ptr = fr_ptr[i]) + fr_len[i]; i_ptr < i_end; i_ptr++) { j = sv_ind[i_ptr]; /* find element f[i,j] in j-th column of matrix F */ for (j_end = (j_ptr = fc_ptr[j]) + fc_len[j]; sv_ind[j_ptr] != i; j_ptr++) /* nop */; xassert(j_ptr < j_end); xassert(sv_val[i_ptr] == sv_val[j_ptr]); /* mark element f[i,j] */ sv_ind[j_ptr] = -i; } } /* walk thru column of matix F and check that all elements has been marked */ for (j = 1; j <= n; j++) { for (j_end = (j_ptr = fc_ptr[j]) + fc_len[j]; j_ptr < j_end; j_ptr++) { xassert((i = sv_ind[j_ptr]) < 0); /* unmark element f[i,j] */ sv_ind[j_ptr] = -i; } } return; } /*********************************************************************** * luf_check_v_rc - check rows and columns of matrix V * * This routine checks that the row- and column-wise representations * of matrix V are identical. * * NOTE: For testing/debugging only. */ void luf_check_v_rc(LUF *luf) { int n = luf->n; SVA *sva = luf->sva; int *sv_ind = sva->ind; double *sv_val = sva->val; int vr_ref = luf->vr_ref; int *vr_ptr = &sva->ptr[vr_ref-1]; int *vr_len = &sva->len[vr_ref-1]; int vc_ref = luf->vc_ref; int *vc_ptr = &sva->ptr[vc_ref-1]; int *vc_len = &sva->len[vc_ref-1]; int i, i_end, i_ptr, j, j_end, j_ptr; /* walk thru rows of matrix V */ for (i = 1; i <= n; i++) { for (i_end = (i_ptr = vr_ptr[i]) + vr_len[i]; i_ptr < i_end; i_ptr++) { j = sv_ind[i_ptr]; /* find element v[i,j] in j-th column of matrix V */ for (j_end = (j_ptr = vc_ptr[j]) + vc_len[j]; sv_ind[j_ptr] != i; j_ptr++) /* nop */; xassert(j_ptr < j_end); xassert(sv_val[i_ptr] == sv_val[j_ptr]); /* mark element v[i,j] */ sv_ind[j_ptr] = -i; } } /* walk thru column of matix V and check that all elements has been marked */ for (j = 1; j <= n; j++) { for (j_end = (j_ptr = vc_ptr[j]) + vc_len[j]; j_ptr < j_end; j_ptr++) { xassert((i = sv_ind[j_ptr]) < 0); /* unmark element v[i,j] */ sv_ind[j_ptr] = -i; } } return; } /*********************************************************************** * luf_f_solve - solve system F * x = b * * This routine solves the system F * x = b, where the matrix F is the * left factor of the sparse LU-factorization. * * On entry the array x should contain elements of the right-hand side * vector b in locations x[1], ..., x[n], where n is the order of the * matrix F. On exit this array will contain elements of the solution * vector x in the same locations. */ void luf_f_solve(LUF *luf, double x[/*1+n*/]) { int n = luf->n; SVA *sva = luf->sva; int *sv_ind = sva->ind; double *sv_val = sva->val; int fc_ref = luf->fc_ref; int *fc_ptr = &sva->ptr[fc_ref-1]; int *fc_len = &sva->len[fc_ref-1]; int *pp_inv = luf->pp_inv; int j, k, ptr, end; double x_j; for (k = 1; k <= n; k++) { /* k-th column of L = j-th column of F */ j = pp_inv[k]; /* x[j] is already computed */ /* walk thru j-th column of matrix F and substitute x[j] into * other equations */ if ((x_j = x[j]) != 0.0) { for (end = (ptr = fc_ptr[j]) + fc_len[j]; ptr < end; ptr++) x[sv_ind[ptr]] -= sv_val[ptr] * x_j; } } return; } /*********************************************************************** * luf_ft_solve - solve system F' * x = b * * This routine solves the system F' * x = b, where F' is a matrix * transposed to the matrix F, which is the left factor of the sparse * LU-factorization. * * On entry the array x should contain elements of the right-hand side * vector b in locations x[1], ..., x[n], where n is the order of the * matrix F. On exit this array will contain elements of the solution * vector x in the same locations. */ void luf_ft_solve(LUF *luf, double x[/*1+n*/]) { int n = luf->n; SVA *sva = luf->sva; int *sv_ind = sva->ind; double *sv_val = sva->val; int fr_ref = luf->fr_ref; int *fr_ptr = &sva->ptr[fr_ref-1]; int *fr_len = &sva->len[fr_ref-1]; int *pp_inv = luf->pp_inv; int i, k, ptr, end; double x_i; for (k = n; k >= 1; k--) { /* k-th column of L' = i-th row of F */ i = pp_inv[k]; /* x[i] is already computed */ /* walk thru i-th row of matrix F and substitute x[i] into * other equations */ if ((x_i = x[i]) != 0.0) { for (end = (ptr = fr_ptr[i]) + fr_len[i]; ptr < end; ptr++) x[sv_ind[ptr]] -= sv_val[ptr] * x_i; } } return; } /*********************************************************************** * luf_v_solve - solve system V * x = b * * This routine solves the system V * x = b, where the matrix V is the * right factor of the sparse LU-factorization. * * On entry the array b should contain elements of the right-hand side * vector b in locations b[1], ..., b[n], where n is the order of the * matrix V. On exit the array x will contain elements of the solution * vector x in locations x[1], ..., x[n]. Note that the array b will be * clobbered on exit. */ void luf_v_solve(LUF *luf, double b[/*1+n*/], double x[/*1+n*/]) { int n = luf->n; SVA *sva = luf->sva; int *sv_ind = sva->ind; double *sv_val = sva->val; double *vr_piv = luf->vr_piv; int vc_ref = luf->vc_ref; int *vc_ptr = &sva->ptr[vc_ref-1]; int *vc_len = &sva->len[vc_ref-1]; int *pp_inv = luf->pp_inv; int *qq_ind = luf->qq_ind; int i, j, k, ptr, end; double x_j; for (k = n; k >= 1; k--) { /* k-th row of U = i-th row of V */ /* k-th column of U = j-th column of V */ i = pp_inv[k]; j = qq_ind[k]; /* compute x[j] = b[i] / u[k,k], where u[k,k] = v[i,j]; * walk through j-th column of matrix V and substitute x[j] * into other equations */ if ((x_j = x[j] = b[i] / vr_piv[i]) != 0.0) { for (end = (ptr = vc_ptr[j]) + vc_len[j]; ptr < end; ptr++) b[sv_ind[ptr]] -= sv_val[ptr] * x_j; } } return; } /*********************************************************************** * luf_vt_solve - solve system V' * x = b * * This routine solves the system V' * x = b, where V' is a matrix * transposed to the matrix V, which is the right factor of the sparse * LU-factorization. * * On entry the array b should contain elements of the right-hand side * vector b in locations b[1], ..., b[n], where n is the order of the * matrix V. On exit the array x will contain elements of the solution * vector x in locations x[1], ..., x[n]. Note that the array b will be * clobbered on exit. */ void luf_vt_solve(LUF *luf, double b[/*1+n*/], double x[/*1+n*/]) { int n = luf->n; SVA *sva = luf->sva; int *sv_ind = sva->ind; double *sv_val = sva->val; double *vr_piv = luf->vr_piv; int vr_ref = luf->vr_ref; int *vr_ptr = &sva->ptr[vr_ref-1]; int *vr_len = &sva->len[vr_ref-1]; int *pp_inv = luf->pp_inv; int *qq_ind = luf->qq_ind; int i, j, k, ptr, end; double x_i; for (k = 1; k <= n; k++) { /* k-th row of U' = j-th column of V */ /* k-th column of U' = i-th row of V */ i = pp_inv[k]; j = qq_ind[k]; /* compute x[i] = b[j] / u'[k,k], where u'[k,k] = v[i,j]; * walk through i-th row of matrix V and substitute x[i] into * other equations */ if ((x_i = x[i] = b[j] / vr_piv[i]) != 0.0) { for (end = (ptr = vr_ptr[i]) + vr_len[i]; ptr < end; ptr++) b[sv_ind[ptr]] -= sv_val[ptr] * x_i; } } return; } /* eof */ Rglpk/src/GLPK/ffalg.c0000644000176000001440000001643312245352174014144 0ustar ripleyusers/* ffalg.c (Ford-Fulkerson algorithm) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2009, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #include "ffalg.h" /*********************************************************************** * NAME * * ffalg - Ford-Fulkerson algorithm * * SYNOPSIS * * #include "ffalg.h" * void ffalg(int nv, int na, const int tail[], const int head[], * int s, int t, const int cap[], int x[], char cut[]); * * DESCRIPTION * * The routine ffalg implements the Ford-Fulkerson algorithm to find a * maximal flow in the specified flow network. * * INPUT PARAMETERS * * nv is the number of nodes, nv >= 2. * * na is the number of arcs, na >= 0. * * tail[a], a = 1,...,na, is the index of tail node of arc a. * * head[a], a = 1,...,na, is the index of head node of arc a. * * s is the source node index, 1 <= s <= nv. * * t is the sink node index, 1 <= t <= nv, t != s. * * cap[a], a = 1,...,na, is the capacity of arc a, cap[a] >= 0. * * NOTE: Multiple arcs are allowed, but self-loops are not allowed. * * OUTPUT PARAMETERS * * x[a], a = 1,...,na, is optimal value of the flow through arc a. * * cut[i], i = 1,...,nv, is 1 if node i is labelled, and 0 otherwise. * The set of arcs, whose one endpoint is labelled and other is not, * defines the minimal cut corresponding to the maximal flow found. * If the parameter cut is NULL, the cut information are not stored. * * REFERENCES * * L.R.Ford, Jr., and D.R.Fulkerson, "Flows in Networks," The RAND * Corp., Report R-375-PR (August 1962), Chap. I "Static Maximal Flow," * pp.30-33. */ void ffalg(int nv, int na, const int tail[], const int head[], int s, int t, const int cap[], int x[], char cut[]) { int a, delta, i, j, k, pos1, pos2, temp, *ptr, *arc, *link, *list; /* sanity checks */ xassert(nv >= 2); xassert(na >= 0); xassert(1 <= s && s <= nv); xassert(1 <= t && t <= nv); xassert(s != t); for (a = 1; a <= na; a++) { i = tail[a], j = head[a]; xassert(1 <= i && i <= nv); xassert(1 <= j && j <= nv); xassert(i != j); xassert(cap[a] >= 0); } /* allocate working arrays */ ptr = xcalloc(1+nv+1, sizeof(int)); arc = xcalloc(1+na+na, sizeof(int)); link = xcalloc(1+nv, sizeof(int)); list = xcalloc(1+nv, sizeof(int)); /* ptr[i] := (degree of node i) */ for (i = 1; i <= nv; i++) ptr[i] = 0; for (a = 1; a <= na; a++) { ptr[tail[a]]++; ptr[head[a]]++; } /* initialize arc pointers */ ptr[1]++; for (i = 1; i < nv; i++) ptr[i+1] += ptr[i]; ptr[nv+1] = ptr[nv]; /* build arc lists */ for (a = 1; a <= na; a++) { arc[--ptr[tail[a]]] = a; arc[--ptr[head[a]]] = a; } xassert(ptr[1] == 1); xassert(ptr[nv+1] == na+na+1); /* now the indices of arcs incident to node i are stored in * locations arc[ptr[i]], arc[ptr[i]+1], ..., arc[ptr[i+1]-1] */ /* initialize arc flows */ for (a = 1; a <= na; a++) x[a] = 0; loop: /* main loop starts here */ /* build augmenting tree rooted at s */ /* link[i] = 0 means that node i is not labelled yet; * link[i] = a means that arc a immediately precedes node i */ /* initially node s is labelled as the root */ for (i = 1; i <= nv; i++) link[i] = 0; link[s] = -1, list[1] = s, pos1 = pos2 = 1; /* breadth first search */ while (pos1 <= pos2) { /* dequeue node i */ i = list[pos1++]; /* consider all arcs incident to node i */ for (k = ptr[i]; k < ptr[i+1]; k++) { a = arc[k]; if (tail[a] == i) { /* a = i->j is a forward arc from s to t */ j = head[a]; /* if node j has been labelled, skip the arc */ if (link[j] != 0) continue; /* if the arc does not allow increasing the flow through * it, skip the arc */ if (x[a] == cap[a]) continue; } else if (head[a] == i) { /* a = i<-j is a backward arc from s to t */ j = tail[a]; /* if node j has been labelled, skip the arc */ if (link[j] != 0) continue; /* if the arc does not allow decreasing the flow through * it, skip the arc */ if (x[a] == 0) continue; } else xassert(a != a); /* label node j and enqueue it */ link[j] = a, list[++pos2] = j; /* check for breakthrough */ if (j == t) goto brkt; } } /* NONBREAKTHROUGH */ /* no augmenting path exists; current flow is maximal */ /* store minimal cut information, if necessary */ if (cut != NULL) { for (i = 1; i <= nv; i++) cut[i] = (char)(link[i] != 0); } goto done; brkt: /* BREAKTHROUGH */ /* walk through arcs of the augmenting path (s, ..., t) found in * the reverse order and determine maximal change of the flow */ delta = 0; for (j = t; j != s; j = i) { /* arc a immediately precedes node j in the path */ a = link[j]; if (head[a] == j) { /* a = i->j is a forward arc of the cycle */ i = tail[a]; /* x[a] may be increased until its upper bound */ temp = cap[a] - x[a]; } else if (tail[a] == j) { /* a = i<-j is a backward arc of the cycle */ i = head[a]; /* x[a] may be decreased until its lower bound */ temp = x[a]; } else xassert(a != a); if (delta == 0 || delta > temp) delta = temp; } xassert(delta > 0); /* increase the flow along the path */ for (j = t; j != s; j = i) { /* arc a immediately precedes node j in the path */ a = link[j]; if (head[a] == j) { /* a = i->j is a forward arc of the cycle */ i = tail[a]; x[a] += delta; } else if (tail[a] == j) { /* a = i<-j is a backward arc of the cycle */ i = head[a]; x[a] -= delta; } else xassert(a != a); } goto loop; done: /* free working arrays */ xfree(ptr); xfree(arc); xfree(link); xfree(list); return; } /* eof */ Rglpk/src/GLPK/glplux.h0000644000176000001440000002123312245352174014377 0ustar ripleyusers/* glplux.h (LU-factorization, bignum arithmetic) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPLUX_H #define GLPLUX_H #include "dmp.h" #include "glpgmp.h" /*---------------------------------------------------------------------- // The structure LUX defines LU-factorization of a square matrix A, // which is the following quartet: // // [A] = (F, V, P, Q), (1) // // where F and V are such matrices that // // A = F * V, (2) // // and P and Q are such permutation matrices that the matrix // // L = P * F * inv(P) (3) // // is lower triangular with unity diagonal, and the matrix // // U = P * V * Q (4) // // is upper triangular. All the matrices have the order n. // // The matrices F and V are stored in row/column-wise sparse format as // row and column linked lists of non-zero elements. Unity elements on // the main diagonal of the matrix F are not stored. Pivot elements of // the matrix V (that correspond to diagonal elements of the matrix U) // are also missing from the row and column lists and stored separately // in an ordinary array. // // The permutation matrices P and Q are stored as ordinary arrays using // both row- and column-like formats. // // The matrices L and U being completely defined by the matrices F, V, // P, and Q are not stored explicitly. // // It is easy to show that the factorization (1)-(3) is some version of // LU-factorization. Indeed, from (3) and (4) it follows that: // // F = inv(P) * L * P, // // V = inv(P) * U * inv(Q), // // and substitution into (2) gives: // // A = F * V = inv(P) * L * U * inv(Q). // // For more details see the program documentation. */ typedef struct LUX LUX; typedef struct LUXELM LUXELM; typedef struct LUXWKA LUXWKA; struct LUX { /* LU-factorization of a square matrix */ int n; /* the order of matrices A, F, V, P, Q */ DMP *pool; /* memory pool for elements of matrices F and V */ LUXELM **F_row; /* LUXELM *F_row[1+n]; */ /* F_row[0] is not used; F_row[i], 1 <= i <= n, is a pointer to the list of elements in i-th row of matrix F (diagonal elements are not stored) */ LUXELM **F_col; /* LUXELM *F_col[1+n]; */ /* F_col[0] is not used; F_col[j], 1 <= j <= n, is a pointer to the list of elements in j-th column of matrix F (diagonal elements are not stored) */ mpq_t *V_piv; /* mpq_t V_piv[1+n]; */ /* V_piv[0] is not used; V_piv[p], 1 <= p <= n, is a pivot element v[p,q] corresponding to a diagonal element u[k,k] of matrix U = P*V*Q (used on k-th elimination step, k = 1, 2, ..., n) */ LUXELM **V_row; /* LUXELM *V_row[1+n]; */ /* V_row[0] is not used; V_row[i], 1 <= i <= n, is a pointer to the list of elements in i-th row of matrix V (except pivot elements) */ LUXELM **V_col; /* LUXELM *V_col[1+n]; */ /* V_col[0] is not used; V_col[j], 1 <= j <= n, is a pointer to the list of elements in j-th column of matrix V (except pivot elements) */ int *P_row; /* int P_row[1+n]; */ /* P_row[0] is not used; P_row[i] = j means that p[i,j] = 1, where p[i,j] is an element of permutation matrix P */ int *P_col; /* int P_col[1+n]; */ /* P_col[0] is not used; P_col[j] = i means that p[i,j] = 1, where p[i,j] is an element of permutation matrix P */ /* if i-th row or column of matrix F is i'-th row or column of matrix L = P*F*inv(P), or if i-th row of matrix V is i'-th row of matrix U = P*V*Q, then P_row[i'] = i and P_col[i] = i' */ int *Q_row; /* int Q_row[1+n]; */ /* Q_row[0] is not used; Q_row[i] = j means that q[i,j] = 1, where q[i,j] is an element of permutation matrix Q */ int *Q_col; /* int Q_col[1+n]; */ /* Q_col[0] is not used; Q_col[j] = i means that q[i,j] = 1, where q[i,j] is an element of permutation matrix Q */ /* if j-th column of matrix V is j'-th column of matrix U = P*V*Q, then Q_row[j] = j' and Q_col[j'] = j */ int rank; /* the (exact) rank of matrices A and V */ }; struct LUXELM { /* element of matrix F or V */ int i; /* row index, 1 <= i <= m */ int j; /* column index, 1 <= j <= n */ mpq_t val; /* numeric (non-zero) element value */ LUXELM *r_prev; /* pointer to previous element in the same row */ LUXELM *r_next; /* pointer to next element in the same row */ LUXELM *c_prev; /* pointer to previous element in the same column */ LUXELM *c_next; /* pointer to next element in the same column */ }; struct LUXWKA { /* working area (used only during factorization) */ /* in order to efficiently implement Markowitz strategy and Duff search technique there are two families {R[0], R[1], ..., R[n]} and {C[0], C[1], ..., C[n]}; member R[k] is a set of active rows of matrix V having k non-zeros, and member C[k] is a set of active columns of matrix V having k non-zeros (in the active submatrix); each set R[k] and C[k] is implemented as a separate doubly linked list */ int *R_len; /* int R_len[1+n]; */ /* R_len[0] is not used; R_len[i], 1 <= i <= n, is the number of non-zero elements in i-th row of matrix V (that is the length of i-th row) */ int *R_head; /* int R_head[1+n]; */ /* R_head[k], 0 <= k <= n, is the number of a first row, which is active and whose length is k */ int *R_prev; /* int R_prev[1+n]; */ /* R_prev[0] is not used; R_prev[i], 1 <= i <= n, is the number of a previous row, which is active and has the same length as i-th row */ int *R_next; /* int R_next[1+n]; */ /* R_prev[0] is not used; R_prev[i], 1 <= i <= n, is the number of a next row, which is active and has the same length as i-th row */ int *C_len; /* int C_len[1+n]; */ /* C_len[0] is not used; C_len[j], 1 <= j <= n, is the number of non-zero elements in j-th column of the active submatrix of matrix V (that is the length of j-th column in the active submatrix) */ int *C_head; /* int C_head[1+n]; */ /* C_head[k], 0 <= k <= n, is the number of a first column, which is active and whose length is k */ int *C_prev; /* int C_prev[1+n]; */ /* C_prev[0] is not used; C_prev[j], 1 <= j <= n, is the number of a previous column, which is active and has the same length as j-th column */ int *C_next; /* int C_next[1+n]; */ /* C_next[0] is not used; C_next[j], 1 <= j <= n, is the number of a next column, which is active and has the same length as j-th column */ }; #define lux_create _glp_lux_create #define lux_decomp _glp_lux_decomp #define lux_f_solve _glp_lux_f_solve #define lux_v_solve _glp_lux_v_solve #define lux_solve _glp_lux_solve #define lux_delete _glp_lux_delete LUX *lux_create(int n); /* create LU-factorization */ int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[], mpq_t val[]), void *info); /* compute LU-factorization */ void lux_f_solve(LUX *lux, int tr, mpq_t x[]); /* solve system F*x = b or F'*x = b */ void lux_v_solve(LUX *lux, int tr, mpq_t x[]); /* solve system V*x = b or V'*x = b */ void lux_solve(LUX *lux, int tr, mpq_t x[]); /* solve system A*x = b or A'*x = b */ void lux_delete(LUX *lux); /* delete LU-factorization */ #endif /* eof */ Rglpk/src/GLPK/Makefile.in0000644000176000001440000051530212175147600014763 0ustar ripleyusers# Makefile.in generated by automake 1.12.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src DIST_COMMON = $(include_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" LTLIBRARIES = $(lib_LTLIBRARIES) libglpk_la_LIBADD = am_libglpk_la_OBJECTS = libglpk_la-glpapi01.lo libglpk_la-glpapi02.lo \ libglpk_la-glpapi03.lo libglpk_la-glpapi04.lo \ libglpk_la-glpapi05.lo libglpk_la-glpapi06.lo \ libglpk_la-glpapi07.lo libglpk_la-glpapi08.lo \ libglpk_la-glpapi09.lo libglpk_la-glpapi10.lo \ libglpk_la-glpapi11.lo libglpk_la-glpapi12.lo \ libglpk_la-glpapi13.lo libglpk_la-glpapi14.lo \ libglpk_la-glpapi15.lo libglpk_la-glpapi16.lo \ libglpk_la-glpapi17.lo libglpk_la-glpapi18.lo \ libglpk_la-glpapi19.lo libglpk_la-glpapi20.lo \ libglpk_la-glpapi21.lo libglpk_la-glpavl.lo \ libglpk_la-glpbfd.lo libglpk_la-glpbfx.lo libglpk_la-glpcpx.lo \ libglpk_la-glpdmx.lo libglpk_la-glpenv07.lo \ libglpk_la-glpenv08.lo libglpk_la-glpgmp.lo \ libglpk_la-glphbm.lo libglpk_la-glpini01.lo \ libglpk_la-glpini02.lo libglpk_la-glpios01.lo \ libglpk_la-glpios02.lo libglpk_la-glpios03.lo \ libglpk_la-glpios04.lo libglpk_la-glpios05.lo \ libglpk_la-glpios06.lo libglpk_la-glpios07.lo \ libglpk_la-glpios08.lo libglpk_la-glpios09.lo \ libglpk_la-glpios10.lo libglpk_la-glpios11.lo \ libglpk_la-glpios12.lo libglpk_la-glpipm.lo \ libglpk_la-glplib03.lo libglpk_la-glplpf.lo \ libglpk_la-glplpx01.lo libglpk_la-glplpx02.lo \ libglpk_la-glplpx03.lo libglpk_la-glplux.lo \ libglpk_la-glpmat.lo libglpk_la-glpmpl01.lo \ libglpk_la-glpmpl02.lo libglpk_la-glpmpl03.lo \ libglpk_la-glpmpl04.lo libglpk_la-glpmpl05.lo \ libglpk_la-glpmpl06.lo libglpk_la-glpmps.lo \ libglpk_la-glpnet03.lo libglpk_la-glpnet04.lo \ libglpk_la-glpnet05.lo libglpk_la-glpnpp01.lo \ libglpk_la-glpnpp02.lo libglpk_la-glpnpp03.lo \ libglpk_la-glpnpp04.lo libglpk_la-glpnpp05.lo \ libglpk_la-glpnpp06.lo libglpk_la-glprgr.lo \ libglpk_la-glpscf.lo libglpk_la-glpscl.lo libglpk_la-glpsdf.lo \ libglpk_la-glpspm.lo libglpk_la-glpspx01.lo \ libglpk_la-glpspx02.lo libglpk_la-glpsql.lo \ libglpk_la-glpssx01.lo libglpk_la-glpssx02.lo \ libglpk_la-glptsp.lo libglpk_la-amd_1.lo libglpk_la-amd_2.lo \ libglpk_la-amd_aat.lo libglpk_la-amd_control.lo \ libglpk_la-amd_defaults.lo libglpk_la-amd_dump.lo \ libglpk_la-amd_info.lo libglpk_la-amd_order.lo \ libglpk_la-amd_post_tree.lo libglpk_la-amd_postorder.lo \ libglpk_la-amd_preprocess.lo libglpk_la-amd_valid.lo \ libglpk_la-fhv.lo libglpk_la-fhvint.lo libglpk_la-luf.lo \ libglpk_la-lufint.lo libglpk_la-sgf.lo libglpk_la-sva.lo \ libglpk_la-cfg.lo libglpk_la-cfg1.lo libglpk_la-colamd.lo \ libglpk_la-alloc.lo libglpk_la-env.lo libglpk_la-error.lo \ libglpk_la-stdout.lo libglpk_la-time.lo libglpk_la-tls.lo \ libglpk_la-minisat.lo libglpk_la-bignum.lo libglpk_la-dmp.lo \ libglpk_la-ffalg.lo libglpk_la-jd.lo libglpk_la-keller.lo \ libglpk_la-mc13d.lo libglpk_la-mc21a.lo libglpk_la-okalg.lo \ libglpk_la-qmd.lo libglpk_la-relax4.lo libglpk_la-rng.lo \ libglpk_la-rng1.lo libglpk_la-triang.lo libglpk_la-wclique.lo \ libglpk_la-wclique1.lo libglpk_la-proxy.lo \ libglpk_la-proxy1.lo libglpk_la-adler32.lo \ libglpk_la-compress.lo libglpk_la-crc32.lo \ libglpk_la-deflate.lo libglpk_la-gzclose.lo \ libglpk_la-gzlib.lo libglpk_la-gzread.lo libglpk_la-gzwrite.lo \ libglpk_la-inffast.lo libglpk_la-inflate.lo \ libglpk_la-inftrees.lo libglpk_la-trees.lo \ libglpk_la-uncompr.lo libglpk_la-zio.lo libglpk_la-zutil.lo libglpk_la_OBJECTS = $(am_libglpk_la_OBJECTS) libglpk_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libglpk_la_LDFLAGS) $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libglpk_la_SOURCES) DIST_SOURCES = $(libglpk_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(include_HEADERS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ include_HEADERS = glpk.h lib_LTLIBRARIES = libglpk.la libglpk_la_CPPFLAGS = \ -I$(srcdir) \ -I$(srcdir)/amd \ -I$(srcdir)/bflib \ -I$(srcdir)/cglib \ -I$(srcdir)/colamd \ -I$(srcdir)/env \ -I$(srcdir)/minisat \ -I$(srcdir)/misc \ -I$(srcdir)/proxy \ -I$(srcdir)/zlib libglpk_la_LDFLAGS = \ -version-info 36:1:0 \ -export-symbols-regex '^glp_*' libglpk_la_SOURCES = \ glpapi01.c \ glpapi02.c \ glpapi03.c \ glpapi04.c \ glpapi05.c \ glpapi06.c \ glpapi07.c \ glpapi08.c \ glpapi09.c \ glpapi10.c \ glpapi11.c \ glpapi12.c \ glpapi13.c \ glpapi14.c \ glpapi15.c \ glpapi16.c \ glpapi17.c \ glpapi18.c \ glpapi19.c \ glpapi20.c \ glpapi21.c \ glpavl.c \ glpbfd.c \ glpbfx.c \ glpcpx.c \ glpdmx.c \ glpenv07.c \ glpenv08.c \ glpgmp.c \ glphbm.c \ glpini01.c \ glpini02.c \ glpios01.c \ glpios02.c \ glpios03.c \ glpios04.c \ glpios05.c \ glpios06.c \ glpios07.c \ glpios08.c \ glpios09.c \ glpios10.c \ glpios11.c \ glpios12.c \ glpipm.c \ glplib03.c \ glplpf.c \ glplpx01.c \ glplpx02.c \ glplpx03.c \ glplux.c \ glpmat.c \ glpmpl01.c \ glpmpl02.c \ glpmpl03.c \ glpmpl04.c \ glpmpl05.c \ glpmpl06.c \ glpmps.c \ glpnet03.c \ glpnet04.c \ glpnet05.c \ glpnpp01.c \ glpnpp02.c \ glpnpp03.c \ glpnpp04.c \ glpnpp05.c \ glpnpp06.c \ glprgr.c \ glpscf.c \ glpscl.c \ glpsdf.c \ glpspm.c \ glpspx01.c \ glpspx02.c \ glpsql.c \ glpssx01.c \ glpssx02.c \ glptsp.c \ amd/amd_1.c \ amd/amd_2.c \ amd/amd_aat.c \ amd/amd_control.c \ amd/amd_defaults.c \ amd/amd_dump.c \ amd/amd_info.c \ amd/amd_order.c \ amd/amd_post_tree.c \ amd/amd_postorder.c \ amd/amd_preprocess.c \ amd/amd_valid.c \ bflib/fhv.c \ bflib/fhvint.c \ bflib/luf.c \ bflib/lufint.c \ bflib/sgf.c \ bflib/sva.c \ cglib/cfg.c \ cglib/cfg1.c \ colamd/colamd.c \ env/alloc.c \ env/env.c \ env/error.c \ env/stdout.c \ env/time.c \ env/tls.c \ minisat/minisat.c \ misc/bignum.c \ misc/dmp.c \ misc/ffalg.c \ misc/jd.c \ misc/keller.c \ misc/mc13d.c \ misc/mc21a.c \ misc/okalg.c \ misc/qmd.c \ misc/relax4.c \ misc/rng.c \ misc/rng1.c \ misc/triang.c \ misc/wclique.c \ misc/wclique1.c \ proxy/proxy.c \ proxy/proxy1.c \ zlib/adler32.c \ zlib/compress.c \ zlib/crc32.c \ zlib/deflate.c \ zlib/gzclose.c \ zlib/gzlib.c \ zlib/gzread.c \ zlib/gzwrite.c \ zlib/inffast.c \ zlib/inflate.c \ zlib/inftrees.c \ zlib/trees.c \ zlib/uncompr.c \ zlib/zio.c \ zlib/zutil.c all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libglpk.la: $(libglpk_la_OBJECTS) $(libglpk_la_DEPENDENCIES) $(EXTRA_libglpk_la_DEPENDENCIES) $(libglpk_la_LINK) -rpath $(libdir) $(libglpk_la_OBJECTS) $(libglpk_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-adler32.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-alloc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-amd_1.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-amd_2.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-amd_aat.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-amd_control.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-amd_defaults.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-amd_dump.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-amd_info.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-amd_order.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-amd_post_tree.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-amd_postorder.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-amd_preprocess.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-amd_valid.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-bignum.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-cfg.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-cfg1.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-colamd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-compress.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-crc32.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-deflate.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-dmp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-env.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-error.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-ffalg.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-fhv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-fhvint.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi01.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi02.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi03.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi04.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi05.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi06.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi07.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi08.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi09.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi10.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi11.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi12.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi13.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi14.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi15.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi16.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi17.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi18.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi19.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi20.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpapi21.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpavl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpbfd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpbfx.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpcpx.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpdmx.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpenv07.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpenv08.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpgmp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glphbm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpini01.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpini02.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpios01.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpios02.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpios03.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpios04.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpios05.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpios06.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpios07.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpios08.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpios09.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpios10.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpios11.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpios12.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpipm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glplib03.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glplpf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glplpx01.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glplpx02.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glplpx03.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glplux.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpmat.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpmpl01.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpmpl02.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpmpl03.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpmpl04.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpmpl05.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpmpl06.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpmps.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpnet03.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpnet04.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpnet05.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpnpp01.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpnpp02.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpnpp03.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpnpp04.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpnpp05.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpnpp06.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glprgr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpscf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpscl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpsdf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpspm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpspx01.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpspx02.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpsql.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpssx01.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glpssx02.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-glptsp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-gzclose.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-gzlib.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-gzread.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-gzwrite.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-inffast.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-inflate.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-inftrees.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-jd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-keller.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-luf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-lufint.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-mc13d.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-mc21a.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-minisat.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-okalg.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-proxy.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-proxy1.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-qmd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-relax4.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-rng.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-rng1.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-sgf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-stdout.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-sva.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-time.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-tls.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-trees.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-triang.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-uncompr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-wclique.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-wclique1.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-zio.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libglpk_la-zutil.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< libglpk_la-glpapi01.lo: glpapi01.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi01.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi01.Tpo -c -o libglpk_la-glpapi01.lo `test -f 'glpapi01.c' || echo '$(srcdir)/'`glpapi01.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi01.Tpo $(DEPDIR)/libglpk_la-glpapi01.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi01.c' object='libglpk_la-glpapi01.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi01.lo `test -f 'glpapi01.c' || echo '$(srcdir)/'`glpapi01.c libglpk_la-glpapi02.lo: glpapi02.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi02.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi02.Tpo -c -o libglpk_la-glpapi02.lo `test -f 'glpapi02.c' || echo '$(srcdir)/'`glpapi02.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi02.Tpo $(DEPDIR)/libglpk_la-glpapi02.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi02.c' object='libglpk_la-glpapi02.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi02.lo `test -f 'glpapi02.c' || echo '$(srcdir)/'`glpapi02.c libglpk_la-glpapi03.lo: glpapi03.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi03.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi03.Tpo -c -o libglpk_la-glpapi03.lo `test -f 'glpapi03.c' || echo '$(srcdir)/'`glpapi03.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi03.Tpo $(DEPDIR)/libglpk_la-glpapi03.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi03.c' object='libglpk_la-glpapi03.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi03.lo `test -f 'glpapi03.c' || echo '$(srcdir)/'`glpapi03.c libglpk_la-glpapi04.lo: glpapi04.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi04.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi04.Tpo -c -o libglpk_la-glpapi04.lo `test -f 'glpapi04.c' || echo '$(srcdir)/'`glpapi04.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi04.Tpo $(DEPDIR)/libglpk_la-glpapi04.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi04.c' object='libglpk_la-glpapi04.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi04.lo `test -f 'glpapi04.c' || echo '$(srcdir)/'`glpapi04.c libglpk_la-glpapi05.lo: glpapi05.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi05.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi05.Tpo -c -o libglpk_la-glpapi05.lo `test -f 'glpapi05.c' || echo '$(srcdir)/'`glpapi05.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi05.Tpo $(DEPDIR)/libglpk_la-glpapi05.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi05.c' object='libglpk_la-glpapi05.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi05.lo `test -f 'glpapi05.c' || echo '$(srcdir)/'`glpapi05.c libglpk_la-glpapi06.lo: glpapi06.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi06.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi06.Tpo -c -o libglpk_la-glpapi06.lo `test -f 'glpapi06.c' || echo '$(srcdir)/'`glpapi06.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi06.Tpo $(DEPDIR)/libglpk_la-glpapi06.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi06.c' object='libglpk_la-glpapi06.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi06.lo `test -f 'glpapi06.c' || echo '$(srcdir)/'`glpapi06.c libglpk_la-glpapi07.lo: glpapi07.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi07.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi07.Tpo -c -o libglpk_la-glpapi07.lo `test -f 'glpapi07.c' || echo '$(srcdir)/'`glpapi07.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi07.Tpo $(DEPDIR)/libglpk_la-glpapi07.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi07.c' object='libglpk_la-glpapi07.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi07.lo `test -f 'glpapi07.c' || echo '$(srcdir)/'`glpapi07.c libglpk_la-glpapi08.lo: glpapi08.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi08.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi08.Tpo -c -o libglpk_la-glpapi08.lo `test -f 'glpapi08.c' || echo '$(srcdir)/'`glpapi08.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi08.Tpo $(DEPDIR)/libglpk_la-glpapi08.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi08.c' object='libglpk_la-glpapi08.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi08.lo `test -f 'glpapi08.c' || echo '$(srcdir)/'`glpapi08.c libglpk_la-glpapi09.lo: glpapi09.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi09.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi09.Tpo -c -o libglpk_la-glpapi09.lo `test -f 'glpapi09.c' || echo '$(srcdir)/'`glpapi09.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi09.Tpo $(DEPDIR)/libglpk_la-glpapi09.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi09.c' object='libglpk_la-glpapi09.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi09.lo `test -f 'glpapi09.c' || echo '$(srcdir)/'`glpapi09.c libglpk_la-glpapi10.lo: glpapi10.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi10.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi10.Tpo -c -o libglpk_la-glpapi10.lo `test -f 'glpapi10.c' || echo '$(srcdir)/'`glpapi10.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi10.Tpo $(DEPDIR)/libglpk_la-glpapi10.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi10.c' object='libglpk_la-glpapi10.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi10.lo `test -f 'glpapi10.c' || echo '$(srcdir)/'`glpapi10.c libglpk_la-glpapi11.lo: glpapi11.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi11.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi11.Tpo -c -o libglpk_la-glpapi11.lo `test -f 'glpapi11.c' || echo '$(srcdir)/'`glpapi11.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi11.Tpo $(DEPDIR)/libglpk_la-glpapi11.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi11.c' object='libglpk_la-glpapi11.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi11.lo `test -f 'glpapi11.c' || echo '$(srcdir)/'`glpapi11.c libglpk_la-glpapi12.lo: glpapi12.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi12.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi12.Tpo -c -o libglpk_la-glpapi12.lo `test -f 'glpapi12.c' || echo '$(srcdir)/'`glpapi12.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi12.Tpo $(DEPDIR)/libglpk_la-glpapi12.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi12.c' object='libglpk_la-glpapi12.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi12.lo `test -f 'glpapi12.c' || echo '$(srcdir)/'`glpapi12.c libglpk_la-glpapi13.lo: glpapi13.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi13.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi13.Tpo -c -o libglpk_la-glpapi13.lo `test -f 'glpapi13.c' || echo '$(srcdir)/'`glpapi13.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi13.Tpo $(DEPDIR)/libglpk_la-glpapi13.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi13.c' object='libglpk_la-glpapi13.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi13.lo `test -f 'glpapi13.c' || echo '$(srcdir)/'`glpapi13.c libglpk_la-glpapi14.lo: glpapi14.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi14.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi14.Tpo -c -o libglpk_la-glpapi14.lo `test -f 'glpapi14.c' || echo '$(srcdir)/'`glpapi14.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi14.Tpo $(DEPDIR)/libglpk_la-glpapi14.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi14.c' object='libglpk_la-glpapi14.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi14.lo `test -f 'glpapi14.c' || echo '$(srcdir)/'`glpapi14.c libglpk_la-glpapi15.lo: glpapi15.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi15.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi15.Tpo -c -o libglpk_la-glpapi15.lo `test -f 'glpapi15.c' || echo '$(srcdir)/'`glpapi15.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi15.Tpo $(DEPDIR)/libglpk_la-glpapi15.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi15.c' object='libglpk_la-glpapi15.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi15.lo `test -f 'glpapi15.c' || echo '$(srcdir)/'`glpapi15.c libglpk_la-glpapi16.lo: glpapi16.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi16.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi16.Tpo -c -o libglpk_la-glpapi16.lo `test -f 'glpapi16.c' || echo '$(srcdir)/'`glpapi16.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi16.Tpo $(DEPDIR)/libglpk_la-glpapi16.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi16.c' object='libglpk_la-glpapi16.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi16.lo `test -f 'glpapi16.c' || echo '$(srcdir)/'`glpapi16.c libglpk_la-glpapi17.lo: glpapi17.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi17.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi17.Tpo -c -o libglpk_la-glpapi17.lo `test -f 'glpapi17.c' || echo '$(srcdir)/'`glpapi17.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi17.Tpo $(DEPDIR)/libglpk_la-glpapi17.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi17.c' object='libglpk_la-glpapi17.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi17.lo `test -f 'glpapi17.c' || echo '$(srcdir)/'`glpapi17.c libglpk_la-glpapi18.lo: glpapi18.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi18.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi18.Tpo -c -o libglpk_la-glpapi18.lo `test -f 'glpapi18.c' || echo '$(srcdir)/'`glpapi18.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi18.Tpo $(DEPDIR)/libglpk_la-glpapi18.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi18.c' object='libglpk_la-glpapi18.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi18.lo `test -f 'glpapi18.c' || echo '$(srcdir)/'`glpapi18.c libglpk_la-glpapi19.lo: glpapi19.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi19.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi19.Tpo -c -o libglpk_la-glpapi19.lo `test -f 'glpapi19.c' || echo '$(srcdir)/'`glpapi19.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi19.Tpo $(DEPDIR)/libglpk_la-glpapi19.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi19.c' object='libglpk_la-glpapi19.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi19.lo `test -f 'glpapi19.c' || echo '$(srcdir)/'`glpapi19.c libglpk_la-glpapi20.lo: glpapi20.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi20.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi20.Tpo -c -o libglpk_la-glpapi20.lo `test -f 'glpapi20.c' || echo '$(srcdir)/'`glpapi20.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi20.Tpo $(DEPDIR)/libglpk_la-glpapi20.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi20.c' object='libglpk_la-glpapi20.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi20.lo `test -f 'glpapi20.c' || echo '$(srcdir)/'`glpapi20.c libglpk_la-glpapi21.lo: glpapi21.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpapi21.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpapi21.Tpo -c -o libglpk_la-glpapi21.lo `test -f 'glpapi21.c' || echo '$(srcdir)/'`glpapi21.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpapi21.Tpo $(DEPDIR)/libglpk_la-glpapi21.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpapi21.c' object='libglpk_la-glpapi21.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpapi21.lo `test -f 'glpapi21.c' || echo '$(srcdir)/'`glpapi21.c libglpk_la-glpavl.lo: glpavl.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpavl.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpavl.Tpo -c -o libglpk_la-glpavl.lo `test -f 'glpavl.c' || echo '$(srcdir)/'`glpavl.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpavl.Tpo $(DEPDIR)/libglpk_la-glpavl.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpavl.c' object='libglpk_la-glpavl.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpavl.lo `test -f 'glpavl.c' || echo '$(srcdir)/'`glpavl.c libglpk_la-glpbfd.lo: glpbfd.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpbfd.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpbfd.Tpo -c -o libglpk_la-glpbfd.lo `test -f 'glpbfd.c' || echo '$(srcdir)/'`glpbfd.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpbfd.Tpo $(DEPDIR)/libglpk_la-glpbfd.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpbfd.c' object='libglpk_la-glpbfd.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpbfd.lo `test -f 'glpbfd.c' || echo '$(srcdir)/'`glpbfd.c libglpk_la-glpbfx.lo: glpbfx.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpbfx.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpbfx.Tpo -c -o libglpk_la-glpbfx.lo `test -f 'glpbfx.c' || echo '$(srcdir)/'`glpbfx.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpbfx.Tpo $(DEPDIR)/libglpk_la-glpbfx.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpbfx.c' object='libglpk_la-glpbfx.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpbfx.lo `test -f 'glpbfx.c' || echo '$(srcdir)/'`glpbfx.c libglpk_la-glpcpx.lo: glpcpx.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpcpx.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpcpx.Tpo -c -o libglpk_la-glpcpx.lo `test -f 'glpcpx.c' || echo '$(srcdir)/'`glpcpx.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpcpx.Tpo $(DEPDIR)/libglpk_la-glpcpx.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpcpx.c' object='libglpk_la-glpcpx.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpcpx.lo `test -f 'glpcpx.c' || echo '$(srcdir)/'`glpcpx.c libglpk_la-glpdmx.lo: glpdmx.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpdmx.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpdmx.Tpo -c -o libglpk_la-glpdmx.lo `test -f 'glpdmx.c' || echo '$(srcdir)/'`glpdmx.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpdmx.Tpo $(DEPDIR)/libglpk_la-glpdmx.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpdmx.c' object='libglpk_la-glpdmx.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpdmx.lo `test -f 'glpdmx.c' || echo '$(srcdir)/'`glpdmx.c libglpk_la-glpenv07.lo: glpenv07.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpenv07.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpenv07.Tpo -c -o libglpk_la-glpenv07.lo `test -f 'glpenv07.c' || echo '$(srcdir)/'`glpenv07.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpenv07.Tpo $(DEPDIR)/libglpk_la-glpenv07.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpenv07.c' object='libglpk_la-glpenv07.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpenv07.lo `test -f 'glpenv07.c' || echo '$(srcdir)/'`glpenv07.c libglpk_la-glpenv08.lo: glpenv08.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpenv08.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpenv08.Tpo -c -o libglpk_la-glpenv08.lo `test -f 'glpenv08.c' || echo '$(srcdir)/'`glpenv08.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpenv08.Tpo $(DEPDIR)/libglpk_la-glpenv08.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpenv08.c' object='libglpk_la-glpenv08.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpenv08.lo `test -f 'glpenv08.c' || echo '$(srcdir)/'`glpenv08.c libglpk_la-glpgmp.lo: glpgmp.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpgmp.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpgmp.Tpo -c -o libglpk_la-glpgmp.lo `test -f 'glpgmp.c' || echo '$(srcdir)/'`glpgmp.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpgmp.Tpo $(DEPDIR)/libglpk_la-glpgmp.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpgmp.c' object='libglpk_la-glpgmp.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpgmp.lo `test -f 'glpgmp.c' || echo '$(srcdir)/'`glpgmp.c libglpk_la-glphbm.lo: glphbm.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glphbm.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glphbm.Tpo -c -o libglpk_la-glphbm.lo `test -f 'glphbm.c' || echo '$(srcdir)/'`glphbm.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glphbm.Tpo $(DEPDIR)/libglpk_la-glphbm.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glphbm.c' object='libglpk_la-glphbm.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glphbm.lo `test -f 'glphbm.c' || echo '$(srcdir)/'`glphbm.c libglpk_la-glpini01.lo: glpini01.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpini01.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpini01.Tpo -c -o libglpk_la-glpini01.lo `test -f 'glpini01.c' || echo '$(srcdir)/'`glpini01.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpini01.Tpo $(DEPDIR)/libglpk_la-glpini01.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpini01.c' object='libglpk_la-glpini01.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpini01.lo `test -f 'glpini01.c' || echo '$(srcdir)/'`glpini01.c libglpk_la-glpini02.lo: glpini02.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpini02.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpini02.Tpo -c -o libglpk_la-glpini02.lo `test -f 'glpini02.c' || echo '$(srcdir)/'`glpini02.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpini02.Tpo $(DEPDIR)/libglpk_la-glpini02.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpini02.c' object='libglpk_la-glpini02.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpini02.lo `test -f 'glpini02.c' || echo '$(srcdir)/'`glpini02.c libglpk_la-glpios01.lo: glpios01.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpios01.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpios01.Tpo -c -o libglpk_la-glpios01.lo `test -f 'glpios01.c' || echo '$(srcdir)/'`glpios01.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpios01.Tpo $(DEPDIR)/libglpk_la-glpios01.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpios01.c' object='libglpk_la-glpios01.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpios01.lo `test -f 'glpios01.c' || echo '$(srcdir)/'`glpios01.c libglpk_la-glpios02.lo: glpios02.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpios02.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpios02.Tpo -c -o libglpk_la-glpios02.lo `test -f 'glpios02.c' || echo '$(srcdir)/'`glpios02.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpios02.Tpo $(DEPDIR)/libglpk_la-glpios02.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpios02.c' object='libglpk_la-glpios02.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpios02.lo `test -f 'glpios02.c' || echo '$(srcdir)/'`glpios02.c libglpk_la-glpios03.lo: glpios03.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpios03.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpios03.Tpo -c -o libglpk_la-glpios03.lo `test -f 'glpios03.c' || echo '$(srcdir)/'`glpios03.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpios03.Tpo $(DEPDIR)/libglpk_la-glpios03.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpios03.c' object='libglpk_la-glpios03.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpios03.lo `test -f 'glpios03.c' || echo '$(srcdir)/'`glpios03.c libglpk_la-glpios04.lo: glpios04.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpios04.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpios04.Tpo -c -o libglpk_la-glpios04.lo `test -f 'glpios04.c' || echo '$(srcdir)/'`glpios04.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpios04.Tpo $(DEPDIR)/libglpk_la-glpios04.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpios04.c' object='libglpk_la-glpios04.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpios04.lo `test -f 'glpios04.c' || echo '$(srcdir)/'`glpios04.c libglpk_la-glpios05.lo: glpios05.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpios05.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpios05.Tpo -c -o libglpk_la-glpios05.lo `test -f 'glpios05.c' || echo '$(srcdir)/'`glpios05.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpios05.Tpo $(DEPDIR)/libglpk_la-glpios05.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpios05.c' object='libglpk_la-glpios05.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpios05.lo `test -f 'glpios05.c' || echo '$(srcdir)/'`glpios05.c libglpk_la-glpios06.lo: glpios06.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpios06.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpios06.Tpo -c -o libglpk_la-glpios06.lo `test -f 'glpios06.c' || echo '$(srcdir)/'`glpios06.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpios06.Tpo $(DEPDIR)/libglpk_la-glpios06.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpios06.c' object='libglpk_la-glpios06.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpios06.lo `test -f 'glpios06.c' || echo '$(srcdir)/'`glpios06.c libglpk_la-glpios07.lo: glpios07.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpios07.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpios07.Tpo -c -o libglpk_la-glpios07.lo `test -f 'glpios07.c' || echo '$(srcdir)/'`glpios07.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpios07.Tpo $(DEPDIR)/libglpk_la-glpios07.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpios07.c' object='libglpk_la-glpios07.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpios07.lo `test -f 'glpios07.c' || echo '$(srcdir)/'`glpios07.c libglpk_la-glpios08.lo: glpios08.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpios08.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpios08.Tpo -c -o libglpk_la-glpios08.lo `test -f 'glpios08.c' || echo '$(srcdir)/'`glpios08.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpios08.Tpo $(DEPDIR)/libglpk_la-glpios08.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpios08.c' object='libglpk_la-glpios08.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpios08.lo `test -f 'glpios08.c' || echo '$(srcdir)/'`glpios08.c libglpk_la-glpios09.lo: glpios09.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpios09.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpios09.Tpo -c -o libglpk_la-glpios09.lo `test -f 'glpios09.c' || echo '$(srcdir)/'`glpios09.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpios09.Tpo $(DEPDIR)/libglpk_la-glpios09.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpios09.c' object='libglpk_la-glpios09.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpios09.lo `test -f 'glpios09.c' || echo '$(srcdir)/'`glpios09.c libglpk_la-glpios10.lo: glpios10.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpios10.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpios10.Tpo -c -o libglpk_la-glpios10.lo `test -f 'glpios10.c' || echo '$(srcdir)/'`glpios10.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpios10.Tpo $(DEPDIR)/libglpk_la-glpios10.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpios10.c' object='libglpk_la-glpios10.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpios10.lo `test -f 'glpios10.c' || echo '$(srcdir)/'`glpios10.c libglpk_la-glpios11.lo: glpios11.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpios11.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpios11.Tpo -c -o libglpk_la-glpios11.lo `test -f 'glpios11.c' || echo '$(srcdir)/'`glpios11.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpios11.Tpo $(DEPDIR)/libglpk_la-glpios11.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpios11.c' object='libglpk_la-glpios11.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpios11.lo `test -f 'glpios11.c' || echo '$(srcdir)/'`glpios11.c libglpk_la-glpios12.lo: glpios12.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpios12.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpios12.Tpo -c -o libglpk_la-glpios12.lo `test -f 'glpios12.c' || echo '$(srcdir)/'`glpios12.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpios12.Tpo $(DEPDIR)/libglpk_la-glpios12.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpios12.c' object='libglpk_la-glpios12.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpios12.lo `test -f 'glpios12.c' || echo '$(srcdir)/'`glpios12.c libglpk_la-glpipm.lo: glpipm.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpipm.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpipm.Tpo -c -o libglpk_la-glpipm.lo `test -f 'glpipm.c' || echo '$(srcdir)/'`glpipm.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpipm.Tpo $(DEPDIR)/libglpk_la-glpipm.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpipm.c' object='libglpk_la-glpipm.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpipm.lo `test -f 'glpipm.c' || echo '$(srcdir)/'`glpipm.c libglpk_la-glplib03.lo: glplib03.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glplib03.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glplib03.Tpo -c -o libglpk_la-glplib03.lo `test -f 'glplib03.c' || echo '$(srcdir)/'`glplib03.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glplib03.Tpo $(DEPDIR)/libglpk_la-glplib03.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glplib03.c' object='libglpk_la-glplib03.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glplib03.lo `test -f 'glplib03.c' || echo '$(srcdir)/'`glplib03.c libglpk_la-glplpf.lo: glplpf.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glplpf.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glplpf.Tpo -c -o libglpk_la-glplpf.lo `test -f 'glplpf.c' || echo '$(srcdir)/'`glplpf.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glplpf.Tpo $(DEPDIR)/libglpk_la-glplpf.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glplpf.c' object='libglpk_la-glplpf.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glplpf.lo `test -f 'glplpf.c' || echo '$(srcdir)/'`glplpf.c libglpk_la-glplpx01.lo: glplpx01.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glplpx01.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glplpx01.Tpo -c -o libglpk_la-glplpx01.lo `test -f 'glplpx01.c' || echo '$(srcdir)/'`glplpx01.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glplpx01.Tpo $(DEPDIR)/libglpk_la-glplpx01.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glplpx01.c' object='libglpk_la-glplpx01.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glplpx01.lo `test -f 'glplpx01.c' || echo '$(srcdir)/'`glplpx01.c libglpk_la-glplpx02.lo: glplpx02.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glplpx02.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glplpx02.Tpo -c -o libglpk_la-glplpx02.lo `test -f 'glplpx02.c' || echo '$(srcdir)/'`glplpx02.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glplpx02.Tpo $(DEPDIR)/libglpk_la-glplpx02.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glplpx02.c' object='libglpk_la-glplpx02.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glplpx02.lo `test -f 'glplpx02.c' || echo '$(srcdir)/'`glplpx02.c libglpk_la-glplpx03.lo: glplpx03.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glplpx03.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glplpx03.Tpo -c -o libglpk_la-glplpx03.lo `test -f 'glplpx03.c' || echo '$(srcdir)/'`glplpx03.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glplpx03.Tpo $(DEPDIR)/libglpk_la-glplpx03.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glplpx03.c' object='libglpk_la-glplpx03.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glplpx03.lo `test -f 'glplpx03.c' || echo '$(srcdir)/'`glplpx03.c libglpk_la-glplux.lo: glplux.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glplux.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glplux.Tpo -c -o libglpk_la-glplux.lo `test -f 'glplux.c' || echo '$(srcdir)/'`glplux.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glplux.Tpo $(DEPDIR)/libglpk_la-glplux.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glplux.c' object='libglpk_la-glplux.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glplux.lo `test -f 'glplux.c' || echo '$(srcdir)/'`glplux.c libglpk_la-glpmat.lo: glpmat.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpmat.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpmat.Tpo -c -o libglpk_la-glpmat.lo `test -f 'glpmat.c' || echo '$(srcdir)/'`glpmat.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpmat.Tpo $(DEPDIR)/libglpk_la-glpmat.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpmat.c' object='libglpk_la-glpmat.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpmat.lo `test -f 'glpmat.c' || echo '$(srcdir)/'`glpmat.c libglpk_la-glpmpl01.lo: glpmpl01.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpmpl01.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpmpl01.Tpo -c -o libglpk_la-glpmpl01.lo `test -f 'glpmpl01.c' || echo '$(srcdir)/'`glpmpl01.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpmpl01.Tpo $(DEPDIR)/libglpk_la-glpmpl01.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpmpl01.c' object='libglpk_la-glpmpl01.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpmpl01.lo `test -f 'glpmpl01.c' || echo '$(srcdir)/'`glpmpl01.c libglpk_la-glpmpl02.lo: glpmpl02.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpmpl02.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpmpl02.Tpo -c -o libglpk_la-glpmpl02.lo `test -f 'glpmpl02.c' || echo '$(srcdir)/'`glpmpl02.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpmpl02.Tpo $(DEPDIR)/libglpk_la-glpmpl02.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpmpl02.c' object='libglpk_la-glpmpl02.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpmpl02.lo `test -f 'glpmpl02.c' || echo '$(srcdir)/'`glpmpl02.c libglpk_la-glpmpl03.lo: glpmpl03.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpmpl03.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpmpl03.Tpo -c -o libglpk_la-glpmpl03.lo `test -f 'glpmpl03.c' || echo '$(srcdir)/'`glpmpl03.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpmpl03.Tpo $(DEPDIR)/libglpk_la-glpmpl03.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpmpl03.c' object='libglpk_la-glpmpl03.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpmpl03.lo `test -f 'glpmpl03.c' || echo '$(srcdir)/'`glpmpl03.c libglpk_la-glpmpl04.lo: glpmpl04.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpmpl04.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpmpl04.Tpo -c -o libglpk_la-glpmpl04.lo `test -f 'glpmpl04.c' || echo '$(srcdir)/'`glpmpl04.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpmpl04.Tpo $(DEPDIR)/libglpk_la-glpmpl04.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpmpl04.c' object='libglpk_la-glpmpl04.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpmpl04.lo `test -f 'glpmpl04.c' || echo '$(srcdir)/'`glpmpl04.c libglpk_la-glpmpl05.lo: glpmpl05.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpmpl05.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpmpl05.Tpo -c -o libglpk_la-glpmpl05.lo `test -f 'glpmpl05.c' || echo '$(srcdir)/'`glpmpl05.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpmpl05.Tpo $(DEPDIR)/libglpk_la-glpmpl05.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpmpl05.c' object='libglpk_la-glpmpl05.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpmpl05.lo `test -f 'glpmpl05.c' || echo '$(srcdir)/'`glpmpl05.c libglpk_la-glpmpl06.lo: glpmpl06.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpmpl06.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpmpl06.Tpo -c -o libglpk_la-glpmpl06.lo `test -f 'glpmpl06.c' || echo '$(srcdir)/'`glpmpl06.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpmpl06.Tpo $(DEPDIR)/libglpk_la-glpmpl06.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpmpl06.c' object='libglpk_la-glpmpl06.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpmpl06.lo `test -f 'glpmpl06.c' || echo '$(srcdir)/'`glpmpl06.c libglpk_la-glpmps.lo: glpmps.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpmps.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpmps.Tpo -c -o libglpk_la-glpmps.lo `test -f 'glpmps.c' || echo '$(srcdir)/'`glpmps.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpmps.Tpo $(DEPDIR)/libglpk_la-glpmps.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpmps.c' object='libglpk_la-glpmps.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpmps.lo `test -f 'glpmps.c' || echo '$(srcdir)/'`glpmps.c libglpk_la-glpnet03.lo: glpnet03.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpnet03.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpnet03.Tpo -c -o libglpk_la-glpnet03.lo `test -f 'glpnet03.c' || echo '$(srcdir)/'`glpnet03.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpnet03.Tpo $(DEPDIR)/libglpk_la-glpnet03.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpnet03.c' object='libglpk_la-glpnet03.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpnet03.lo `test -f 'glpnet03.c' || echo '$(srcdir)/'`glpnet03.c libglpk_la-glpnet04.lo: glpnet04.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpnet04.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpnet04.Tpo -c -o libglpk_la-glpnet04.lo `test -f 'glpnet04.c' || echo '$(srcdir)/'`glpnet04.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpnet04.Tpo $(DEPDIR)/libglpk_la-glpnet04.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpnet04.c' object='libglpk_la-glpnet04.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpnet04.lo `test -f 'glpnet04.c' || echo '$(srcdir)/'`glpnet04.c libglpk_la-glpnet05.lo: glpnet05.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpnet05.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpnet05.Tpo -c -o libglpk_la-glpnet05.lo `test -f 'glpnet05.c' || echo '$(srcdir)/'`glpnet05.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpnet05.Tpo $(DEPDIR)/libglpk_la-glpnet05.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpnet05.c' object='libglpk_la-glpnet05.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpnet05.lo `test -f 'glpnet05.c' || echo '$(srcdir)/'`glpnet05.c libglpk_la-glpnpp01.lo: glpnpp01.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpnpp01.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpnpp01.Tpo -c -o libglpk_la-glpnpp01.lo `test -f 'glpnpp01.c' || echo '$(srcdir)/'`glpnpp01.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpnpp01.Tpo $(DEPDIR)/libglpk_la-glpnpp01.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpnpp01.c' object='libglpk_la-glpnpp01.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpnpp01.lo `test -f 'glpnpp01.c' || echo '$(srcdir)/'`glpnpp01.c libglpk_la-glpnpp02.lo: glpnpp02.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpnpp02.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpnpp02.Tpo -c -o libglpk_la-glpnpp02.lo `test -f 'glpnpp02.c' || echo '$(srcdir)/'`glpnpp02.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpnpp02.Tpo $(DEPDIR)/libglpk_la-glpnpp02.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpnpp02.c' object='libglpk_la-glpnpp02.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpnpp02.lo `test -f 'glpnpp02.c' || echo '$(srcdir)/'`glpnpp02.c libglpk_la-glpnpp03.lo: glpnpp03.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpnpp03.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpnpp03.Tpo -c -o libglpk_la-glpnpp03.lo `test -f 'glpnpp03.c' || echo '$(srcdir)/'`glpnpp03.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpnpp03.Tpo $(DEPDIR)/libglpk_la-glpnpp03.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpnpp03.c' object='libglpk_la-glpnpp03.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpnpp03.lo `test -f 'glpnpp03.c' || echo '$(srcdir)/'`glpnpp03.c libglpk_la-glpnpp04.lo: glpnpp04.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpnpp04.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpnpp04.Tpo -c -o libglpk_la-glpnpp04.lo `test -f 'glpnpp04.c' || echo '$(srcdir)/'`glpnpp04.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpnpp04.Tpo $(DEPDIR)/libglpk_la-glpnpp04.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpnpp04.c' object='libglpk_la-glpnpp04.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpnpp04.lo `test -f 'glpnpp04.c' || echo '$(srcdir)/'`glpnpp04.c libglpk_la-glpnpp05.lo: glpnpp05.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpnpp05.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpnpp05.Tpo -c -o libglpk_la-glpnpp05.lo `test -f 'glpnpp05.c' || echo '$(srcdir)/'`glpnpp05.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpnpp05.Tpo $(DEPDIR)/libglpk_la-glpnpp05.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpnpp05.c' object='libglpk_la-glpnpp05.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpnpp05.lo `test -f 'glpnpp05.c' || echo '$(srcdir)/'`glpnpp05.c libglpk_la-glpnpp06.lo: glpnpp06.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpnpp06.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpnpp06.Tpo -c -o libglpk_la-glpnpp06.lo `test -f 'glpnpp06.c' || echo '$(srcdir)/'`glpnpp06.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpnpp06.Tpo $(DEPDIR)/libglpk_la-glpnpp06.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpnpp06.c' object='libglpk_la-glpnpp06.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpnpp06.lo `test -f 'glpnpp06.c' || echo '$(srcdir)/'`glpnpp06.c libglpk_la-glprgr.lo: glprgr.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glprgr.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glprgr.Tpo -c -o libglpk_la-glprgr.lo `test -f 'glprgr.c' || echo '$(srcdir)/'`glprgr.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glprgr.Tpo $(DEPDIR)/libglpk_la-glprgr.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glprgr.c' object='libglpk_la-glprgr.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glprgr.lo `test -f 'glprgr.c' || echo '$(srcdir)/'`glprgr.c libglpk_la-glpscf.lo: glpscf.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpscf.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpscf.Tpo -c -o libglpk_la-glpscf.lo `test -f 'glpscf.c' || echo '$(srcdir)/'`glpscf.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpscf.Tpo $(DEPDIR)/libglpk_la-glpscf.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpscf.c' object='libglpk_la-glpscf.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpscf.lo `test -f 'glpscf.c' || echo '$(srcdir)/'`glpscf.c libglpk_la-glpscl.lo: glpscl.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpscl.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpscl.Tpo -c -o libglpk_la-glpscl.lo `test -f 'glpscl.c' || echo '$(srcdir)/'`glpscl.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpscl.Tpo $(DEPDIR)/libglpk_la-glpscl.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpscl.c' object='libglpk_la-glpscl.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpscl.lo `test -f 'glpscl.c' || echo '$(srcdir)/'`glpscl.c libglpk_la-glpsdf.lo: glpsdf.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpsdf.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpsdf.Tpo -c -o libglpk_la-glpsdf.lo `test -f 'glpsdf.c' || echo '$(srcdir)/'`glpsdf.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpsdf.Tpo $(DEPDIR)/libglpk_la-glpsdf.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpsdf.c' object='libglpk_la-glpsdf.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpsdf.lo `test -f 'glpsdf.c' || echo '$(srcdir)/'`glpsdf.c libglpk_la-glpspm.lo: glpspm.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpspm.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpspm.Tpo -c -o libglpk_la-glpspm.lo `test -f 'glpspm.c' || echo '$(srcdir)/'`glpspm.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpspm.Tpo $(DEPDIR)/libglpk_la-glpspm.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpspm.c' object='libglpk_la-glpspm.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpspm.lo `test -f 'glpspm.c' || echo '$(srcdir)/'`glpspm.c libglpk_la-glpspx01.lo: glpspx01.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpspx01.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpspx01.Tpo -c -o libglpk_la-glpspx01.lo `test -f 'glpspx01.c' || echo '$(srcdir)/'`glpspx01.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpspx01.Tpo $(DEPDIR)/libglpk_la-glpspx01.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpspx01.c' object='libglpk_la-glpspx01.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpspx01.lo `test -f 'glpspx01.c' || echo '$(srcdir)/'`glpspx01.c libglpk_la-glpspx02.lo: glpspx02.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpspx02.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpspx02.Tpo -c -o libglpk_la-glpspx02.lo `test -f 'glpspx02.c' || echo '$(srcdir)/'`glpspx02.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpspx02.Tpo $(DEPDIR)/libglpk_la-glpspx02.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpspx02.c' object='libglpk_la-glpspx02.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpspx02.lo `test -f 'glpspx02.c' || echo '$(srcdir)/'`glpspx02.c libglpk_la-glpsql.lo: glpsql.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpsql.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpsql.Tpo -c -o libglpk_la-glpsql.lo `test -f 'glpsql.c' || echo '$(srcdir)/'`glpsql.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpsql.Tpo $(DEPDIR)/libglpk_la-glpsql.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpsql.c' object='libglpk_la-glpsql.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpsql.lo `test -f 'glpsql.c' || echo '$(srcdir)/'`glpsql.c libglpk_la-glpssx01.lo: glpssx01.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpssx01.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpssx01.Tpo -c -o libglpk_la-glpssx01.lo `test -f 'glpssx01.c' || echo '$(srcdir)/'`glpssx01.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpssx01.Tpo $(DEPDIR)/libglpk_la-glpssx01.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpssx01.c' object='libglpk_la-glpssx01.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpssx01.lo `test -f 'glpssx01.c' || echo '$(srcdir)/'`glpssx01.c libglpk_la-glpssx02.lo: glpssx02.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glpssx02.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glpssx02.Tpo -c -o libglpk_la-glpssx02.lo `test -f 'glpssx02.c' || echo '$(srcdir)/'`glpssx02.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glpssx02.Tpo $(DEPDIR)/libglpk_la-glpssx02.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glpssx02.c' object='libglpk_la-glpssx02.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glpssx02.lo `test -f 'glpssx02.c' || echo '$(srcdir)/'`glpssx02.c libglpk_la-glptsp.lo: glptsp.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-glptsp.lo -MD -MP -MF $(DEPDIR)/libglpk_la-glptsp.Tpo -c -o libglpk_la-glptsp.lo `test -f 'glptsp.c' || echo '$(srcdir)/'`glptsp.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-glptsp.Tpo $(DEPDIR)/libglpk_la-glptsp.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='glptsp.c' object='libglpk_la-glptsp.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-glptsp.lo `test -f 'glptsp.c' || echo '$(srcdir)/'`glptsp.c libglpk_la-amd_1.lo: amd/amd_1.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-amd_1.lo -MD -MP -MF $(DEPDIR)/libglpk_la-amd_1.Tpo -c -o libglpk_la-amd_1.lo `test -f 'amd/amd_1.c' || echo '$(srcdir)/'`amd/amd_1.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-amd_1.Tpo $(DEPDIR)/libglpk_la-amd_1.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='amd/amd_1.c' object='libglpk_la-amd_1.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-amd_1.lo `test -f 'amd/amd_1.c' || echo '$(srcdir)/'`amd/amd_1.c libglpk_la-amd_2.lo: amd/amd_2.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-amd_2.lo -MD -MP -MF $(DEPDIR)/libglpk_la-amd_2.Tpo -c -o libglpk_la-amd_2.lo `test -f 'amd/amd_2.c' || echo '$(srcdir)/'`amd/amd_2.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-amd_2.Tpo $(DEPDIR)/libglpk_la-amd_2.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='amd/amd_2.c' object='libglpk_la-amd_2.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-amd_2.lo `test -f 'amd/amd_2.c' || echo '$(srcdir)/'`amd/amd_2.c libglpk_la-amd_aat.lo: amd/amd_aat.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-amd_aat.lo -MD -MP -MF $(DEPDIR)/libglpk_la-amd_aat.Tpo -c -o libglpk_la-amd_aat.lo `test -f 'amd/amd_aat.c' || echo '$(srcdir)/'`amd/amd_aat.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-amd_aat.Tpo $(DEPDIR)/libglpk_la-amd_aat.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='amd/amd_aat.c' object='libglpk_la-amd_aat.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-amd_aat.lo `test -f 'amd/amd_aat.c' || echo '$(srcdir)/'`amd/amd_aat.c libglpk_la-amd_control.lo: amd/amd_control.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-amd_control.lo -MD -MP -MF $(DEPDIR)/libglpk_la-amd_control.Tpo -c -o libglpk_la-amd_control.lo `test -f 'amd/amd_control.c' || echo '$(srcdir)/'`amd/amd_control.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-amd_control.Tpo $(DEPDIR)/libglpk_la-amd_control.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='amd/amd_control.c' object='libglpk_la-amd_control.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-amd_control.lo `test -f 'amd/amd_control.c' || echo '$(srcdir)/'`amd/amd_control.c libglpk_la-amd_defaults.lo: amd/amd_defaults.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-amd_defaults.lo -MD -MP -MF $(DEPDIR)/libglpk_la-amd_defaults.Tpo -c -o libglpk_la-amd_defaults.lo `test -f 'amd/amd_defaults.c' || echo '$(srcdir)/'`amd/amd_defaults.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-amd_defaults.Tpo $(DEPDIR)/libglpk_la-amd_defaults.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='amd/amd_defaults.c' object='libglpk_la-amd_defaults.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-amd_defaults.lo `test -f 'amd/amd_defaults.c' || echo '$(srcdir)/'`amd/amd_defaults.c libglpk_la-amd_dump.lo: amd/amd_dump.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-amd_dump.lo -MD -MP -MF $(DEPDIR)/libglpk_la-amd_dump.Tpo -c -o libglpk_la-amd_dump.lo `test -f 'amd/amd_dump.c' || echo '$(srcdir)/'`amd/amd_dump.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-amd_dump.Tpo $(DEPDIR)/libglpk_la-amd_dump.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='amd/amd_dump.c' object='libglpk_la-amd_dump.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-amd_dump.lo `test -f 'amd/amd_dump.c' || echo '$(srcdir)/'`amd/amd_dump.c libglpk_la-amd_info.lo: amd/amd_info.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-amd_info.lo -MD -MP -MF $(DEPDIR)/libglpk_la-amd_info.Tpo -c -o libglpk_la-amd_info.lo `test -f 'amd/amd_info.c' || echo '$(srcdir)/'`amd/amd_info.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-amd_info.Tpo $(DEPDIR)/libglpk_la-amd_info.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='amd/amd_info.c' object='libglpk_la-amd_info.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-amd_info.lo `test -f 'amd/amd_info.c' || echo '$(srcdir)/'`amd/amd_info.c libglpk_la-amd_order.lo: amd/amd_order.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-amd_order.lo -MD -MP -MF $(DEPDIR)/libglpk_la-amd_order.Tpo -c -o libglpk_la-amd_order.lo `test -f 'amd/amd_order.c' || echo '$(srcdir)/'`amd/amd_order.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-amd_order.Tpo $(DEPDIR)/libglpk_la-amd_order.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='amd/amd_order.c' object='libglpk_la-amd_order.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-amd_order.lo `test -f 'amd/amd_order.c' || echo '$(srcdir)/'`amd/amd_order.c libglpk_la-amd_post_tree.lo: amd/amd_post_tree.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-amd_post_tree.lo -MD -MP -MF $(DEPDIR)/libglpk_la-amd_post_tree.Tpo -c -o libglpk_la-amd_post_tree.lo `test -f 'amd/amd_post_tree.c' || echo '$(srcdir)/'`amd/amd_post_tree.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-amd_post_tree.Tpo $(DEPDIR)/libglpk_la-amd_post_tree.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='amd/amd_post_tree.c' object='libglpk_la-amd_post_tree.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-amd_post_tree.lo `test -f 'amd/amd_post_tree.c' || echo '$(srcdir)/'`amd/amd_post_tree.c libglpk_la-amd_postorder.lo: amd/amd_postorder.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-amd_postorder.lo -MD -MP -MF $(DEPDIR)/libglpk_la-amd_postorder.Tpo -c -o libglpk_la-amd_postorder.lo `test -f 'amd/amd_postorder.c' || echo '$(srcdir)/'`amd/amd_postorder.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-amd_postorder.Tpo $(DEPDIR)/libglpk_la-amd_postorder.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='amd/amd_postorder.c' object='libglpk_la-amd_postorder.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-amd_postorder.lo `test -f 'amd/amd_postorder.c' || echo '$(srcdir)/'`amd/amd_postorder.c libglpk_la-amd_preprocess.lo: amd/amd_preprocess.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-amd_preprocess.lo -MD -MP -MF $(DEPDIR)/libglpk_la-amd_preprocess.Tpo -c -o libglpk_la-amd_preprocess.lo `test -f 'amd/amd_preprocess.c' || echo '$(srcdir)/'`amd/amd_preprocess.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-amd_preprocess.Tpo $(DEPDIR)/libglpk_la-amd_preprocess.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='amd/amd_preprocess.c' object='libglpk_la-amd_preprocess.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-amd_preprocess.lo `test -f 'amd/amd_preprocess.c' || echo '$(srcdir)/'`amd/amd_preprocess.c libglpk_la-amd_valid.lo: amd/amd_valid.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-amd_valid.lo -MD -MP -MF $(DEPDIR)/libglpk_la-amd_valid.Tpo -c -o libglpk_la-amd_valid.lo `test -f 'amd/amd_valid.c' || echo '$(srcdir)/'`amd/amd_valid.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-amd_valid.Tpo $(DEPDIR)/libglpk_la-amd_valid.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='amd/amd_valid.c' object='libglpk_la-amd_valid.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-amd_valid.lo `test -f 'amd/amd_valid.c' || echo '$(srcdir)/'`amd/amd_valid.c libglpk_la-fhv.lo: bflib/fhv.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-fhv.lo -MD -MP -MF $(DEPDIR)/libglpk_la-fhv.Tpo -c -o libglpk_la-fhv.lo `test -f 'bflib/fhv.c' || echo '$(srcdir)/'`bflib/fhv.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-fhv.Tpo $(DEPDIR)/libglpk_la-fhv.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bflib/fhv.c' object='libglpk_la-fhv.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-fhv.lo `test -f 'bflib/fhv.c' || echo '$(srcdir)/'`bflib/fhv.c libglpk_la-fhvint.lo: bflib/fhvint.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-fhvint.lo -MD -MP -MF $(DEPDIR)/libglpk_la-fhvint.Tpo -c -o libglpk_la-fhvint.lo `test -f 'bflib/fhvint.c' || echo '$(srcdir)/'`bflib/fhvint.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-fhvint.Tpo $(DEPDIR)/libglpk_la-fhvint.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bflib/fhvint.c' object='libglpk_la-fhvint.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-fhvint.lo `test -f 'bflib/fhvint.c' || echo '$(srcdir)/'`bflib/fhvint.c libglpk_la-luf.lo: bflib/luf.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-luf.lo -MD -MP -MF $(DEPDIR)/libglpk_la-luf.Tpo -c -o libglpk_la-luf.lo `test -f 'bflib/luf.c' || echo '$(srcdir)/'`bflib/luf.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-luf.Tpo $(DEPDIR)/libglpk_la-luf.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bflib/luf.c' object='libglpk_la-luf.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-luf.lo `test -f 'bflib/luf.c' || echo '$(srcdir)/'`bflib/luf.c libglpk_la-lufint.lo: bflib/lufint.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-lufint.lo -MD -MP -MF $(DEPDIR)/libglpk_la-lufint.Tpo -c -o libglpk_la-lufint.lo `test -f 'bflib/lufint.c' || echo '$(srcdir)/'`bflib/lufint.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-lufint.Tpo $(DEPDIR)/libglpk_la-lufint.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bflib/lufint.c' object='libglpk_la-lufint.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-lufint.lo `test -f 'bflib/lufint.c' || echo '$(srcdir)/'`bflib/lufint.c libglpk_la-sgf.lo: bflib/sgf.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-sgf.lo -MD -MP -MF $(DEPDIR)/libglpk_la-sgf.Tpo -c -o libglpk_la-sgf.lo `test -f 'bflib/sgf.c' || echo '$(srcdir)/'`bflib/sgf.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-sgf.Tpo $(DEPDIR)/libglpk_la-sgf.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bflib/sgf.c' object='libglpk_la-sgf.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-sgf.lo `test -f 'bflib/sgf.c' || echo '$(srcdir)/'`bflib/sgf.c libglpk_la-sva.lo: bflib/sva.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-sva.lo -MD -MP -MF $(DEPDIR)/libglpk_la-sva.Tpo -c -o libglpk_la-sva.lo `test -f 'bflib/sva.c' || echo '$(srcdir)/'`bflib/sva.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-sva.Tpo $(DEPDIR)/libglpk_la-sva.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bflib/sva.c' object='libglpk_la-sva.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-sva.lo `test -f 'bflib/sva.c' || echo '$(srcdir)/'`bflib/sva.c libglpk_la-cfg.lo: cglib/cfg.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-cfg.lo -MD -MP -MF $(DEPDIR)/libglpk_la-cfg.Tpo -c -o libglpk_la-cfg.lo `test -f 'cglib/cfg.c' || echo '$(srcdir)/'`cglib/cfg.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-cfg.Tpo $(DEPDIR)/libglpk_la-cfg.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='cglib/cfg.c' object='libglpk_la-cfg.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-cfg.lo `test -f 'cglib/cfg.c' || echo '$(srcdir)/'`cglib/cfg.c libglpk_la-cfg1.lo: cglib/cfg1.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-cfg1.lo -MD -MP -MF $(DEPDIR)/libglpk_la-cfg1.Tpo -c -o libglpk_la-cfg1.lo `test -f 'cglib/cfg1.c' || echo '$(srcdir)/'`cglib/cfg1.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-cfg1.Tpo $(DEPDIR)/libglpk_la-cfg1.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='cglib/cfg1.c' object='libglpk_la-cfg1.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-cfg1.lo `test -f 'cglib/cfg1.c' || echo '$(srcdir)/'`cglib/cfg1.c libglpk_la-colamd.lo: colamd/colamd.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-colamd.lo -MD -MP -MF $(DEPDIR)/libglpk_la-colamd.Tpo -c -o libglpk_la-colamd.lo `test -f 'colamd/colamd.c' || echo '$(srcdir)/'`colamd/colamd.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-colamd.Tpo $(DEPDIR)/libglpk_la-colamd.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='colamd/colamd.c' object='libglpk_la-colamd.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-colamd.lo `test -f 'colamd/colamd.c' || echo '$(srcdir)/'`colamd/colamd.c libglpk_la-alloc.lo: env/alloc.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-alloc.lo -MD -MP -MF $(DEPDIR)/libglpk_la-alloc.Tpo -c -o libglpk_la-alloc.lo `test -f 'env/alloc.c' || echo '$(srcdir)/'`env/alloc.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-alloc.Tpo $(DEPDIR)/libglpk_la-alloc.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='env/alloc.c' object='libglpk_la-alloc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-alloc.lo `test -f 'env/alloc.c' || echo '$(srcdir)/'`env/alloc.c libglpk_la-env.lo: env/env.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-env.lo -MD -MP -MF $(DEPDIR)/libglpk_la-env.Tpo -c -o libglpk_la-env.lo `test -f 'env/env.c' || echo '$(srcdir)/'`env/env.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-env.Tpo $(DEPDIR)/libglpk_la-env.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='env/env.c' object='libglpk_la-env.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-env.lo `test -f 'env/env.c' || echo '$(srcdir)/'`env/env.c libglpk_la-error.lo: env/error.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-error.lo -MD -MP -MF $(DEPDIR)/libglpk_la-error.Tpo -c -o libglpk_la-error.lo `test -f 'env/error.c' || echo '$(srcdir)/'`env/error.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-error.Tpo $(DEPDIR)/libglpk_la-error.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='env/error.c' object='libglpk_la-error.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-error.lo `test -f 'env/error.c' || echo '$(srcdir)/'`env/error.c libglpk_la-stdout.lo: env/stdout.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-stdout.lo -MD -MP -MF $(DEPDIR)/libglpk_la-stdout.Tpo -c -o libglpk_la-stdout.lo `test -f 'env/stdout.c' || echo '$(srcdir)/'`env/stdout.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-stdout.Tpo $(DEPDIR)/libglpk_la-stdout.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='env/stdout.c' object='libglpk_la-stdout.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-stdout.lo `test -f 'env/stdout.c' || echo '$(srcdir)/'`env/stdout.c libglpk_la-time.lo: env/time.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-time.lo -MD -MP -MF $(DEPDIR)/libglpk_la-time.Tpo -c -o libglpk_la-time.lo `test -f 'env/time.c' || echo '$(srcdir)/'`env/time.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-time.Tpo $(DEPDIR)/libglpk_la-time.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='env/time.c' object='libglpk_la-time.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-time.lo `test -f 'env/time.c' || echo '$(srcdir)/'`env/time.c libglpk_la-tls.lo: env/tls.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-tls.lo -MD -MP -MF $(DEPDIR)/libglpk_la-tls.Tpo -c -o libglpk_la-tls.lo `test -f 'env/tls.c' || echo '$(srcdir)/'`env/tls.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-tls.Tpo $(DEPDIR)/libglpk_la-tls.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='env/tls.c' object='libglpk_la-tls.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-tls.lo `test -f 'env/tls.c' || echo '$(srcdir)/'`env/tls.c libglpk_la-minisat.lo: minisat/minisat.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-minisat.lo -MD -MP -MF $(DEPDIR)/libglpk_la-minisat.Tpo -c -o libglpk_la-minisat.lo `test -f 'minisat/minisat.c' || echo '$(srcdir)/'`minisat/minisat.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-minisat.Tpo $(DEPDIR)/libglpk_la-minisat.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='minisat/minisat.c' object='libglpk_la-minisat.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-minisat.lo `test -f 'minisat/minisat.c' || echo '$(srcdir)/'`minisat/minisat.c libglpk_la-bignum.lo: misc/bignum.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-bignum.lo -MD -MP -MF $(DEPDIR)/libglpk_la-bignum.Tpo -c -o libglpk_la-bignum.lo `test -f 'misc/bignum.c' || echo '$(srcdir)/'`misc/bignum.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-bignum.Tpo $(DEPDIR)/libglpk_la-bignum.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='misc/bignum.c' object='libglpk_la-bignum.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-bignum.lo `test -f 'misc/bignum.c' || echo '$(srcdir)/'`misc/bignum.c libglpk_la-dmp.lo: misc/dmp.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-dmp.lo -MD -MP -MF $(DEPDIR)/libglpk_la-dmp.Tpo -c -o libglpk_la-dmp.lo `test -f 'misc/dmp.c' || echo '$(srcdir)/'`misc/dmp.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-dmp.Tpo $(DEPDIR)/libglpk_la-dmp.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='misc/dmp.c' object='libglpk_la-dmp.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-dmp.lo `test -f 'misc/dmp.c' || echo '$(srcdir)/'`misc/dmp.c libglpk_la-ffalg.lo: misc/ffalg.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-ffalg.lo -MD -MP -MF $(DEPDIR)/libglpk_la-ffalg.Tpo -c -o libglpk_la-ffalg.lo `test -f 'misc/ffalg.c' || echo '$(srcdir)/'`misc/ffalg.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-ffalg.Tpo $(DEPDIR)/libglpk_la-ffalg.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='misc/ffalg.c' object='libglpk_la-ffalg.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-ffalg.lo `test -f 'misc/ffalg.c' || echo '$(srcdir)/'`misc/ffalg.c libglpk_la-jd.lo: misc/jd.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-jd.lo -MD -MP -MF $(DEPDIR)/libglpk_la-jd.Tpo -c -o libglpk_la-jd.lo `test -f 'misc/jd.c' || echo '$(srcdir)/'`misc/jd.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-jd.Tpo $(DEPDIR)/libglpk_la-jd.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='misc/jd.c' object='libglpk_la-jd.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-jd.lo `test -f 'misc/jd.c' || echo '$(srcdir)/'`misc/jd.c libglpk_la-keller.lo: misc/keller.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-keller.lo -MD -MP -MF $(DEPDIR)/libglpk_la-keller.Tpo -c -o libglpk_la-keller.lo `test -f 'misc/keller.c' || echo '$(srcdir)/'`misc/keller.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-keller.Tpo $(DEPDIR)/libglpk_la-keller.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='misc/keller.c' object='libglpk_la-keller.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-keller.lo `test -f 'misc/keller.c' || echo '$(srcdir)/'`misc/keller.c libglpk_la-mc13d.lo: misc/mc13d.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-mc13d.lo -MD -MP -MF $(DEPDIR)/libglpk_la-mc13d.Tpo -c -o libglpk_la-mc13d.lo `test -f 'misc/mc13d.c' || echo '$(srcdir)/'`misc/mc13d.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-mc13d.Tpo $(DEPDIR)/libglpk_la-mc13d.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='misc/mc13d.c' object='libglpk_la-mc13d.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-mc13d.lo `test -f 'misc/mc13d.c' || echo '$(srcdir)/'`misc/mc13d.c libglpk_la-mc21a.lo: misc/mc21a.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-mc21a.lo -MD -MP -MF $(DEPDIR)/libglpk_la-mc21a.Tpo -c -o libglpk_la-mc21a.lo `test -f 'misc/mc21a.c' || echo '$(srcdir)/'`misc/mc21a.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-mc21a.Tpo $(DEPDIR)/libglpk_la-mc21a.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='misc/mc21a.c' object='libglpk_la-mc21a.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-mc21a.lo `test -f 'misc/mc21a.c' || echo '$(srcdir)/'`misc/mc21a.c libglpk_la-okalg.lo: misc/okalg.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-okalg.lo -MD -MP -MF $(DEPDIR)/libglpk_la-okalg.Tpo -c -o libglpk_la-okalg.lo `test -f 'misc/okalg.c' || echo '$(srcdir)/'`misc/okalg.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-okalg.Tpo $(DEPDIR)/libglpk_la-okalg.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='misc/okalg.c' object='libglpk_la-okalg.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-okalg.lo `test -f 'misc/okalg.c' || echo '$(srcdir)/'`misc/okalg.c libglpk_la-qmd.lo: misc/qmd.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-qmd.lo -MD -MP -MF $(DEPDIR)/libglpk_la-qmd.Tpo -c -o libglpk_la-qmd.lo `test -f 'misc/qmd.c' || echo '$(srcdir)/'`misc/qmd.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-qmd.Tpo $(DEPDIR)/libglpk_la-qmd.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='misc/qmd.c' object='libglpk_la-qmd.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-qmd.lo `test -f 'misc/qmd.c' || echo '$(srcdir)/'`misc/qmd.c libglpk_la-relax4.lo: misc/relax4.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-relax4.lo -MD -MP -MF $(DEPDIR)/libglpk_la-relax4.Tpo -c -o libglpk_la-relax4.lo `test -f 'misc/relax4.c' || echo '$(srcdir)/'`misc/relax4.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-relax4.Tpo $(DEPDIR)/libglpk_la-relax4.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='misc/relax4.c' object='libglpk_la-relax4.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-relax4.lo `test -f 'misc/relax4.c' || echo '$(srcdir)/'`misc/relax4.c libglpk_la-rng.lo: misc/rng.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-rng.lo -MD -MP -MF $(DEPDIR)/libglpk_la-rng.Tpo -c -o libglpk_la-rng.lo `test -f 'misc/rng.c' || echo '$(srcdir)/'`misc/rng.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-rng.Tpo $(DEPDIR)/libglpk_la-rng.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='misc/rng.c' object='libglpk_la-rng.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-rng.lo `test -f 'misc/rng.c' || echo '$(srcdir)/'`misc/rng.c libglpk_la-rng1.lo: misc/rng1.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-rng1.lo -MD -MP -MF $(DEPDIR)/libglpk_la-rng1.Tpo -c -o libglpk_la-rng1.lo `test -f 'misc/rng1.c' || echo '$(srcdir)/'`misc/rng1.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-rng1.Tpo $(DEPDIR)/libglpk_la-rng1.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='misc/rng1.c' object='libglpk_la-rng1.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-rng1.lo `test -f 'misc/rng1.c' || echo '$(srcdir)/'`misc/rng1.c libglpk_la-triang.lo: misc/triang.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-triang.lo -MD -MP -MF $(DEPDIR)/libglpk_la-triang.Tpo -c -o libglpk_la-triang.lo `test -f 'misc/triang.c' || echo '$(srcdir)/'`misc/triang.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-triang.Tpo $(DEPDIR)/libglpk_la-triang.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='misc/triang.c' object='libglpk_la-triang.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-triang.lo `test -f 'misc/triang.c' || echo '$(srcdir)/'`misc/triang.c libglpk_la-wclique.lo: misc/wclique.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-wclique.lo -MD -MP -MF $(DEPDIR)/libglpk_la-wclique.Tpo -c -o libglpk_la-wclique.lo `test -f 'misc/wclique.c' || echo '$(srcdir)/'`misc/wclique.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-wclique.Tpo $(DEPDIR)/libglpk_la-wclique.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='misc/wclique.c' object='libglpk_la-wclique.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-wclique.lo `test -f 'misc/wclique.c' || echo '$(srcdir)/'`misc/wclique.c libglpk_la-wclique1.lo: misc/wclique1.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-wclique1.lo -MD -MP -MF $(DEPDIR)/libglpk_la-wclique1.Tpo -c -o libglpk_la-wclique1.lo `test -f 'misc/wclique1.c' || echo '$(srcdir)/'`misc/wclique1.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-wclique1.Tpo $(DEPDIR)/libglpk_la-wclique1.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='misc/wclique1.c' object='libglpk_la-wclique1.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-wclique1.lo `test -f 'misc/wclique1.c' || echo '$(srcdir)/'`misc/wclique1.c libglpk_la-proxy.lo: proxy/proxy.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-proxy.lo -MD -MP -MF $(DEPDIR)/libglpk_la-proxy.Tpo -c -o libglpk_la-proxy.lo `test -f 'proxy/proxy.c' || echo '$(srcdir)/'`proxy/proxy.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-proxy.Tpo $(DEPDIR)/libglpk_la-proxy.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='proxy/proxy.c' object='libglpk_la-proxy.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-proxy.lo `test -f 'proxy/proxy.c' || echo '$(srcdir)/'`proxy/proxy.c libglpk_la-proxy1.lo: proxy/proxy1.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-proxy1.lo -MD -MP -MF $(DEPDIR)/libglpk_la-proxy1.Tpo -c -o libglpk_la-proxy1.lo `test -f 'proxy/proxy1.c' || echo '$(srcdir)/'`proxy/proxy1.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-proxy1.Tpo $(DEPDIR)/libglpk_la-proxy1.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='proxy/proxy1.c' object='libglpk_la-proxy1.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-proxy1.lo `test -f 'proxy/proxy1.c' || echo '$(srcdir)/'`proxy/proxy1.c libglpk_la-adler32.lo: zlib/adler32.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-adler32.lo -MD -MP -MF $(DEPDIR)/libglpk_la-adler32.Tpo -c -o libglpk_la-adler32.lo `test -f 'zlib/adler32.c' || echo '$(srcdir)/'`zlib/adler32.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-adler32.Tpo $(DEPDIR)/libglpk_la-adler32.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zlib/adler32.c' object='libglpk_la-adler32.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-adler32.lo `test -f 'zlib/adler32.c' || echo '$(srcdir)/'`zlib/adler32.c libglpk_la-compress.lo: zlib/compress.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-compress.lo -MD -MP -MF $(DEPDIR)/libglpk_la-compress.Tpo -c -o libglpk_la-compress.lo `test -f 'zlib/compress.c' || echo '$(srcdir)/'`zlib/compress.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-compress.Tpo $(DEPDIR)/libglpk_la-compress.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zlib/compress.c' object='libglpk_la-compress.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-compress.lo `test -f 'zlib/compress.c' || echo '$(srcdir)/'`zlib/compress.c libglpk_la-crc32.lo: zlib/crc32.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-crc32.lo -MD -MP -MF $(DEPDIR)/libglpk_la-crc32.Tpo -c -o libglpk_la-crc32.lo `test -f 'zlib/crc32.c' || echo '$(srcdir)/'`zlib/crc32.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-crc32.Tpo $(DEPDIR)/libglpk_la-crc32.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zlib/crc32.c' object='libglpk_la-crc32.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-crc32.lo `test -f 'zlib/crc32.c' || echo '$(srcdir)/'`zlib/crc32.c libglpk_la-deflate.lo: zlib/deflate.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-deflate.lo -MD -MP -MF $(DEPDIR)/libglpk_la-deflate.Tpo -c -o libglpk_la-deflate.lo `test -f 'zlib/deflate.c' || echo '$(srcdir)/'`zlib/deflate.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-deflate.Tpo $(DEPDIR)/libglpk_la-deflate.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zlib/deflate.c' object='libglpk_la-deflate.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-deflate.lo `test -f 'zlib/deflate.c' || echo '$(srcdir)/'`zlib/deflate.c libglpk_la-gzclose.lo: zlib/gzclose.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-gzclose.lo -MD -MP -MF $(DEPDIR)/libglpk_la-gzclose.Tpo -c -o libglpk_la-gzclose.lo `test -f 'zlib/gzclose.c' || echo '$(srcdir)/'`zlib/gzclose.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-gzclose.Tpo $(DEPDIR)/libglpk_la-gzclose.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zlib/gzclose.c' object='libglpk_la-gzclose.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-gzclose.lo `test -f 'zlib/gzclose.c' || echo '$(srcdir)/'`zlib/gzclose.c libglpk_la-gzlib.lo: zlib/gzlib.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-gzlib.lo -MD -MP -MF $(DEPDIR)/libglpk_la-gzlib.Tpo -c -o libglpk_la-gzlib.lo `test -f 'zlib/gzlib.c' || echo '$(srcdir)/'`zlib/gzlib.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-gzlib.Tpo $(DEPDIR)/libglpk_la-gzlib.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zlib/gzlib.c' object='libglpk_la-gzlib.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-gzlib.lo `test -f 'zlib/gzlib.c' || echo '$(srcdir)/'`zlib/gzlib.c libglpk_la-gzread.lo: zlib/gzread.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-gzread.lo -MD -MP -MF $(DEPDIR)/libglpk_la-gzread.Tpo -c -o libglpk_la-gzread.lo `test -f 'zlib/gzread.c' || echo '$(srcdir)/'`zlib/gzread.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-gzread.Tpo $(DEPDIR)/libglpk_la-gzread.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zlib/gzread.c' object='libglpk_la-gzread.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-gzread.lo `test -f 'zlib/gzread.c' || echo '$(srcdir)/'`zlib/gzread.c libglpk_la-gzwrite.lo: zlib/gzwrite.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-gzwrite.lo -MD -MP -MF $(DEPDIR)/libglpk_la-gzwrite.Tpo -c -o libglpk_la-gzwrite.lo `test -f 'zlib/gzwrite.c' || echo '$(srcdir)/'`zlib/gzwrite.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-gzwrite.Tpo $(DEPDIR)/libglpk_la-gzwrite.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zlib/gzwrite.c' object='libglpk_la-gzwrite.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-gzwrite.lo `test -f 'zlib/gzwrite.c' || echo '$(srcdir)/'`zlib/gzwrite.c libglpk_la-inffast.lo: zlib/inffast.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-inffast.lo -MD -MP -MF $(DEPDIR)/libglpk_la-inffast.Tpo -c -o libglpk_la-inffast.lo `test -f 'zlib/inffast.c' || echo '$(srcdir)/'`zlib/inffast.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-inffast.Tpo $(DEPDIR)/libglpk_la-inffast.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zlib/inffast.c' object='libglpk_la-inffast.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-inffast.lo `test -f 'zlib/inffast.c' || echo '$(srcdir)/'`zlib/inffast.c libglpk_la-inflate.lo: zlib/inflate.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-inflate.lo -MD -MP -MF $(DEPDIR)/libglpk_la-inflate.Tpo -c -o libglpk_la-inflate.lo `test -f 'zlib/inflate.c' || echo '$(srcdir)/'`zlib/inflate.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-inflate.Tpo $(DEPDIR)/libglpk_la-inflate.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zlib/inflate.c' object='libglpk_la-inflate.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-inflate.lo `test -f 'zlib/inflate.c' || echo '$(srcdir)/'`zlib/inflate.c libglpk_la-inftrees.lo: zlib/inftrees.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-inftrees.lo -MD -MP -MF $(DEPDIR)/libglpk_la-inftrees.Tpo -c -o libglpk_la-inftrees.lo `test -f 'zlib/inftrees.c' || echo '$(srcdir)/'`zlib/inftrees.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-inftrees.Tpo $(DEPDIR)/libglpk_la-inftrees.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zlib/inftrees.c' object='libglpk_la-inftrees.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-inftrees.lo `test -f 'zlib/inftrees.c' || echo '$(srcdir)/'`zlib/inftrees.c libglpk_la-trees.lo: zlib/trees.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-trees.lo -MD -MP -MF $(DEPDIR)/libglpk_la-trees.Tpo -c -o libglpk_la-trees.lo `test -f 'zlib/trees.c' || echo '$(srcdir)/'`zlib/trees.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-trees.Tpo $(DEPDIR)/libglpk_la-trees.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zlib/trees.c' object='libglpk_la-trees.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-trees.lo `test -f 'zlib/trees.c' || echo '$(srcdir)/'`zlib/trees.c libglpk_la-uncompr.lo: zlib/uncompr.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-uncompr.lo -MD -MP -MF $(DEPDIR)/libglpk_la-uncompr.Tpo -c -o libglpk_la-uncompr.lo `test -f 'zlib/uncompr.c' || echo '$(srcdir)/'`zlib/uncompr.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-uncompr.Tpo $(DEPDIR)/libglpk_la-uncompr.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zlib/uncompr.c' object='libglpk_la-uncompr.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-uncompr.lo `test -f 'zlib/uncompr.c' || echo '$(srcdir)/'`zlib/uncompr.c libglpk_la-zio.lo: zlib/zio.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-zio.lo -MD -MP -MF $(DEPDIR)/libglpk_la-zio.Tpo -c -o libglpk_la-zio.lo `test -f 'zlib/zio.c' || echo '$(srcdir)/'`zlib/zio.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-zio.Tpo $(DEPDIR)/libglpk_la-zio.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zlib/zio.c' object='libglpk_la-zio.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-zio.lo `test -f 'zlib/zio.c' || echo '$(srcdir)/'`zlib/zio.c libglpk_la-zutil.lo: zlib/zutil.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libglpk_la-zutil.lo -MD -MP -MF $(DEPDIR)/libglpk_la-zutil.Tpo -c -o libglpk_la-zutil.lo `test -f 'zlib/zutil.c' || echo '$(srcdir)/'`zlib/zutil.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libglpk_la-zutil.Tpo $(DEPDIR)/libglpk_la-zutil.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='zlib/zutil.c' object='libglpk_la-zutil.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libglpk_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libglpk_la-zutil.lo `test -f 'zlib/zutil.c' || echo '$(srcdir)/'`zlib/zutil.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-includeHEADERS: $(include_HEADERS) @$(NORMAL_INSTALL) @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ done uninstall-includeHEADERS: @$(NORMAL_UNINSTALL) @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: $(HEADERS) $(SOURCES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-includeHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool cscopelist ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-includeHEADERS install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-includeHEADERS \ uninstall-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: Rglpk/src/GLPK/qmd.h0000644000176000001440000000415712245352174013653 0ustar ripleyusers/* qmd.h (quotient minimum degree algorithm) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2001, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef QMD_H #define QMD_H #define genqmd _glp_genqmd void genqmd(int *neqns, int xadj[], int adjncy[], int perm[], int invp[], int deg[], int marker[], int rchset[], int nbrhd[], int qsize[], int qlink[], int *nofsub); /* GENeral Quotient Minimum Degree algorithm */ #define qmdrch _glp_qmdrch void qmdrch(int *root, int xadj[], int adjncy[], int deg[], int marker[], int *rchsze, int rchset[], int *nhdsze, int nbrhd[]); /* Quotient MD ReaCHable set */ #define qmdqt _glp_qmdqt void qmdqt(int *root, int xadj[], int adjncy[], int marker[], int *rchsze, int rchset[], int nbrhd[]); /* Quotient MD Quotient graph Transformation */ #define qmdupd _glp_qmdupd void qmdupd(int xadj[], int adjncy[], int *nlist, int list[], int deg[], int qsize[], int qlink[], int marker[], int rchset[], int nbrhd[]); /* Quotient MD UPDate */ #define qmdmrg _glp_qmdmrg void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[], int qlink[], int marker[], int *deg0, int *nhdsze, int nbrhd[], int rchset[], int ovrlp[]); /* Quotient MD MeRGe */ #endif /* eof */ Rglpk/src/GLPK/glpnpp01.c0000644000176000001440000007127712245352174014535 0ustar ripleyusers/* glpnpp01.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpnpp.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 */ Rglpk/src/GLPK/glpmpl06.c0000644000176000001440000007515612245352174014535 0ustar ripleyusers/* glpmpl06.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #define _GLPSTD_ERRNO #define _GLPSTD_STDIO #include "glpmpl.h" #include "glpsql.h" /**********************************************************************/ #define CSV_FIELD_MAX 50 /* maximal number of fields in record */ #define CSV_FDLEN_MAX 100 /* maximal field length */ struct csv { /* comma-separated values file */ int mode; /* 'R' = reading; 'W' = writing */ char *fname; /* name of csv file */ FILE *fp; /* stream assigned to csv file */ jmp_buf jump; /* address for non-local go to in case of error */ int count; /* record count */ /*--------------------------------------------------------------*/ /* used only for input csv file */ int c; /* current character or EOF */ int what; /* current marker: */ #define CSV_EOF 0 /* end-of-file */ #define CSV_EOR 1 /* end-of-record */ #define CSV_NUM 2 /* floating-point number */ #define CSV_STR 3 /* character string */ char field[CSV_FDLEN_MAX+1]; /* current field just read */ int nf; /* number of fields in the csv file */ int ref[1+CSV_FIELD_MAX]; /* ref[k] = k', if k-th field of the csv file corresponds to k'-th field in the table statement; if ref[k] = 0, k-th field of the csv file is ignored */ #if 1 /* 01/VI-2010 */ int nskip; /* number of comment records preceding the header record */ #endif }; #undef read_char static void read_char(struct csv *csv) { /* read character from csv data file */ int c; xassert(csv->c != EOF); if (csv->c == '\n') csv->count++; loop: c = fgetc(csv->fp); if (ferror(csv->fp)) { xprintf("%s:%d: read error - %s\n", csv->fname, csv->count, strerror(errno)); longjmp(csv->jump, 0); } if (feof(csv->fp)) { if (csv->c == '\n') { csv->count--; c = EOF; } else { xprintf("%s:%d: warning: missing final end-of-line\n", csv->fname, csv->count); c = '\n'; } } else if (c == '\r') goto loop; else if (c == '\n') ; else if (iscntrl(c)) { xprintf("%s:%d: invalid control character 0x%02X\n", csv->fname, csv->count, c); longjmp(csv->jump, 0); } csv->c = c; return; } static void read_field(struct csv *csv) { /* read field from csv data file */ /* check for end of file */ if (csv->c == EOF) { csv->what = CSV_EOF; strcpy(csv->field, "EOF"); goto done; } /* check for end of record */ if (csv->c == '\n') { csv->what = CSV_EOR; strcpy(csv->field, "EOR"); read_char(csv); if (csv->c == ',') err1: { xprintf("%s:%d: empty field not allowed\n", csv->fname, csv->count); longjmp(csv->jump, 0); } if (csv->c == '\n') { xprintf("%s:%d: empty record not allowed\n", csv->fname, csv->count); longjmp(csv->jump, 0); } #if 1 /* 01/VI-2010 */ /* skip comment records; may appear only before the very first record containing field names */ if (csv->c == '#' && csv->count == 1) { while (csv->c == '#') { while (csv->c != '\n') read_char(csv); read_char(csv); csv->nskip++; } } #endif goto done; } /* skip comma before next field */ if (csv->c == ',') read_char(csv); /* read field */ if (csv->c == '\'' || csv->c == '"') { /* read a field enclosed in quotes */ int quote = csv->c, len = 0; csv->what = CSV_STR; /* skip opening quote */ read_char(csv); /* read field characters within quotes */ for (;;) { /* check for closing quote and read it */ if (csv->c == quote) { read_char(csv); if (csv->c == quote) ; else if (csv->c == ',' || csv->c == '\n') break; else { xprintf("%s:%d: invalid field\n", csv->fname, csv->count); longjmp(csv->jump, 0); } } /* check the current field length */ if (len == CSV_FDLEN_MAX) err2: { xprintf("%s:%d: field too long\n", csv->fname, csv->count); longjmp(csv->jump, 0); } /* add the current character to the field */ csv->field[len++] = (char)csv->c; /* read the next character */ read_char(csv); } /* the field has been read */ if (len == 0) goto err1; csv->field[len] = '\0'; } else { /* read a field not enclosed in quotes */ int len = 0; double temp; csv->what = CSV_NUM; while (!(csv->c == ',' || csv->c == '\n')) { /* quotes within the field are not allowed */ if (csv->c == '\'' || csv->c == '"') { xprintf("%s:%d: invalid use of single or double quote wi" "thin field\n", csv->fname, csv->count); longjmp(csv->jump, 0); } /* check the current field length */ if (len == CSV_FDLEN_MAX) goto err2; /* add the current character to the field */ csv->field[len++] = (char)csv->c; /* read the next character */ read_char(csv); } /* the field has been read */ if (len == 0) goto err1; csv->field[len] = '\0'; /* check the field type */ if (str2num(csv->field, &temp)) csv->what = CSV_STR; } done: return; } static struct csv *csv_open_file(TABDCA *dca, int mode) { /* open csv data file */ struct csv *csv; /* create control structure */ csv = xmalloc(sizeof(struct csv)); csv->mode = mode; csv->fname = NULL; csv->fp = NULL; if (setjmp(csv->jump)) goto fail; csv->count = 0; csv->c = '\n'; csv->what = 0; csv->field[0] = '\0'; csv->nf = 0; /* try to open the csv data file */ if (mpl_tab_num_args(dca) < 2) { xprintf("csv_driver: file name not specified\n"); longjmp(csv->jump, 0); } csv->fname = xmalloc(strlen(mpl_tab_get_arg(dca, 2))+1); strcpy(csv->fname, mpl_tab_get_arg(dca, 2)); if (mode == 'R') { /* open the file for reading */ int k; csv->fp = fopen(csv->fname, "r"); if (csv->fp == NULL) { xprintf("csv_driver: unable to open %s - %s\n", csv->fname, strerror(errno)); longjmp(csv->jump, 0); } #if 1 /* 01/VI-2010 */ csv->nskip = 0; #endif /* skip fake new-line */ read_field(csv); xassert(csv->what == CSV_EOR); /* read field names */ xassert(csv->nf == 0); for (;;) { read_field(csv); if (csv->what == CSV_EOR) break; if (csv->what != CSV_STR) { xprintf("%s:%d: invalid field name\n", csv->fname, csv->count); longjmp(csv->jump, 0); } if (csv->nf == CSV_FIELD_MAX) { xprintf("%s:%d: too many fields\n", csv->fname, csv->count); longjmp(csv->jump, 0); } csv->nf++; /* find corresponding field in the table statement */ for (k = mpl_tab_num_flds(dca); k >= 1; k--) { if (strcmp(mpl_tab_get_name(dca, k), csv->field) == 0) break; } csv->ref[csv->nf] = k; } /* find dummy RECNO field in the table statement */ for (k = mpl_tab_num_flds(dca); k >= 1; k--) if (strcmp(mpl_tab_get_name(dca, k), "RECNO") == 0) break; csv->ref[0] = k; } else if (mode == 'W') { /* open the file for writing */ int k, nf; csv->fp = fopen(csv->fname, "w"); if (csv->fp == NULL) { xprintf("csv_driver: unable to create %s - %s\n", csv->fname, strerror(errno)); longjmp(csv->jump, 0); } /* write field names */ nf = mpl_tab_num_flds(dca); for (k = 1; k <= nf; k++) fprintf(csv->fp, "%s%c", mpl_tab_get_name(dca, k), k < nf ? ',' : '\n'); csv->count++; } else xassert(mode != mode); /* the file has been open */ return csv; fail: /* the file cannot be open */ if (csv->fname != NULL) xfree(csv->fname); if (csv->fp != NULL) fclose(csv->fp); xfree(csv); return NULL; } static int csv_read_record(TABDCA *dca, struct csv *csv) { /* read next record from csv data file */ int k, ret = 0; xassert(csv->mode == 'R'); if (setjmp(csv->jump)) { ret = 1; goto done; } /* read dummy RECNO field */ if (csv->ref[0] > 0) #if 0 /* 01/VI-2010 */ mpl_tab_set_num(dca, csv->ref[0], csv->count-1); #else mpl_tab_set_num(dca, csv->ref[0], csv->count-csv->nskip-1); #endif /* read fields */ for (k = 1; k <= csv->nf; k++) { read_field(csv); if (csv->what == CSV_EOF) { /* end-of-file reached */ xassert(k == 1); ret = -1; goto done; } else if (csv->what == CSV_EOR) { /* end-of-record reached */ int lack = csv->nf - k + 1; if (lack == 1) xprintf("%s:%d: one field missing\n", csv->fname, csv->count); else xprintf("%s:%d: %d fields missing\n", csv->fname, csv->count, lack); longjmp(csv->jump, 0); } else if (csv->what == CSV_NUM) { /* floating-point number */ if (csv->ref[k] > 0) { double num; xassert(str2num(csv->field, &num) == 0); mpl_tab_set_num(dca, csv->ref[k], num); } } else if (csv->what == CSV_STR) { /* character string */ if (csv->ref[k] > 0) mpl_tab_set_str(dca, csv->ref[k], csv->field); } else xassert(csv != csv); } /* now there must be NL */ read_field(csv); xassert(csv->what != CSV_EOF); if (csv->what != CSV_EOR) { xprintf("%s:%d: too many fields\n", csv->fname, csv->count); longjmp(csv->jump, 0); } done: return ret; } static int csv_write_record(TABDCA *dca, struct csv *csv) { /* write next record to csv data file */ int k, nf, ret = 0; const char *c; xassert(csv->mode == 'W'); nf = mpl_tab_num_flds(dca); for (k = 1; k <= nf; k++) { switch (mpl_tab_get_type(dca, k)) { case 'N': fprintf(csv->fp, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k)); break; case 'S': fputc('"', csv->fp); for (c = mpl_tab_get_str(dca, k); *c != '\0'; c++) { if (*c == '"') fputc('"', csv->fp), fputc('"', csv->fp); else fputc(*c, csv->fp); } fputc('"', csv->fp); break; default: xassert(dca != dca); } fputc(k < nf ? ',' : '\n', csv->fp); } csv->count++; if (ferror(csv->fp)) { xprintf("%s:%d: write error - %s\n", csv->fname, csv->count, strerror(errno)); ret = 1; } return ret; } static int csv_close_file(TABDCA *dca, struct csv *csv) { /* close csv data file */ int ret = 0; xassert(dca == dca); if (csv->mode == 'W') { fflush(csv->fp); if (ferror(csv->fp)) { xprintf("%s:%d: write error - %s\n", csv->fname, csv->count, strerror(errno)); ret = 1; } } xfree(csv->fname); fclose(csv->fp); xfree(csv); return ret; } /**********************************************************************/ #define DBF_FIELD_MAX 50 /* maximal number of fields in record */ #define DBF_FDLEN_MAX 100 /* maximal field length */ struct dbf { /* xBASE data file */ int mode; /* 'R' = reading; 'W' = writing */ char *fname; /* name of xBASE file */ FILE *fp; /* stream assigned to xBASE file */ jmp_buf jump; /* address for non-local go to in case of error */ int offset; /* offset of a byte to be read next */ int count; /* record count */ int nf; /* number of fields */ int ref[1+DBF_FIELD_MAX]; /* ref[k] = k', if k-th field of the csv file corresponds to k'-th field in the table statement; if ref[k] = 0, k-th field of the csv file is ignored */ int type[1+DBF_FIELD_MAX]; /* type[k] is type of k-th field */ int len[1+DBF_FIELD_MAX]; /* len[k] is length of k-th field */ int prec[1+DBF_FIELD_MAX]; /* prec[k] is precision of k-th field */ }; static int read_byte(struct dbf *dbf) { /* read byte from xBASE data file */ int b; b = fgetc(dbf->fp); if (ferror(dbf->fp)) { xprintf("%s:0x%X: read error - %s\n", dbf->fname, dbf->offset, strerror(errno)); longjmp(dbf->jump, 0); } if (feof(dbf->fp)) { xprintf("%s:0x%X: unexpected end of file\n", dbf->fname, dbf->offset); longjmp(dbf->jump, 0); } xassert(0x00 <= b && b <= 0xFF); dbf->offset++; return b; } static void read_header(TABDCA *dca, struct dbf *dbf) { /* read xBASE data file header */ int b, j, k, recl; char name[10+1]; /* (ignored) */ for (j = 1; j <= 10; j++) read_byte(dbf); /* length of each record, in bytes */ recl = read_byte(dbf); recl += read_byte(dbf) << 8; /* (ignored) */ for (j = 1; j <= 20; j++) read_byte(dbf); /* field descriptor array */ xassert(dbf->nf == 0); for (;;) { /* check for end of array */ b = read_byte(dbf); if (b == 0x0D) break; if (dbf->nf == DBF_FIELD_MAX) { xprintf("%s:0x%X: too many fields\n", dbf->fname, dbf->offset); longjmp(dbf->jump, 0); } dbf->nf++; /* field name */ name[0] = (char)b; for (j = 1; j < 10; j++) { b = read_byte(dbf); name[j] = (char)b; } name[10] = '\0'; b = read_byte(dbf); if (b != 0x00) { xprintf("%s:0x%X: invalid field name\n", dbf->fname, dbf->offset); longjmp(dbf->jump, 0); } /* find corresponding field in the table statement */ for (k = mpl_tab_num_flds(dca); k >= 1; k--) if (strcmp(mpl_tab_get_name(dca, k), name) == 0) break; dbf->ref[dbf->nf] = k; /* field type */ b = read_byte(dbf); if (!(b == 'C' || b == 'N')) { xprintf("%s:0x%X: invalid field type\n", dbf->fname, dbf->offset); longjmp(dbf->jump, 0); } dbf->type[dbf->nf] = b; /* (ignored) */ for (j = 1; j <= 4; j++) read_byte(dbf); /* field length */ b = read_byte(dbf); if (b == 0) { xprintf("%s:0x%X: invalid field length\n", dbf->fname, dbf->offset); longjmp(dbf->jump, 0); } if (b > DBF_FDLEN_MAX) { xprintf("%s:0x%X: field too long\n", dbf->fname, dbf->offset); longjmp(dbf->jump, 0); } dbf->len[dbf->nf] = b; recl -= b; /* (ignored) */ for (j = 1; j <= 15; j++) read_byte(dbf); } if (recl != 1) { xprintf("%s:0x%X: invalid file header\n", dbf->fname, dbf->offset); longjmp(dbf->jump, 0); } /* find dummy RECNO field in the table statement */ for (k = mpl_tab_num_flds(dca); k >= 1; k--) if (strcmp(mpl_tab_get_name(dca, k), "RECNO") == 0) break; dbf->ref[0] = k; return; } static void parse_third_arg(TABDCA *dca, struct dbf *dbf) { /* parse xBASE file format (third argument) */ int j, k, temp; const char *arg; dbf->nf = mpl_tab_num_flds(dca); arg = mpl_tab_get_arg(dca, 3), j = 0; for (k = 1; k <= dbf->nf; k++) { /* parse specification of k-th field */ if (arg[j] == '\0') { xprintf("xBASE driver: field %s: specification missing\n", mpl_tab_get_name(dca, k)); longjmp(dbf->jump, 0); } /* parse field type */ if (arg[j] == 'C' || arg[j] == 'N') dbf->type[k] = arg[j], j++; else { xprintf("xBASE driver: field %s: invalid field type\n", mpl_tab_get_name(dca, k)); longjmp(dbf->jump, 0); } /* check for left parenthesis */ if (arg[j] == '(') j++; else err: { xprintf("xBASE driver: field %s: invalid field format\n", mpl_tab_get_name(dca, k)); longjmp(dbf->jump, 0); } /* parse field length */ temp = 0; while (isdigit(arg[j])) { if (temp > DBF_FDLEN_MAX) break; temp = 10 * temp + (arg[j] - '0'), j++; } if (!(1 <= temp && temp <= DBF_FDLEN_MAX)) { xprintf("xBASE driver: field %s: invalid field length\n", mpl_tab_get_name(dca, k)); longjmp(dbf->jump, 0); } dbf->len[k] = temp; /* parse optional field precision */ if (dbf->type[k] == 'N' && arg[j] == ',') { j++; temp = 0; while (isdigit(arg[j])) { if (temp > dbf->len[k]) break; temp = 10 * temp + (arg[j] - '0'), j++; } if (temp > dbf->len[k]) { xprintf("xBASE driver: field %s: invalid field precision" "\n", mpl_tab_get_name(dca, k)); longjmp(dbf->jump, 0); } dbf->prec[k] = temp; } else dbf->prec[k] = 0; /* check for right parenthesis */ if (arg[j] == ')') j++; else goto err; } /* ignore other specifications */ return; } static void write_byte(struct dbf *dbf, int b) { /* write byte to xBASE data file */ fputc(b, dbf->fp); dbf->offset++; return; } static void write_header(TABDCA *dca, struct dbf *dbf) { /* write xBASE data file header */ int j, k, temp; const char *name; /* version number */ write_byte(dbf, 0x03 /* file without DBT */); /* date of last update (YYMMDD) */ write_byte(dbf, 70 /* 1970 */); write_byte(dbf, 1 /* January */); write_byte(dbf, 1 /* 1st */); /* number of records (unknown so far) */ for (j = 1; j <= 4; j++) write_byte(dbf, 0xFF); /* length of the header, in bytes */ temp = 32 + dbf->nf * 32 + 1; write_byte(dbf, temp); write_byte(dbf, temp >> 8); /* length of each record, in bytes */ temp = 1; for (k = 1; k <= dbf->nf; k++) temp += dbf->len[k]; write_byte(dbf, temp); write_byte(dbf, temp >> 8); /* (reserved) */ for (j = 1; j <= 20; j++) write_byte(dbf, 0x00); /* field descriptor array */ for (k = 1; k <= dbf->nf; k++) { /* field name (terminated by 0x00) */ name = mpl_tab_get_name(dca, k); for (j = 0; j < 10 && name[j] != '\0'; j++) write_byte(dbf, name[j]); for (j = j; j < 11; j++) write_byte(dbf, 0x00); /* field type */ write_byte(dbf, dbf->type[k]); /* (reserved) */ for (j = 1; j <= 4; j++) write_byte(dbf, 0x00); /* field length */ write_byte(dbf, dbf->len[k]); /* field precision */ write_byte(dbf, dbf->prec[k]); /* (reserved) */ for (j = 1; j <= 14; j++) write_byte(dbf, 0x00); } /* end of header */ write_byte(dbf, 0x0D); return; } static struct dbf *dbf_open_file(TABDCA *dca, int mode) { /* open xBASE data file */ struct dbf *dbf; /* create control structure */ dbf = xmalloc(sizeof(struct dbf)); dbf->mode = mode; dbf->fname = NULL; dbf->fp = NULL; if (setjmp(dbf->jump)) goto fail; dbf->offset = 0; dbf->count = 0; dbf->nf = 0; /* try to open the xBASE data file */ if (mpl_tab_num_args(dca) < 2) { xprintf("xBASE driver: file name not specified\n"); longjmp(dbf->jump, 0); } dbf->fname = xmalloc(strlen(mpl_tab_get_arg(dca, 2))+1); strcpy(dbf->fname, mpl_tab_get_arg(dca, 2)); if (mode == 'R') { /* open the file for reading */ dbf->fp = fopen(dbf->fname, "rb"); if (dbf->fp == NULL) { xprintf("xBASE driver: unable to open %s - %s\n", dbf->fname, strerror(errno)); longjmp(dbf->jump, 0); } read_header(dca, dbf); } else if (mode == 'W') { /* open the file for writing */ if (mpl_tab_num_args(dca) < 3) { xprintf("xBASE driver: file format not specified\n"); longjmp(dbf->jump, 0); } parse_third_arg(dca, dbf); dbf->fp = fopen(dbf->fname, "wb"); if (dbf->fp == NULL) { xprintf("xBASE driver: unable to create %s - %s\n", dbf->fname, strerror(errno)); longjmp(dbf->jump, 0); } write_header(dca, dbf); } else xassert(mode != mode); /* the file has been open */ return dbf; fail: /* the file cannot be open */ if (dbf->fname != NULL) xfree(dbf->fname); if (dbf->fp != NULL) fclose(dbf->fp); xfree(dbf); return NULL; } static int dbf_read_record(TABDCA *dca, struct dbf *dbf) { /* read next record from xBASE data file */ int b, j, k, ret = 0; char buf[DBF_FDLEN_MAX+1]; xassert(dbf->mode == 'R'); if (setjmp(dbf->jump)) { ret = 1; goto done; } /* check record flag */ b = read_byte(dbf); if (b == 0x1A) { /* end of data */ ret = -1; goto done; } if (b != 0x20) { xprintf("%s:0x%X: invalid record flag\n", dbf->fname, dbf->offset); longjmp(dbf->jump, 0); } /* read dummy RECNO field */ if (dbf->ref[0] > 0) mpl_tab_set_num(dca, dbf->ref[0], dbf->count+1); /* read fields */ for (k = 1; k <= dbf->nf; k++) { /* read k-th field */ for (j = 0; j < dbf->len[k]; j++) buf[j] = (char)read_byte(dbf); buf[dbf->len[k]] = '\0'; /* set field value */ if (dbf->type[k] == 'C') { /* character field */ if (dbf->ref[k] > 0) mpl_tab_set_str(dca, dbf->ref[k], strtrim(buf)); } else if (dbf->type[k] == 'N') { /* numeric field */ if (dbf->ref[k] > 0) { double num; strspx(buf); xassert(str2num(buf, &num) == 0); mpl_tab_set_num(dca, dbf->ref[k], num); } } else xassert(dbf != dbf); } /* increase record count */ dbf->count++; done: return ret; } static int dbf_write_record(TABDCA *dca, struct dbf *dbf) { /* write next record to xBASE data file */ int j, k, ret = 0; char buf[255+1]; xassert(dbf->mode == 'W'); if (setjmp(dbf->jump)) { ret = 1; goto done; } /* record flag */ write_byte(dbf, 0x20); xassert(dbf->nf == mpl_tab_num_flds(dca)); for (k = 1; k <= dbf->nf; k++) { if (dbf->type[k] == 'C') { /* character field */ const char *str; if (mpl_tab_get_type(dca, k) == 'N') { sprintf(buf, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k)); str = buf; } else if (mpl_tab_get_type(dca, k) == 'S') str = mpl_tab_get_str(dca, k); else xassert(dca != dca); if ((int)strlen(str) > dbf->len[k]) { xprintf("xBASE driver: field %s: cannot convert %.15s..." " to field format\n", mpl_tab_get_name(dca, k), str); longjmp(dbf->jump, 0); } for (j = 0; j < dbf->len[k] && str[j] != '\0'; j++) write_byte(dbf, str[j]); for (j = j; j < dbf->len[k]; j++) write_byte(dbf, ' '); } else if (dbf->type[k] == 'N') { /* numeric field */ double num = mpl_tab_get_num(dca, k); if (fabs(num) > 1e20) err: { xprintf("xBASE driver: field %s: cannot convert %g to fi" "eld format\n", mpl_tab_get_name(dca, k), num); longjmp(dbf->jump, 0); } sprintf(buf, "%*.*f", dbf->len[k], dbf->prec[k], num); xassert(strlen(buf) < sizeof(buf)); if ((int)strlen(buf) != dbf->len[k]) goto err; for (j = 0; j < dbf->len[k]; j++) write_byte(dbf, buf[j]); } else xassert(dbf != dbf); } /* increase record count */ dbf->count++; done: return ret; } static int dbf_close_file(TABDCA *dca, struct dbf *dbf) { /* close xBASE data file */ int ret = 0; xassert(dca == dca); if (dbf->mode == 'W') { if (setjmp(dbf->jump)) { ret = 1; goto skip; } /* end-of-file flag */ write_byte(dbf, 0x1A); /* number of records */ dbf->offset = 4; if (fseek(dbf->fp, dbf->offset, SEEK_SET)) { xprintf("%s:0x%X: seek error - %s\n", dbf->fname, dbf->offset, strerror(errno)); longjmp(dbf->jump, 0); } write_byte(dbf, dbf->count); write_byte(dbf, dbf->count >> 8); write_byte(dbf, dbf->count >> 16); write_byte(dbf, dbf->count >> 24); fflush(dbf->fp); if (ferror(dbf->fp)) { xprintf("%s:0x%X: write error - %s\n", dbf->fname, dbf->offset, strerror(errno)); longjmp(dbf->jump, 0); } skip: ; } xfree(dbf->fname); fclose(dbf->fp); xfree(dbf); return ret; } /**********************************************************************/ #define TAB_CSV 1 #define TAB_XBASE 2 #define TAB_ODBC 3 #define TAB_MYSQL 4 void mpl_tab_drv_open(MPL *mpl, int mode) { TABDCA *dca = mpl->dca; xassert(dca->id == 0); xassert(dca->link == NULL); xassert(dca->na >= 1); if (strcmp(dca->arg[1], "CSV") == 0) { dca->id = TAB_CSV; dca->link = csv_open_file(dca, mode); } else if (strcmp(dca->arg[1], "xBASE") == 0) { dca->id = TAB_XBASE; dca->link = dbf_open_file(dca, mode); } else if (strcmp(dca->arg[1], "ODBC") == 0 || strcmp(dca->arg[1], "iODBC") == 0) { dca->id = TAB_ODBC; dca->link = db_iodbc_open(dca, mode); } else if (strcmp(dca->arg[1], "MySQL") == 0) { dca->id = TAB_MYSQL; dca->link = db_mysql_open(dca, mode); } else xprintf("Invalid table driver `%s'\n", dca->arg[1]); if (dca->link == NULL) error(mpl, "error on opening table %s", mpl->stmt->u.tab->name); return; } int mpl_tab_drv_read(MPL *mpl) { TABDCA *dca = mpl->dca; int ret; switch (dca->id) { case TAB_CSV: ret = csv_read_record(dca, dca->link); break; case TAB_XBASE: ret = dbf_read_record(dca, dca->link); break; case TAB_ODBC: ret = db_iodbc_read(dca, dca->link); break; case TAB_MYSQL: ret = db_mysql_read(dca, dca->link); break; default: xassert(dca != dca); } if (ret > 0) error(mpl, "error on reading data from table %s", mpl->stmt->u.tab->name); return ret; } void mpl_tab_drv_write(MPL *mpl) { TABDCA *dca = mpl->dca; int ret; switch (dca->id) { case TAB_CSV: ret = csv_write_record(dca, dca->link); break; case TAB_XBASE: ret = dbf_write_record(dca, dca->link); break; case TAB_ODBC: ret = db_iodbc_write(dca, dca->link); break; case TAB_MYSQL: ret = db_mysql_write(dca, dca->link); break; default: xassert(dca != dca); } if (ret) error(mpl, "error on writing data to table %s", mpl->stmt->u.tab->name); return; } void mpl_tab_drv_close(MPL *mpl) { TABDCA *dca = mpl->dca; int ret; switch (dca->id) { case TAB_CSV: ret = csv_close_file(dca, dca->link); break; case TAB_XBASE: ret = dbf_close_file(dca, dca->link); break; case TAB_ODBC: ret = db_iodbc_close(dca, dca->link); break; case TAB_MYSQL: ret = db_mysql_close(dca, dca->link); break; default: xassert(dca != dca); } dca->id = 0; dca->link = NULL; if (ret) error(mpl, "error on closing table %s", mpl->stmt->u.tab->name); return; } /* eof */ Rglpk/src/GLPK/glpipm.c0000644000176000001440000011412312245352174014350 0ustar ripleyusers/* glpipm.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpipm.h" #include "glpmat.h" #define ITER_MAX 100 /* maximal number of iterations */ struct csa { /* common storage area */ /*--------------------------------------------------------------*/ /* LP data */ int m; /* number of rows (equality constraints) */ int n; /* number of columns (structural variables) */ int *A_ptr; /* int A_ptr[1+m+1]; */ int *A_ind; /* int A_ind[A_ptr[m+1]]; */ double *A_val; /* double A_val[A_ptr[m+1]]; */ /* mxn-matrix A in storage-by-rows format */ double *b; /* double b[1+m]; */ /* m-vector b of right-hand sides */ double *c; /* double c[1+n]; */ /* n-vector c of objective coefficients; c[0] is constant term of the objective function */ /*--------------------------------------------------------------*/ /* LP solution */ double *x; /* double x[1+n]; */ double *y; /* double y[1+m]; */ double *z; /* double z[1+n]; */ /* current point in primal-dual space; the best point on exit */ /*--------------------------------------------------------------*/ /* control parameters */ const glp_iptcp *parm; /*--------------------------------------------------------------*/ /* working arrays and variables */ double *D; /* double D[1+n]; */ /* diagonal nxn-matrix D = X*inv(Z), where X = diag(x[j]) and Z = diag(z[j]) */ int *P; /* int P[1+m+m]; */ /* permutation mxm-matrix P used to minimize fill-in in Cholesky factorization */ int *S_ptr; /* int S_ptr[1+m+1]; */ int *S_ind; /* int S_ind[S_ptr[m+1]]; */ double *S_val; /* double S_val[S_ptr[m+1]]; */ double *S_diag; /* double S_diag[1+m]; */ /* symmetric mxm-matrix S = P*A*D*A'*P' whose upper triangular part without diagonal elements is stored in S_ptr, S_ind, and S_val in storage-by-rows format, diagonal elements are stored in S_diag */ int *U_ptr; /* int U_ptr[1+m+1]; */ int *U_ind; /* int U_ind[U_ptr[m+1]]; */ double *U_val; /* double U_val[U_ptr[m+1]]; */ double *U_diag; /* double U_diag[1+m]; */ /* upper triangular mxm-matrix U defining Cholesky factorization S = U'*U; its non-diagonal elements are stored in U_ptr, U_ind, U_val in storage-by-rows format, diagonal elements are stored in U_diag */ int iter; /* iteration number (0, 1, 2, ...); iter = 0 corresponds to the initial point */ double obj; /* current value of the objective function */ double rpi; /* relative primal infeasibility rpi = ||A*x-b||/(1+||b||) */ double rdi; /* relative dual infeasibility rdi = ||A'*y+z-c||/(1+||c||) */ double gap; /* primal-dual gap = |c'*x-b'*y|/(1+|c'*x|) which is a relative difference between primal and dual objective functions */ double phi; /* merit function phi = ||A*x-b||/max(1,||b||) + + ||A'*y+z-c||/max(1,||c||) + + |c'*x-b'*y|/max(1,||b||,||c||) */ double mu; /* duality measure mu = x'*z/n (used as barrier parameter) */ double rmu; /* rmu = max(||A*x-b||,||A'*y+z-c||)/mu */ double rmu0; /* the initial value of rmu on iteration 0 */ double *phi_min; /* double phi_min[1+ITER_MAX]; */ /* phi_min[k] = min(phi[k]), where phi[k] is the value of phi on k-th iteration, 0 <= k <= iter */ int best_iter; /* iteration number, on which the value of phi reached its best (minimal) value */ double *best_x; /* double best_x[1+n]; */ double *best_y; /* double best_y[1+m]; */ double *best_z; /* double best_z[1+n]; */ /* best point (in the sense of the merit function phi) which has been reached on iteration iter_best */ double best_obj; /* objective value at the best point */ double *dx_aff; /* double dx_aff[1+n]; */ double *dy_aff; /* double dy_aff[1+m]; */ double *dz_aff; /* double dz_aff[1+n]; */ /* affine scaling direction */ double alfa_aff_p, alfa_aff_d; /* maximal primal and dual stepsizes in affine scaling direction, on which x and z are still non-negative */ double mu_aff; /* duality measure mu_aff = x_aff'*z_aff/n in the boundary point x_aff' = x+alfa_aff_p*dx_aff, z_aff' = z+alfa_aff_d*dz_aff */ double sigma; /* Mehrotra's heuristic parameter (0 <= sigma <= 1) */ double *dx_cc; /* double dx_cc[1+n]; */ double *dy_cc; /* double dy_cc[1+m]; */ double *dz_cc; /* double dz_cc[1+n]; */ /* centering corrector direction */ double *dx; /* double dx[1+n]; */ double *dy; /* double dy[1+m]; */ double *dz; /* double dz[1+n]; */ /* final combined direction dx = dx_aff+dx_cc, dy = dy_aff+dy_cc, dz = dz_aff+dz_cc */ double alfa_max_p; double alfa_max_d; /* maximal primal and dual stepsizes in combined direction, on which x and z are still non-negative */ }; /*********************************************************************** * initialize - allocate and initialize common storage area * * This routine allocates and initializes the common storage area (CSA) * used by interior-point method routines. */ static void initialize(struct csa *csa) { int m = csa->m; int n = csa->n; int i; if (csa->parm->msg_lev >= GLP_MSG_ALL) xprintf("Matrix A has %d non-zeros\n", csa->A_ptr[m+1]-1); csa->D = xcalloc(1+n, sizeof(double)); /* P := I */ csa->P = xcalloc(1+m+m, sizeof(int)); for (i = 1; i <= m; i++) csa->P[i] = csa->P[m+i] = i; /* S := A*A', symbolically */ csa->S_ptr = xcalloc(1+m+1, sizeof(int)); csa->S_ind = adat_symbolic(m, n, csa->P, csa->A_ptr, csa->A_ind, csa->S_ptr); if (csa->parm->msg_lev >= GLP_MSG_ALL) xprintf("Matrix S = A*A' has %d non-zeros (upper triangle)\n", csa->S_ptr[m+1]-1 + m); /* determine P using specified ordering algorithm */ if (csa->parm->ord_alg == GLP_ORD_NONE) { if (csa->parm->msg_lev >= GLP_MSG_ALL) xprintf("Original ordering is being used\n"); for (i = 1; i <= m; i++) csa->P[i] = csa->P[m+i] = i; } else if (csa->parm->ord_alg == GLP_ORD_QMD) { if (csa->parm->msg_lev >= GLP_MSG_ALL) xprintf("Minimum degree ordering (QMD)...\n"); min_degree(m, csa->S_ptr, csa->S_ind, csa->P); } else if (csa->parm->ord_alg == GLP_ORD_AMD) { if (csa->parm->msg_lev >= GLP_MSG_ALL) xprintf("Approximate minimum degree ordering (AMD)...\n"); amd_order1(m, csa->S_ptr, csa->S_ind, csa->P); } else if (csa->parm->ord_alg == GLP_ORD_SYMAMD) { if (csa->parm->msg_lev >= GLP_MSG_ALL) xprintf("Approximate minimum degree ordering (SYMAMD)...\n") ; symamd_ord(m, csa->S_ptr, csa->S_ind, csa->P); } else xassert(csa != csa); /* S := P*A*A'*P', symbolically */ xfree(csa->S_ind); csa->S_ind = adat_symbolic(m, n, csa->P, csa->A_ptr, csa->A_ind, csa->S_ptr); csa->S_val = xcalloc(csa->S_ptr[m+1], sizeof(double)); csa->S_diag = xcalloc(1+m, sizeof(double)); /* compute Cholesky factorization S = U'*U, symbolically */ if (csa->parm->msg_lev >= GLP_MSG_ALL) xprintf("Computing Cholesky factorization S = L*L'...\n"); csa->U_ptr = xcalloc(1+m+1, sizeof(int)); csa->U_ind = chol_symbolic(m, csa->S_ptr, csa->S_ind, csa->U_ptr); if (csa->parm->msg_lev >= GLP_MSG_ALL) xprintf("Matrix L has %d non-zeros\n", csa->U_ptr[m+1]-1 + m); csa->U_val = xcalloc(csa->U_ptr[m+1], sizeof(double)); csa->U_diag = xcalloc(1+m, sizeof(double)); csa->iter = 0; csa->obj = 0.0; csa->rpi = 0.0; csa->rdi = 0.0; csa->gap = 0.0; csa->phi = 0.0; csa->mu = 0.0; csa->rmu = 0.0; csa->rmu0 = 0.0; csa->phi_min = xcalloc(1+ITER_MAX, sizeof(double)); csa->best_iter = 0; csa->best_x = xcalloc(1+n, sizeof(double)); csa->best_y = xcalloc(1+m, sizeof(double)); csa->best_z = xcalloc(1+n, sizeof(double)); csa->best_obj = 0.0; csa->dx_aff = xcalloc(1+n, sizeof(double)); csa->dy_aff = xcalloc(1+m, sizeof(double)); csa->dz_aff = xcalloc(1+n, sizeof(double)); csa->alfa_aff_p = 0.0; csa->alfa_aff_d = 0.0; csa->mu_aff = 0.0; csa->sigma = 0.0; csa->dx_cc = xcalloc(1+n, sizeof(double)); csa->dy_cc = xcalloc(1+m, sizeof(double)); csa->dz_cc = xcalloc(1+n, sizeof(double)); csa->dx = csa->dx_aff; csa->dy = csa->dy_aff; csa->dz = csa->dz_aff; csa->alfa_max_p = 0.0; csa->alfa_max_d = 0.0; return; } /*********************************************************************** * A_by_vec - compute y = A*x * * This routine computes matrix-vector product y = A*x, where A is the * constraint matrix. */ static void A_by_vec(struct csa *csa, double x[], double y[]) { /* compute y = A*x */ int m = csa->m; int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int i, t, beg, end; double temp; for (i = 1; i <= m; i++) { temp = 0.0; beg = A_ptr[i], end = A_ptr[i+1]; for (t = beg; t < end; t++) temp += A_val[t] * x[A_ind[t]]; y[i] = temp; } return; } /*********************************************************************** * AT_by_vec - compute y = A'*x * * This routine computes matrix-vector product y = A'*x, where A' is a * matrix transposed to the constraint matrix A. */ static void AT_by_vec(struct csa *csa, double x[], double y[]) { /* compute y = A'*x, where A' is transposed to A */ int m = csa->m; int n = csa->n; int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int i, j, t, beg, end; double temp; for (j = 1; j <= n; j++) y[j] = 0.0; for (i = 1; i <= m; i++) { temp = x[i]; if (temp == 0.0) continue; beg = A_ptr[i], end = A_ptr[i+1]; for (t = beg; t < end; t++) y[A_ind[t]] += A_val[t] * temp; } return; } /*********************************************************************** * decomp_NE - numeric factorization of matrix S = P*A*D*A'*P' * * This routine implements numeric phase of Cholesky factorization of * the matrix S = P*A*D*A'*P', which is a permuted matrix of the normal * equation system. Matrix D is assumed to be already computed. */ static void decomp_NE(struct csa *csa) { adat_numeric(csa->m, csa->n, csa->P, csa->A_ptr, csa->A_ind, csa->A_val, csa->D, csa->S_ptr, csa->S_ind, csa->S_val, csa->S_diag); chol_numeric(csa->m, csa->S_ptr, csa->S_ind, csa->S_val, csa->S_diag, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag); return; } /*********************************************************************** * solve_NE - solve normal equation system * * This routine solves the normal equation system: * * A*D*A'*y = h. * * It is assumed that the matrix A*D*A' has been previously factorized * by the routine decomp_NE. * * On entry the array y contains the vector of right-hand sides h. On * exit this array contains the computed vector of unknowns y. * * Once the vector y has been computed the routine checks for numeric * stability. If the residual vector: * * r = A*D*A'*y - h * * is relatively small, the routine returns zero, otherwise non-zero is * returned. */ static int solve_NE(struct csa *csa, double y[]) { int m = csa->m; int n = csa->n; int *P = csa->P; int i, j, ret = 0; double *h, *r, *w; /* save vector of right-hand sides h */ h = xcalloc(1+m, sizeof(double)); for (i = 1; i <= m; i++) h[i] = y[i]; /* solve normal equation system (A*D*A')*y = h */ /* since S = P*A*D*A'*P' = U'*U, then A*D*A' = P'*U'*U*P, so we have inv(A*D*A') = P'*inv(U)*inv(U')*P */ /* w := P*h */ w = xcalloc(1+m, sizeof(double)); for (i = 1; i <= m; i++) w[i] = y[P[i]]; /* w := inv(U')*w */ ut_solve(m, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag, w); /* w := inv(U)*w */ u_solve(m, csa->U_ptr, csa->U_ind, csa->U_val, csa->U_diag, w); /* y := P'*w */ for (i = 1; i <= m; i++) y[i] = w[P[m+i]]; xfree(w); /* compute residual vector r = A*D*A'*y - h */ r = xcalloc(1+m, sizeof(double)); /* w := A'*y */ w = xcalloc(1+n, sizeof(double)); AT_by_vec(csa, y, w); /* w := D*w */ for (j = 1; j <= n; j++) w[j] *= csa->D[j]; /* r := A*w */ A_by_vec(csa, w, r); xfree(w); /* r := r - h */ for (i = 1; i <= m; i++) r[i] -= h[i]; /* check for numeric stability */ for (i = 1; i <= m; i++) { if (fabs(r[i]) / (1.0 + fabs(h[i])) > 1e-4) { ret = 1; break; } } xfree(h); xfree(r); return ret; } /*********************************************************************** * solve_NS - solve Newtonian system * * This routine solves the Newtonian system: * * A*dx = p * * A'*dy + dz = q * * Z*dx + X*dz = r * * where X = diag(x[j]), Z = diag(z[j]), by reducing it to the normal * equation system: * * (A*inv(Z)*X*A')*dy = A*inv(Z)*(X*q-r)+p * * (it is assumed that the matrix A*inv(Z)*X*A' has been factorized by * the routine decomp_NE). * * Once vector dy has been computed the routine computes vectors dx and * dz as follows: * * dx = inv(Z)*(X*(A'*dy-q)+r) * * dz = inv(X)*(r-Z*dx) * * The routine solve_NS returns the same code which was reported by the * routine solve_NE (see above). */ static int solve_NS(struct csa *csa, double p[], double q[], double r[], double dx[], double dy[], double dz[]) { int m = csa->m; int n = csa->n; double *x = csa->x; double *z = csa->z; int i, j, ret; double *w = dx; /* compute the vector of right-hand sides A*inv(Z)*(X*q-r)+p for the normal equation system */ for (j = 1; j <= n; j++) w[j] = (x[j] * q[j] - r[j]) / z[j]; A_by_vec(csa, w, dy); for (i = 1; i <= m; i++) dy[i] += p[i]; /* solve the normal equation system to compute vector dy */ ret = solve_NE(csa, dy); /* compute vectors dx and dz */ AT_by_vec(csa, dy, dx); for (j = 1; j <= n; j++) { dx[j] = (x[j] * (dx[j] - q[j]) + r[j]) / z[j]; dz[j] = (r[j] - z[j] * dx[j]) / x[j]; } return ret; } /*********************************************************************** * initial_point - choose initial point using Mehrotra's heuristic * * This routine chooses a starting point using a heuristic proposed in * the paper: * * S. Mehrotra. On the implementation of a primal-dual interior point * method. SIAM J. on Optim., 2(4), pp. 575-601, 1992. * * The starting point x in the primal space is chosen as a solution of * the following least squares problem: * * minimize ||x|| * * subject to A*x = b * * which can be computed explicitly as follows: * * x = A'*inv(A*A')*b * * Similarly, the starting point (y, z) in the dual space is chosen as * a solution of the following least squares problem: * * minimize ||z|| * * subject to A'*y + z = c * * which can be computed explicitly as follows: * * y = inv(A*A')*A*c * * z = c - A'*y * * However, some components of the vectors x and z may be non-positive * or close to zero, so the routine uses a Mehrotra's heuristic to find * a more appropriate starting point. */ static void initial_point(struct csa *csa) { int m = csa->m; int n = csa->n; double *b = csa->b; double *c = csa->c; double *x = csa->x; double *y = csa->y; double *z = csa->z; double *D = csa->D; int i, j; double dp, dd, ex, ez, xz; /* factorize A*A' */ for (j = 1; j <= n; j++) D[j] = 1.0; decomp_NE(csa); /* x~ = A'*inv(A*A')*b */ for (i = 1; i <= m; i++) y[i] = b[i]; solve_NE(csa, y); AT_by_vec(csa, y, x); /* y~ = inv(A*A')*A*c */ A_by_vec(csa, c, y); solve_NE(csa, y); /* z~ = c - A'*y~ */ AT_by_vec(csa, y,z); for (j = 1; j <= n; j++) z[j] = c[j] - z[j]; /* use Mehrotra's heuristic in order to choose more appropriate starting point with positive components of vectors x and z */ dp = dd = 0.0; for (j = 1; j <= n; j++) { if (dp < -1.5 * x[j]) dp = -1.5 * x[j]; if (dd < -1.5 * z[j]) dd = -1.5 * z[j]; } /* note that b = 0 involves x = 0, and c = 0 involves y = 0 and z = 0, so we need to be careful */ if (dp == 0.0) dp = 1.5; if (dd == 0.0) dd = 1.5; ex = ez = xz = 0.0; for (j = 1; j <= n; j++) { ex += (x[j] + dp); ez += (z[j] + dd); xz += (x[j] + dp) * (z[j] + dd); } dp += 0.5 * (xz / ez); dd += 0.5 * (xz / ex); for (j = 1; j <= n; j++) { x[j] += dp; z[j] += dd; xassert(x[j] > 0.0 && z[j] > 0.0); } return; } /*********************************************************************** * basic_info - perform basic computations at the current point * * This routine computes the following quantities at the current point: * * 1) value of the objective function: * * F = c'*x + c[0] * * 2) relative primal infeasibility: * * rpi = ||A*x-b|| / (1+||b||) * * 3) relative dual infeasibility: * * rdi = ||A'*y+z-c|| / (1+||c||) * * 4) primal-dual gap (relative difference between the primal and the * dual objective function values): * * gap = |c'*x-b'*y| / (1+|c'*x|) * * 5) merit function: * * phi = ||A*x-b|| / max(1,||b||) + ||A'*y+z-c|| / max(1,||c||) + * * + |c'*x-b'*y| / max(1,||b||,||c||) * * 6) duality measure: * * mu = x'*z / n * * 7) the ratio of infeasibility to mu: * * rmu = max(||A*x-b||,||A'*y+z-c||) / mu * * where ||*|| denotes euclidian norm, *' denotes transposition. */ static void basic_info(struct csa *csa) { int m = csa->m; int n = csa->n; double *b = csa->b; double *c = csa->c; double *x = csa->x; double *y = csa->y; double *z = csa->z; int i, j; double norm1, bnorm, norm2, cnorm, cx, by, *work, temp; /* compute value of the objective function */ temp = c[0]; for (j = 1; j <= n; j++) temp += c[j] * x[j]; csa->obj = temp; /* norm1 = ||A*x-b|| */ work = xcalloc(1+m, sizeof(double)); A_by_vec(csa, x, work); norm1 = 0.0; for (i = 1; i <= m; i++) norm1 += (work[i] - b[i]) * (work[i] - b[i]); norm1 = sqrt(norm1); xfree(work); /* bnorm = ||b|| */ bnorm = 0.0; for (i = 1; i <= m; i++) bnorm += b[i] * b[i]; bnorm = sqrt(bnorm); /* compute relative primal infeasibility */ csa->rpi = norm1 / (1.0 + bnorm); /* norm2 = ||A'*y+z-c|| */ work = xcalloc(1+n, sizeof(double)); AT_by_vec(csa, y, work); norm2 = 0.0; for (j = 1; j <= n; j++) norm2 += (work[j] + z[j] - c[j]) * (work[j] + z[j] - c[j]); norm2 = sqrt(norm2); xfree(work); /* cnorm = ||c|| */ cnorm = 0.0; for (j = 1; j <= n; j++) cnorm += c[j] * c[j]; cnorm = sqrt(cnorm); /* compute relative dual infeasibility */ csa->rdi = norm2 / (1.0 + cnorm); /* by = b'*y */ by = 0.0; for (i = 1; i <= m; i++) by += b[i] * y[i]; /* cx = c'*x */ cx = 0.0; for (j = 1; j <= n; j++) cx += c[j] * x[j]; /* compute primal-dual gap */ csa->gap = fabs(cx - by) / (1.0 + fabs(cx)); /* compute merit function */ csa->phi = 0.0; csa->phi += norm1 / (bnorm > 1.0 ? bnorm : 1.0); csa->phi += norm2 / (cnorm > 1.0 ? cnorm : 1.0); temp = 1.0; if (temp < bnorm) temp = bnorm; if (temp < cnorm) temp = cnorm; csa->phi += fabs(cx - by) / temp; /* compute duality measure */ temp = 0.0; for (j = 1; j <= n; j++) temp += x[j] * z[j]; csa->mu = temp / (double)n; /* compute the ratio of infeasibility to mu */ csa->rmu = (norm1 > norm2 ? norm1 : norm2) / csa->mu; return; } /*********************************************************************** * make_step - compute next point using Mehrotra's technique * * This routine computes the next point using the predictor-corrector * technique proposed in the paper: * * S. Mehrotra. On the implementation of a primal-dual interior point * method. SIAM J. on Optim., 2(4), pp. 575-601, 1992. * * At first, the routine computes so called affine scaling (predictor) * direction (dx_aff,dy_aff,dz_aff) which is a solution of the system: * * A*dx_aff = b - A*x * * A'*dy_aff + dz_aff = c - A'*y - z * * Z*dx_aff + X*dz_aff = - X*Z*e * * where (x,y,z) is the current point, X = diag(x[j]), Z = diag(z[j]), * e = (1,...,1)'. * * Then, the routine computes the centering parameter sigma, using the * following Mehrotra's heuristic: * * alfa_aff_p = inf{0 <= alfa <= 1 | x+alfa*dx_aff >= 0} * * alfa_aff_d = inf{0 <= alfa <= 1 | z+alfa*dz_aff >= 0} * * mu_aff = (x+alfa_aff_p*dx_aff)'*(z+alfa_aff_d*dz_aff)/n * * sigma = (mu_aff/mu)^3 * * where alfa_aff_p is the maximal stepsize along the affine scaling * direction in the primal space, alfa_aff_d is the maximal stepsize * along the same direction in the dual space. * * After determining sigma the routine computes so called centering * (corrector) direction (dx_cc,dy_cc,dz_cc) which is the solution of * the system: * * A*dx_cc = 0 * * A'*dy_cc + dz_cc = 0 * * Z*dx_cc + X*dz_cc = sigma*mu*e - X*Z*e * * Finally, the routine computes the combined direction * * (dx,dy,dz) = (dx_aff,dy_aff,dz_aff) + (dx_cc,dy_cc,dz_cc) * * and determines maximal primal and dual stepsizes along the combined * direction: * * alfa_max_p = inf{0 <= alfa <= 1 | x+alfa*dx >= 0} * * alfa_max_d = inf{0 <= alfa <= 1 | z+alfa*dz >= 0} * * In order to prevent the next point to be too close to the boundary * of the positive ortant, the routine decreases maximal stepsizes: * * alfa_p = gamma_p * alfa_max_p * * alfa_d = gamma_d * alfa_max_d * * where gamma_p and gamma_d are scaling factors, and computes the next * point: * * x_new = x + alfa_p * dx * * y_new = y + alfa_d * dy * * z_new = z + alfa_d * dz * * which becomes the current point on the next iteration. */ static int make_step(struct csa *csa) { int m = csa->m; int n = csa->n; double *b = csa->b; double *c = csa->c; double *x = csa->x; double *y = csa->y; double *z = csa->z; double *dx_aff = csa->dx_aff; double *dy_aff = csa->dy_aff; double *dz_aff = csa->dz_aff; double *dx_cc = csa->dx_cc; double *dy_cc = csa->dy_cc; double *dz_cc = csa->dz_cc; double *dx = csa->dx; double *dy = csa->dy; double *dz = csa->dz; int i, j, ret = 0; double temp, gamma_p, gamma_d, *p, *q, *r; /* allocate working arrays */ p = xcalloc(1+m, sizeof(double)); q = xcalloc(1+n, sizeof(double)); r = xcalloc(1+n, sizeof(double)); /* p = b - A*x */ A_by_vec(csa, x, p); for (i = 1; i <= m; i++) p[i] = b[i] - p[i]; /* q = c - A'*y - z */ AT_by_vec(csa, y,q); for (j = 1; j <= n; j++) q[j] = c[j] - q[j] - z[j]; /* r = - X * Z * e */ for (j = 1; j <= n; j++) r[j] = - x[j] * z[j]; /* solve the first Newtonian system */ if (solve_NS(csa, p, q, r, dx_aff, dy_aff, dz_aff)) { ret = 1; goto done; } /* alfa_aff_p = inf{0 <= alfa <= 1 | x + alfa*dx_aff >= 0} */ /* alfa_aff_d = inf{0 <= alfa <= 1 | z + alfa*dz_aff >= 0} */ csa->alfa_aff_p = csa->alfa_aff_d = 1.0; for (j = 1; j <= n; j++) { if (dx_aff[j] < 0.0) { temp = - x[j] / dx_aff[j]; if (csa->alfa_aff_p > temp) csa->alfa_aff_p = temp; } if (dz_aff[j] < 0.0) { temp = - z[j] / dz_aff[j]; if (csa->alfa_aff_d > temp) csa->alfa_aff_d = temp; } } /* mu_aff = (x+alfa_aff_p*dx_aff)' * (z+alfa_aff_d*dz_aff) / n */ temp = 0.0; for (j = 1; j <= n; j++) temp += (x[j] + csa->alfa_aff_p * dx_aff[j]) * (z[j] + csa->alfa_aff_d * dz_aff[j]); csa->mu_aff = temp / (double)n; /* sigma = (mu_aff/mu)^3 */ temp = csa->mu_aff / csa->mu; csa->sigma = temp * temp * temp; /* p = 0 */ for (i = 1; i <= m; i++) p[i] = 0.0; /* q = 0 */ for (j = 1; j <= n; j++) q[j] = 0.0; /* r = sigma * mu * e - X * Z * e */ for (j = 1; j <= n; j++) r[j] = csa->sigma * csa->mu - dx_aff[j] * dz_aff[j]; /* solve the second Newtonian system with the same coefficients but with altered right-hand sides */ if (solve_NS(csa, p, q, r, dx_cc, dy_cc, dz_cc)) { ret = 1; goto done; } /* (dx,dy,dz) = (dx_aff,dy_aff,dz_aff) + (dx_cc,dy_cc,dz_cc) */ for (j = 1; j <= n; j++) dx[j] = dx_aff[j] + dx_cc[j]; for (i = 1; i <= m; i++) dy[i] = dy_aff[i] + dy_cc[i]; for (j = 1; j <= n; j++) dz[j] = dz_aff[j] + dz_cc[j]; /* alfa_max_p = inf{0 <= alfa <= 1 | x + alfa*dx >= 0} */ /* alfa_max_d = inf{0 <= alfa <= 1 | z + alfa*dz >= 0} */ csa->alfa_max_p = csa->alfa_max_d = 1.0; for (j = 1; j <= n; j++) { if (dx[j] < 0.0) { temp = - x[j] / dx[j]; if (csa->alfa_max_p > temp) csa->alfa_max_p = temp; } if (dz[j] < 0.0) { temp = - z[j] / dz[j]; if (csa->alfa_max_d > temp) csa->alfa_max_d = temp; } } /* determine scale factors (not implemented yet) */ gamma_p = 0.90; gamma_d = 0.90; /* compute the next point */ for (j = 1; j <= n; j++) { x[j] += gamma_p * csa->alfa_max_p * dx[j]; xassert(x[j] > 0.0); } for (i = 1; i <= m; i++) y[i] += gamma_d * csa->alfa_max_d * dy[i]; for (j = 1; j <= n; j++) { z[j] += gamma_d * csa->alfa_max_d * dz[j]; xassert(z[j] > 0.0); } done: /* free working arrays */ xfree(p); xfree(q); xfree(r); return ret; } /*********************************************************************** * terminate - deallocate common storage area * * This routine frees all memory allocated to the common storage area * used by interior-point method routines. */ static void terminate(struct csa *csa) { xfree(csa->D); xfree(csa->P); xfree(csa->S_ptr); xfree(csa->S_ind); xfree(csa->S_val); xfree(csa->S_diag); xfree(csa->U_ptr); xfree(csa->U_ind); xfree(csa->U_val); xfree(csa->U_diag); xfree(csa->phi_min); xfree(csa->best_x); xfree(csa->best_y); xfree(csa->best_z); xfree(csa->dx_aff); xfree(csa->dy_aff); xfree(csa->dz_aff); xfree(csa->dx_cc); xfree(csa->dy_cc); xfree(csa->dz_cc); return; } /*********************************************************************** * ipm_main - main interior-point method routine * * This is a main routine of the primal-dual interior-point method. * * The routine ipm_main returns one of the following codes: * * 0 - optimal solution found; * 1 - problem has no feasible (primal or dual) solution; * 2 - no convergence; * 3 - iteration limit exceeded; * 4 - numeric instability on solving Newtonian system. * * In case of non-zero return code the routine returns the best point, * which has been reached during optimization. */ static int ipm_main(struct csa *csa) { int m = csa->m; int n = csa->n; int i, j, status; double temp; /* choose initial point using Mehrotra's heuristic */ if (csa->parm->msg_lev >= GLP_MSG_ALL) xprintf("Guessing initial point...\n"); initial_point(csa); /* main loop starts here */ if (csa->parm->msg_lev >= GLP_MSG_ALL) xprintf("Optimization begins...\n"); for (;;) { /* perform basic computations at the current point */ basic_info(csa); /* save initial value of rmu */ if (csa->iter == 0) csa->rmu0 = csa->rmu; /* accumulate values of min(phi[k]) and save the best point */ xassert(csa->iter <= ITER_MAX); if (csa->iter == 0 || csa->phi_min[csa->iter-1] > csa->phi) { csa->phi_min[csa->iter] = csa->phi; csa->best_iter = csa->iter; for (j = 1; j <= n; j++) csa->best_x[j] = csa->x[j]; for (i = 1; i <= m; i++) csa->best_y[i] = csa->y[i]; for (j = 1; j <= n; j++) csa->best_z[j] = csa->z[j]; csa->best_obj = csa->obj; } else csa->phi_min[csa->iter] = csa->phi_min[csa->iter-1]; /* display information at the current point */ if (csa->parm->msg_lev >= GLP_MSG_ON) xprintf("%3d: obj = %17.9e; rpi = %8.1e; rdi = %8.1e; gap =" " %8.1e\n", csa->iter, csa->obj, csa->rpi, csa->rdi, csa->gap); /* check if the current point is optimal */ if (csa->rpi < 1e-8 && csa->rdi < 1e-8 && csa->gap < 1e-8) { if (csa->parm->msg_lev >= GLP_MSG_ALL) xprintf("OPTIMAL SOLUTION FOUND\n"); status = 0; break; } /* check if the problem has no feasible solution */ temp = 1e5 * csa->phi_min[csa->iter]; if (temp < 1e-8) temp = 1e-8; if (csa->phi >= temp) { if (csa->parm->msg_lev >= GLP_MSG_ALL) xprintf("PROBLEM HAS NO FEASIBLE PRIMAL/DUAL SOLUTION\n") ; status = 1; break; } /* check for very slow convergence or divergence */ if (((csa->rpi >= 1e-8 || csa->rdi >= 1e-8) && csa->rmu / csa->rmu0 >= 1e6) || (csa->iter >= 30 && csa->phi_min[csa->iter] >= 0.5 * csa->phi_min[csa->iter - 30])) { if (csa->parm->msg_lev >= GLP_MSG_ALL) xprintf("NO CONVERGENCE; SEARCH TERMINATED\n"); status = 2; break; } /* check for maximal number of iterations */ if (csa->iter == ITER_MAX) { if (csa->parm->msg_lev >= GLP_MSG_ALL) xprintf("ITERATION LIMIT EXCEEDED; SEARCH TERMINATED\n"); status = 3; break; } /* start the next iteration */ csa->iter++; /* factorize normal equation system */ for (j = 1; j <= n; j++) csa->D[j] = csa->x[j] / csa->z[j]; decomp_NE(csa); /* compute the next point using Mehrotra's predictor-corrector technique */ if (make_step(csa)) { if (csa->parm->msg_lev >= GLP_MSG_ALL) xprintf("NUMERIC INSTABILITY; SEARCH TERMINATED\n"); status = 4; break; } } /* restore the best point */ if (status != 0) { for (j = 1; j <= n; j++) csa->x[j] = csa->best_x[j]; for (i = 1; i <= m; i++) csa->y[i] = csa->best_y[i]; for (j = 1; j <= n; j++) csa->z[j] = csa->best_z[j]; if (csa->parm->msg_lev >= GLP_MSG_ALL) xprintf("Best point %17.9e was reached on iteration %d\n", csa->best_obj, csa->best_iter); } /* return to the calling program */ return status; } /*********************************************************************** * NAME * * ipm_solve - core LP solver based on the interior-point method * * SYNOPSIS * * #include "glpipm.h" * int ipm_solve(glp_prob *P, const glp_iptcp *parm); * * DESCRIPTION * * The routine ipm_solve is a core LP solver based on the primal-dual * interior-point method. * * The routine assumes the following standard formulation of LP problem * to be solved: * * minimize * * F = c[0] + c[1]*x[1] + c[2]*x[2] + ... + c[n]*x[n] * * subject to linear constraints * * a[1,1]*x[1] + a[1,2]*x[2] + ... + a[1,n]*x[n] = b[1] * * a[2,1]*x[1] + a[2,2]*x[2] + ... + a[2,n]*x[n] = b[2] * * . . . . . . * * a[m,1]*x[1] + a[m,2]*x[2] + ... + a[m,n]*x[n] = b[m] * * and non-negative variables * * x[1] >= 0, x[2] >= 0, ..., x[n] >= 0 * * where: * F is the objective function; * x[1], ..., x[n] are (structural) variables; * c[0] is a constant term of the objective function; * c[1], ..., c[n] are objective coefficients; * a[1,1], ..., a[m,n] are constraint coefficients; * b[1], ..., b[n] are right-hand sides. * * The solution is three vectors x, y, and z, which are stored by the * routine in the arrays x, y, and z, respectively. These vectors * correspond to the best primal-dual point found during optimization. * They are approximate solution of the following system (which is the * Karush-Kuhn-Tucker optimality conditions): * * A*x = b (primal feasibility condition) * * A'*y + z = c (dual feasibility condition) * * x'*z = 0 (primal-dual complementarity condition) * * x >= 0, z >= 0 (non-negativity condition) * * where: * x[1], ..., x[n] are primal (structural) variables; * y[1], ..., y[m] are dual variables (Lagrange multipliers) for * equality constraints; * z[1], ..., z[n] are dual variables (Lagrange multipliers) for * non-negativity constraints. * * RETURNS * * 0 LP has been successfully solved. * * GLP_ENOCVG * No convergence. * * GLP_EITLIM * Iteration limit exceeded. * * GLP_EINSTAB * Numeric instability on solving Newtonian system. * * In case of non-zero return code the routine returns the best point, * which has been reached during optimization. */ int ipm_solve(glp_prob *P, const glp_iptcp *parm) { struct csa _dsa, *csa = &_dsa; int m = P->m; int n = P->n; int nnz = P->nnz; GLPROW *row; GLPCOL *col; GLPAIJ *aij; int i, j, loc, ret, *A_ind, *A_ptr; double dir, *A_val, *b, *c, *x, *y, *z; xassert(m > 0); xassert(n > 0); /* allocate working arrays */ A_ptr = xcalloc(1+m+1, sizeof(int)); A_ind = xcalloc(1+nnz, sizeof(int)); A_val = xcalloc(1+nnz, sizeof(double)); b = xcalloc(1+m, sizeof(double)); c = xcalloc(1+n, sizeof(double)); x = xcalloc(1+n, sizeof(double)); y = xcalloc(1+m, sizeof(double)); z = xcalloc(1+n, sizeof(double)); /* prepare rows and constraint coefficients */ loc = 1; for (i = 1; i <= m; i++) { row = P->row[i]; xassert(row->type == GLP_FX); b[i] = row->lb * row->rii; A_ptr[i] = loc; for (aij = row->ptr; aij != NULL; aij = aij->r_next) { A_ind[loc] = aij->col->j; A_val[loc] = row->rii * aij->val * aij->col->sjj; loc++; } } A_ptr[m+1] = loc; xassert(loc-1 == nnz); /* prepare columns and objective coefficients */ if (P->dir == GLP_MIN) dir = +1.0; else if (P->dir == GLP_MAX) dir = -1.0; else xassert(P != P); c[0] = dir * P->c0; for (j = 1; j <= n; j++) { col = P->col[j]; xassert(col->type == GLP_LO && col->lb == 0.0); c[j] = dir * col->coef * col->sjj; } /* allocate and initialize the common storage area */ csa->m = m; csa->n = n; csa->A_ptr = A_ptr; csa->A_ind = A_ind; csa->A_val = A_val; csa->b = b; csa->c = c; csa->x = x; csa->y = y; csa->z = z; csa->parm = parm; initialize(csa); /* solve LP with the interior-point method */ ret = ipm_main(csa); /* deallocate the common storage area */ terminate(csa); /* determine solution status */ if (ret == 0) { /* optimal solution found */ P->ipt_stat = GLP_OPT; ret = 0; } else if (ret == 1) { /* problem has no feasible (primal or dual) solution */ P->ipt_stat = GLP_NOFEAS; ret = 0; } else if (ret == 2) { /* no convergence */ P->ipt_stat = GLP_INFEAS; ret = GLP_ENOCVG; } else if (ret == 3) { /* iteration limit exceeded */ P->ipt_stat = GLP_INFEAS; ret = GLP_EITLIM; } else if (ret == 4) { /* numeric instability on solving Newtonian system */ P->ipt_stat = GLP_INFEAS; ret = GLP_EINSTAB; } else xassert(ret != ret); /* store row solution components */ for (i = 1; i <= m; i++) { row = P->row[i]; row->pval = row->lb; row->dval = dir * y[i] * row->rii; } /* store column solution components */ P->ipt_obj = P->c0; for (j = 1; j <= n; j++) { col = P->col[j]; col->pval = x[j] * col->sjj; col->dval = dir * z[j] / col->sjj; P->ipt_obj += col->coef * col->pval; } /* free working arrays */ xfree(A_ptr); xfree(A_ind); xfree(A_val); xfree(b); xfree(c); xfree(x); xfree(y); xfree(z); return ret; } /* eof */ Rglpk/src/GLPK/glpsql.h0000644000176000001440000000415712245352174014374 0ustar ripleyusers/* glpsql.h */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Author: Heinrich Schuchardt . * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPSQL_H #define GLPSQL_H #define db_iodbc_open _glp_db_iodbc_open void *db_iodbc_open(TABDCA *dca, int mode); /* open iODBC database connection */ #define db_iodbc_read _glp_db_iodbc_read int db_iodbc_read(TABDCA *dca, void *link); /* read data from iODBC */ #define db_iodbc_write _glp_db_iodbc_write int db_iodbc_write(TABDCA *dca, void *link); /* write data to iODBC */ #define db_iodbc_close _glp_db_iodbc_close int db_iodbc_close(TABDCA *dca, void *link); /* close iODBC database connection */ #define db_mysql_open _glp_db_mysql_open void *db_mysql_open(TABDCA *dca, int mode); /* open MySQL database connection */ #define db_mysql_read _glp_db_mysql_read int db_mysql_read(TABDCA *dca, void *link); /* read data from MySQL */ #define db_mysql_write _glp_db_mysql_write int db_mysql_write(TABDCA *dca, void *link); /* write data to MySQL */ #define db_mysql_close _glp_db_mysql_close int db_mysql_close(TABDCA *dca, void *link); /* close MySQL database connection */ #endif /* eof */ Rglpk/src/GLPK/glpapi16.c0000644000176000001440000002563412245352174014513 0ustar ripleyusers/* glpapi16.c (graph and network analysis routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpapi.h" #include "mc13d.h" /*********************************************************************** * NAME * * glp_weak_comp - find all weakly connected components of graph * * SYNOPSIS * * int glp_weak_comp(glp_graph *G, int v_num); * * DESCRIPTION * * The routine glp_weak_comp finds all weakly connected components of * the specified graph. * * The parameter v_num specifies an offset of the field of type int * in the vertex data block, to which the routine stores the number of * a (weakly) connected component containing that vertex. If v_num < 0, * no component numbers are stored. * * The components are numbered in arbitrary order from 1 to nc, where * nc is the total number of components found, 0 <= nc <= |V|. * * RETURNS * * The routine returns nc, the total number of components found. */ int glp_weak_comp(glp_graph *G, int v_num) { glp_vertex *v; glp_arc *a; int f, i, j, nc, nv, pos1, pos2, *prev, *next, *list; if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int)) xerror("glp_weak_comp: v_num = %d; invalid offset\n", v_num); nv = G->nv; if (nv == 0) { nc = 0; goto done; } /* allocate working arrays */ prev = xcalloc(1+nv, sizeof(int)); next = xcalloc(1+nv, sizeof(int)); list = xcalloc(1+nv, sizeof(int)); /* if vertex i is unlabelled, prev[i] is the index of previous unlabelled vertex, and next[i] is the index of next unlabelled vertex; if vertex i is labelled, then prev[i] < 0, and next[i] is the connected component number */ /* initially all vertices are unlabelled */ f = 1; for (i = 1; i <= nv; i++) prev[i] = i - 1, next[i] = i + 1; next[nv] = 0; /* main loop (until all vertices have been labelled) */ nc = 0; while (f != 0) { /* take an unlabelled vertex */ i = f; /* and remove it from the list of unlabelled vertices */ f = next[i]; if (f != 0) prev[f] = 0; /* label the vertex; it begins a new component */ prev[i] = -1, next[i] = ++nc; /* breadth first search */ list[1] = i, pos1 = pos2 = 1; while (pos1 <= pos2) { /* dequeue vertex i */ i = list[pos1++]; /* consider all arcs incoming to vertex i */ for (a = G->v[i]->in; a != NULL; a = a->h_next) { /* vertex j is adjacent to vertex i */ j = a->tail->i; if (prev[j] >= 0) { /* vertex j is unlabelled */ /* remove it from the list of unlabelled vertices */ if (prev[j] == 0) f = next[j]; else next[prev[j]] = next[j]; if (next[j] == 0) ; else prev[next[j]] = prev[j]; /* label the vertex */ prev[j] = -1, next[j] = nc; /* and enqueue it for further consideration */ list[++pos2] = j; } } /* consider all arcs outgoing from vertex i */ for (a = G->v[i]->out; a != NULL; a = a->t_next) { /* vertex j is adjacent to vertex i */ j = a->head->i; if (prev[j] >= 0) { /* vertex j is unlabelled */ /* remove it from the list of unlabelled vertices */ if (prev[j] == 0) f = next[j]; else next[prev[j]] = next[j]; if (next[j] == 0) ; else prev[next[j]] = prev[j]; /* label the vertex */ prev[j] = -1, next[j] = nc; /* and enqueue it for further consideration */ list[++pos2] = j; } } } } /* store component numbers */ if (v_num >= 0) { for (i = 1; i <= nv; i++) { v = G->v[i]; memcpy((char *)v->data + v_num, &next[i], sizeof(int)); } } /* free working arrays */ xfree(prev); xfree(next); xfree(list); done: return nc; } /*********************************************************************** * NAME * * glp_strong_comp - find all strongly connected components of graph * * SYNOPSIS * * int glp_strong_comp(glp_graph *G, int v_num); * * DESCRIPTION * * The routine glp_strong_comp finds all strongly connected components * of the specified graph. * * The parameter v_num specifies an offset of the field of type int * in the vertex data block, to which the routine stores the number of * a strongly connected component containing that vertex. If v_num < 0, * no component numbers are stored. * * The components are numbered in arbitrary order from 1 to nc, where * nc is the total number of components found, 0 <= nc <= |V|. However, * the component numbering has the property that for every arc (i->j) * in the graph the condition num(i) >= num(j) holds. * * RETURNS * * The routine returns nc, the total number of components found. */ int glp_strong_comp(glp_graph *G, int v_num) { glp_vertex *v; glp_arc *a; int i, k, last, n, na, nc, *icn, *ip, *lenr, *ior, *ib, *lowl, *numb, *prev; if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int)) xerror("glp_strong_comp: v_num = %d; invalid offset\n", v_num); n = G->nv; if (n == 0) { nc = 0; goto done; } na = G->na; icn = xcalloc(1+na, sizeof(int)); ip = xcalloc(1+n, sizeof(int)); lenr = xcalloc(1+n, sizeof(int)); ior = xcalloc(1+n, sizeof(int)); ib = xcalloc(1+n, sizeof(int)); lowl = xcalloc(1+n, sizeof(int)); numb = xcalloc(1+n, sizeof(int)); prev = xcalloc(1+n, sizeof(int)); k = 1; for (i = 1; i <= n; i++) { v = G->v[i]; ip[i] = k; for (a = v->out; a != NULL; a = a->t_next) icn[k++] = a->head->i; lenr[i] = k - ip[i]; } xassert(na == k-1); nc = mc13d(n, icn, ip, lenr, ior, ib, lowl, numb, prev); if (v_num >= 0) { xassert(ib[1] == 1); for (k = 1; k <= nc; k++) { last = (k < nc ? ib[k+1] : n+1); xassert(ib[k] < last); for (i = ib[k]; i < last; i++) { v = G->v[ior[i]]; memcpy((char *)v->data + v_num, &k, sizeof(int)); } } } xfree(icn); xfree(ip); xfree(lenr); xfree(ior); xfree(ib); xfree(lowl); xfree(numb); xfree(prev); done: return nc; } /*********************************************************************** * NAME * * glp_top_sort - topological sorting of acyclic digraph * * SYNOPSIS * * int glp_top_sort(glp_graph *G, int v_num); * * DESCRIPTION * * The routine glp_top_sort performs topological sorting of vertices of * the specified acyclic digraph. * * The parameter v_num specifies an offset of the field of type int in * the vertex data block, to which the routine stores the vertex number * assigned. If v_num < 0, vertex numbers are not stored. * * The vertices are numbered from 1 to n, where n is the total number * of vertices in the graph. The vertex numbering has the property that * for every arc (i->j) in the graph the condition num(i) < num(j) * holds. Special case num(i) = 0 means that vertex i is not assigned a * number, because the graph is *not* acyclic. * * RETURNS * * If the graph is acyclic and therefore all the vertices have been * assigned numbers, the routine glp_top_sort returns zero. Otherwise, * if the graph is not acyclic, the routine returns the number of * vertices which have not been numbered, i.e. for which num(i) = 0. */ static int top_sort(glp_graph *G, int num[]) { glp_arc *a; int i, j, cnt, top, *stack, *indeg; /* allocate working arrays */ indeg = xcalloc(1+G->nv, sizeof(int)); stack = xcalloc(1+G->nv, sizeof(int)); /* determine initial indegree of each vertex; push into the stack the vertices having zero indegree */ top = 0; for (i = 1; i <= G->nv; i++) { num[i] = indeg[i] = 0; for (a = G->v[i]->in; a != NULL; a = a->h_next) indeg[i]++; if (indeg[i] == 0) stack[++top] = i; } /* assign numbers to vertices in the sorted order */ cnt = 0; while (top > 0) { /* pull vertex i from the stack */ i = stack[top--]; /* it has zero indegree in the current graph */ xassert(indeg[i] == 0); /* so assign it a next number */ xassert(num[i] == 0); num[i] = ++cnt; /* remove vertex i from the current graph, update indegree of its adjacent vertices, and push into the stack new vertices whose indegree becomes zero */ for (a = G->v[i]->out; a != NULL; a = a->t_next) { j = a->head->i; /* there exists arc (i->j) in the graph */ xassert(indeg[j] > 0); indeg[j]--; if (indeg[j] == 0) stack[++top] = j; } } /* free working arrays */ xfree(indeg); xfree(stack); return G->nv - cnt; } int glp_top_sort(glp_graph *G, int v_num) { glp_vertex *v; int i, cnt, *num; if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int)) xerror("glp_top_sort: v_num = %d; invalid offset\n", v_num); if (G->nv == 0) { cnt = 0; goto done; } num = xcalloc(1+G->nv, sizeof(int)); cnt = top_sort(G, num); if (v_num >= 0) { for (i = 1; i <= G->nv; i++) { v = G->v[i]; memcpy((char *)v->data + v_num, &num[i], sizeof(int)); } } xfree(num); done: return cnt; } /* eof */ Rglpk/src/GLPK/error.c0000644000176000001440000000743112245352174014214 0ustar ripleyusers/* error.c (error handling) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" /*********************************************************************** * NAME * * glp_error - display fatal error message and terminate execution * * SYNOPSIS * * void glp_error(const char *fmt, ...); * * DESCRIPTION * * The routine glp_error (implemented as a macro) formats its * parameters using the format control string fmt, writes the formatted * message on the terminal, and abnormally terminates the program. */ static void errfunc(const char *fmt, ...) { ENV *env = get_env_ptr(); va_list arg; env->term_out = GLP_ON; va_start(arg, fmt); xvprintf(fmt, arg); va_end(arg); xprintf("Error detected in file %s at line %d\n", env->err_file, env->err_line); if (env->err_hook != NULL) env->err_hook(env->err_info); abort(); exit(EXIT_FAILURE); /* no return */ } glp_errfunc glp_error_(const char *file, int line) { ENV *env = get_env_ptr(); env->err_file = file; env->err_line = line; return errfunc; } /*********************************************************************** * NAME * * glp_assert - check for logical condition * * SYNOPSIS * * #include "glplib.h" * void glp_assert(int expr); * * DESCRIPTION * * The routine glp_assert (implemented as a macro) checks for a logical * condition specified by the parameter expr. If the condition is false * (i.e. the value of expr is zero), the routine writes a message on * the terminal and abnormally terminates the program. */ void glp_assert_(const char *expr, const char *file, int line) { glp_error_(file, line)("Assertion failed: %s\n", expr); /* no return */ } /*********************************************************************** * NAME * * glp_error_hook - install hook to intercept abnormal termination * * SYNOPSIS * * void glp_error_hook(void (*func)(void *info), void *info); * * DESCRIPTION * * The routine glp_error_hook installs a user-defined hook routine to * intercept abnormal termination. * * The parameter func specifies the user-defined hook routine. It is * called from the routine glp_error before the latter calls the abort * function to abnormally terminate the application program because of * fatal error. The parameter info is a transit pointer, specified in * the corresponding call to the routine glp_error_hook; it may be used * to pass some information to the hook routine. * * To uninstall the hook routine the parameters func and info should be * both specified as NULL. */ void glp_error_hook(void (*func)(void *info), void *info) { ENV *env = get_env_ptr(); if (func == NULL) { env->err_hook = NULL; env->err_info = NULL; } else { env->err_hook = func; env->err_info = info; } return; } /* eof */ Rglpk/src/GLPK/alloc.c0000644000176000001440000002054012245352174014151 0ustar ripleyusers/* alloc.c (dynamic memory allocation) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #define ALIGN 16 /* some processors need data to be properly aligned, so this macro * defines the alignment boundary, in bytes, provided by glpk memory * allocation routines; looks like 16-byte alignment boundary is * sufficient for all 32- and 64-bit platforms (8-byte boundary is not * sufficient for some 64-bit platforms because of jmp_buf) */ #define MBD_SIZE (((sizeof(MBD) + (ALIGN - 1)) / ALIGN) * ALIGN) /* size of memory block descriptor, in bytes, rounded up to multiple * of the alignment boundary */ /*********************************************************************** * dma - dynamic memory allocation (basic routine) * * This routine performs dynamic memory allocation. It is similar to * the standard realloc function, however, it provides every allocated * memory block with a descriptor, which is used for sanity checks on * reallocating/freeing previously allocated memory blocks as well as * for book-keeping the memory usage statistics. */ static void *dma(const char *func, void *ptr, size_t size) { ENV *env = get_env_ptr(); MBD *mbd; if (ptr == NULL) { /* new memory block will be allocated */ mbd = NULL; } else { /* allocated memory block will be reallocated or freed */ /* get pointer to the block descriptor */ mbd = (MBD *)((char *)ptr - MBD_SIZE); /* make sure that the block descriptor is valid */ if (mbd->self != mbd) xerror("%s: ptr = %p; invalid pointer\n", func, ptr); /* remove the block from the linked list */ mbd->self = NULL; if (mbd->prev == NULL) env->mem_ptr = mbd->next; else mbd->prev->next = mbd->next; if (mbd->next == NULL) ; else mbd->next->prev = mbd->prev; /* decrease usage counts */ if (!(env->mem_count >= 1 && env->mem_total >= mbd->size)) xerror("%s: memory allocation error\n", func); env->mem_count--; env->mem_total -= mbd->size; if (size == 0) { /* free the memory block */ free(mbd); return NULL; } } /* allocate/reallocate memory block */ if (size > SIZE_T_MAX - MBD_SIZE) xerror("%s: block too large\n", func); size += MBD_SIZE; if (size > env->mem_limit - env->mem_total) xerror("%s: memory allocation limit exceeded\n", func); if (env->mem_count == INT_MAX) xerror("%s: too many memory blocks allocated\n", func); mbd = (mbd == NULL ? malloc(size) : realloc(mbd, size)); if (mbd == NULL) xerror("%s: no memory available\n", func); /* setup the block descriptor */ mbd->size = size; mbd->self = mbd; mbd->prev = NULL; mbd->next = env->mem_ptr; /* add the block to the beginning of the linked list */ if (mbd->next != NULL) mbd->next->prev = mbd; env->mem_ptr = mbd; /* increase usage counts */ env->mem_count++; if (env->mem_cpeak < env->mem_count) env->mem_cpeak = env->mem_count; env->mem_total += size; if (env->mem_tpeak < env->mem_total) env->mem_tpeak = env->mem_total; return (char *)mbd + MBD_SIZE; } /*********************************************************************** * NAME * * glp_alloc - allocate memory block * * SYNOPSIS * * void *glp_alloc(int n, int size); * * DESCRIPTION * * The routine glp_alloc allocates a memory block of n * size bytes * long. * * Note that being allocated the memory block contains arbitrary data * (not binary zeros!). * * RETURNS * * The routine glp_alloc returns a pointer to the block allocated. * To free this block the routine glp_free (not free!) must be used. */ void *glp_alloc(int n, int size) { if (n < 1) xerror("glp_alloc: n = %d; invalid parameter\n", n); if (size < 1) xerror("glp_alloc: size = %d; invalid parameter\n", size); if ((size_t)n > SIZE_T_MAX / (size_t)size) xerror("glp_alloc: n = %d, size = %d; block too large\n", n, size); return dma("glp_alloc", NULL, (size_t)n * (size_t)size); } /**********************************************************************/ void *glp_realloc(void *ptr, int n, int size) { /* reallocate memory block */ if (ptr == NULL) xerror("glp_realloc: ptr = %p; invalid pointer\n", ptr); if (n < 1) xerror("glp_realloc: n = %d; invalid parameter\n", n); if (size < 1) xerror("glp_realloc: size = %d; invalid parameter\n", size); if ((size_t)n > SIZE_T_MAX / (size_t)size) xerror("glp_realloc: n = %d, size = %d; block too large\n", n, size); return dma("glp_realloc", ptr, (size_t)n * (size_t)size); } /*********************************************************************** * NAME * * glp_free - free (deallocate) memory block * * SYNOPSIS * * void glp_free(void *ptr); * * DESCRIPTION * * The routine glp_free frees (deallocates) a memory block pointed to * by ptr, which was previuosly allocated by the routine glp_alloc or * reallocated by the routine glp_realloc. */ void glp_free(void *ptr) { if (ptr == NULL) xerror("glp_free: ptr = %p; invalid pointer\n", ptr); dma("glp_free", ptr, 0); return; } /*********************************************************************** * NAME * * glp_mem_limit - set memory usage limit * * SYNOPSIS * * void glp_mem_limit(int limit); * * DESCRIPTION * * The routine glp_mem_limit limits the amount of memory available for * dynamic allocation (in GLPK routines) to limit megabytes. */ void glp_mem_limit(int limit) { ENV *env = get_env_ptr(); if (limit < 1) xerror("glp_mem_limit: limit = %d; invalid parameter\n", limit); if ((size_t)limit <= (SIZE_T_MAX >> 20)) env->mem_limit = (size_t)limit << 20; else env->mem_limit = SIZE_T_MAX; return; } /*********************************************************************** * NAME * * glp_mem_usage - get memory usage information * * SYNOPSIS * * void glp_mem_usage(int *count, int *cpeak, size_t *total, * size_t *tpeak); * * DESCRIPTION * * The routine glp_mem_usage reports some information about utilization * of the memory by GLPK routines. Information is stored to locations * specified by corresponding parameters (see below). Any parameter can * be specified as NULL, in which case its value is not stored. * * *count is the number of the memory blocks currently allocated by the * routines glp_malloc and glp_calloc (one call to glp_malloc or * glp_calloc results in allocating one memory block). * * *cpeak is the peak value of *count reached since the initialization * of the GLPK library environment. * * *total is the total amount, in bytes, of the memory blocks currently * allocated by the routines glp_malloc and glp_calloc. * * *tpeak is the peak value of *total reached since the initialization * of the GLPK library envirionment. */ void glp_mem_usage(int *count, int *cpeak, size_t *total, size_t *tpeak) { ENV *env = get_env_ptr(); if (count != NULL) *count = env->mem_count; if (cpeak != NULL) *cpeak = env->mem_cpeak; if (total != NULL) *total = env->mem_total; if (tpeak != NULL) *tpeak = env->mem_tpeak; return; } /* eof */ Rglpk/src/GLPK/glptsp.h0000644000176000001440000001053312245352174014376 0ustar ripleyusers/* glptsp.h (TSP format) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPTSP_H #define GLPTSP_H typedef struct TSP TSP; struct TSP { /* TSP (or related problem) instance in the format described in the report [G.Reinelt, TSPLIB 95] */ /*--------------------------------------------------------------*/ /* the specification part */ char *name; /* identifies the data file */ int type; /* specifies the type of data: */ #define TSP_UNDEF 0 /* undefined */ #define TSP_TSP 1 /* symmetric TSP */ #define TSP_ATSP 2 /* asymmetric TSP */ #define TSP_TOUR 3 /* collection of tours */ char *comment; /* additional comments (usually the name of the contributor or creator of the problem instance is given here) */ int dimension; /* for a TSP or ATSP, the dimension is the number of its nodes for a TOUR it is the dimension of the corresponding problem */ int edge_weight_type; /* specifies how the edge weights (or distances) are given: */ #define TSP_UNDEF 0 /* undefined */ #define TSP_EXPLICIT 1 /* listed explicitly */ #define TSP_EUC_2D 2 /* Eucl. distances in 2-D */ #define TSP_CEIL_2D 3 /* Eucl. distances in 2-D rounded up */ #define TSP_GEO 4 /* geographical distances */ #define TSP_ATT 5 /* special distance function */ int edge_weight_format; /* describes the format of the edge weights if they are given explicitly: */ #define TSP_UNDEF 0 /* undefined */ #define TSP_FUNCTION 1 /* given by a function */ #define TSP_FULL_MATRIX 2 /* given by a full matrix */ #define TSP_UPPER_ROW 3 /* upper triangulat matrix (row-wise without diagonal entries) */ #define TSP_LOWER_DIAG_ROW 4 /* lower triangular matrix (row-wise including diagonal entries) */ int display_data_type; /* specifies how a graphical display of the nodes can be obtained: */ #define TSP_UNDEF 0 /* undefined */ #define TSP_COORD_DISPLAY 1 /* display is generated from the node coordinates */ #define TSP_TWOD_DISPLAY 2 /* explicit coordinates in 2-D are given */ /*--------------------------------------------------------------*/ /* data part */ /* NODE_COORD_SECTION: */ double *node_x_coord; /* double node_x_coord[1+dimension]; */ double *node_y_coord; /* double node_y_coord[1+dimension]; */ /* DISPLAY_DATA_SECTION: */ double *dply_x_coord; /* double dply_x_coord[1+dimension]; */ double *dply_y_coord; /* double dply_y_coord[1+dimension]; */ /* TOUR_SECTION: */ int *tour; /* int tour[1+dimension]; */ /* EDGE_WEIGHT_SECTION: */ int *edge_weight; /* int edge_weight[1+dimension*dimension]; */ }; #define tsp_read_data _glp_tsp_read_data #define tsp_free_data _glp_tsp_free_data #define tsp_distance _glp_tsp_distance TSP *tsp_read_data(char *fname); /* read TSP instance data */ void tsp_free_data(TSP *tsp); /* free TSP instance data */ int tsp_distance(TSP *tsp, int i, int j); /* compute distance between two nodes */ #endif /* eof */ Rglpk/src/GLPK/glpipm.h0000644000176000001440000000247212245352174014360 0ustar ripleyusers/* glpipm.h (primal-dual interior-point method) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPIPM_H #define GLPIPM_H #include "glpapi.h" #define ipm_solve _glp_ipm_solve int ipm_solve(glp_prob *P, const glp_iptcp *parm); /* core LP solver based on the interior-point method */ #endif /* eof */ Rglpk/src/GLPK/glpmpl01.c0000644000176000001440000052704612245352174014530 0ustar ripleyusers/* glpmpl01.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #define _GLPSTD_STDIO #include "glpmpl.h" #define dmp_get_atomv dmp_get_atom /**********************************************************************/ /* * * PROCESSING MODEL SECTION * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- enter_context - enter current token into context queue. -- -- This routine enters the current token into the context queue. */ void enter_context(MPL *mpl) { char *image, *s; if (mpl->token == T_EOF) image = "_|_"; else if (mpl->token == T_STRING) image = "'...'"; else image = mpl->image; xassert(0 <= mpl->c_ptr && mpl->c_ptr < CONTEXT_SIZE); mpl->context[mpl->c_ptr++] = ' '; if (mpl->c_ptr == CONTEXT_SIZE) mpl->c_ptr = 0; for (s = image; *s != '\0'; s++) { mpl->context[mpl->c_ptr++] = *s; if (mpl->c_ptr == CONTEXT_SIZE) mpl->c_ptr = 0; } return; } /*---------------------------------------------------------------------- -- print_context - print current content of context queue. -- -- This routine prints current content of the context queue. */ void print_context(MPL *mpl) { int c; while (mpl->c_ptr > 0) { mpl->c_ptr--; c = mpl->context[0]; memmove(mpl->context, mpl->context+1, CONTEXT_SIZE-1); mpl->context[CONTEXT_SIZE-1] = (char)c; } xprintf("Context: %s%.*s\n", mpl->context[0] == ' ' ? "" : "...", CONTEXT_SIZE, mpl->context); return; } /*---------------------------------------------------------------------- -- get_char - scan next character from input text file. -- -- This routine scans a next ASCII character from the input text file. -- In case of end-of-file, the character is assigned EOF. */ void get_char(MPL *mpl) { int c; if (mpl->c == EOF) goto done; if (mpl->c == '\n') mpl->line++; c = read_char(mpl); if (c == EOF) { if (mpl->c == '\n') mpl->line--; else warning(mpl, "final NL missing before end of file"); } else if (c == '\n') ; else if (isspace(c)) c = ' '; else if (iscntrl(c)) { enter_context(mpl); error(mpl, "control character 0x%02X not allowed", c); } mpl->c = c; done: return; } /*---------------------------------------------------------------------- -- append_char - append character to current token. -- -- This routine appends the current character to the current token and -- then scans a next character. */ void append_char(MPL *mpl) { xassert(0 <= mpl->imlen && mpl->imlen <= MAX_LENGTH); if (mpl->imlen == MAX_LENGTH) { switch (mpl->token) { case T_NAME: enter_context(mpl); error(mpl, "symbolic name %s... too long", mpl->image); case T_SYMBOL: enter_context(mpl); error(mpl, "symbol %s... too long", mpl->image); case T_NUMBER: enter_context(mpl); error(mpl, "numeric literal %s... too long", mpl->image); case T_STRING: enter_context(mpl); error(mpl, "string literal too long"); default: xassert(mpl != mpl); } } mpl->image[mpl->imlen++] = (char)mpl->c; mpl->image[mpl->imlen] = '\0'; get_char(mpl); return; } /*---------------------------------------------------------------------- -- get_token - scan next token from input text file. -- -- This routine scans a next token from the input text file using the -- standard finite automation technique. */ void get_token(MPL *mpl) { /* save the current token */ mpl->b_token = mpl->token; mpl->b_imlen = mpl->imlen; strcpy(mpl->b_image, mpl->image); mpl->b_value = mpl->value; /* if the next token is already scanned, make it current */ if (mpl->f_scan) { mpl->f_scan = 0; mpl->token = mpl->f_token; mpl->imlen = mpl->f_imlen; strcpy(mpl->image, mpl->f_image); mpl->value = mpl->f_value; goto done; } loop: /* nothing has been scanned so far */ mpl->token = 0; mpl->imlen = 0; mpl->image[0] = '\0'; mpl->value = 0.0; /* skip any uninteresting characters */ while (mpl->c == ' ' || mpl->c == '\n') get_char(mpl); /* recognize and construct the token */ if (mpl->c == EOF) { /* end-of-file reached */ mpl->token = T_EOF; } else if (mpl->c == '#') { /* comment; skip anything until end-of-line */ while (mpl->c != '\n' && mpl->c != EOF) get_char(mpl); goto loop; } else if (!mpl->flag_d && (isalpha(mpl->c) || mpl->c == '_')) { /* symbolic name or reserved keyword */ mpl->token = T_NAME; while (isalnum(mpl->c) || mpl->c == '_') append_char(mpl); if (strcmp(mpl->image, "and") == 0) mpl->token = T_AND; else if (strcmp(mpl->image, "by") == 0) mpl->token = T_BY; else if (strcmp(mpl->image, "cross") == 0) mpl->token = T_CROSS; else if (strcmp(mpl->image, "diff") == 0) mpl->token = T_DIFF; else if (strcmp(mpl->image, "div") == 0) mpl->token = T_DIV; else if (strcmp(mpl->image, "else") == 0) mpl->token = T_ELSE; else if (strcmp(mpl->image, "if") == 0) mpl->token = T_IF; else if (strcmp(mpl->image, "in") == 0) mpl->token = T_IN; #if 1 /* 21/VII-2006 */ else if (strcmp(mpl->image, "Infinity") == 0) mpl->token = T_INFINITY; #endif else if (strcmp(mpl->image, "inter") == 0) mpl->token = T_INTER; else if (strcmp(mpl->image, "less") == 0) mpl->token = T_LESS; else if (strcmp(mpl->image, "mod") == 0) mpl->token = T_MOD; else if (strcmp(mpl->image, "not") == 0) mpl->token = T_NOT; else if (strcmp(mpl->image, "or") == 0) mpl->token = T_OR; else if (strcmp(mpl->image, "s") == 0 && mpl->c == '.') { mpl->token = T_SPTP; append_char(mpl); if (mpl->c != 't') sptp: { enter_context(mpl); error(mpl, "keyword s.t. incomplete"); } append_char(mpl); if (mpl->c != '.') goto sptp; append_char(mpl); } else if (strcmp(mpl->image, "symdiff") == 0) mpl->token = T_SYMDIFF; else if (strcmp(mpl->image, "then") == 0) mpl->token = T_THEN; else if (strcmp(mpl->image, "union") == 0) mpl->token = T_UNION; else if (strcmp(mpl->image, "within") == 0) mpl->token = T_WITHIN; } else if (!mpl->flag_d && isdigit(mpl->c)) { /* numeric literal */ mpl->token = T_NUMBER; /* scan integer part */ while (isdigit(mpl->c)) append_char(mpl); /* scan optional fractional part */ if (mpl->c == '.') { append_char(mpl); if (mpl->c == '.') { /* hmm, it is not the fractional part, it is dots that follow the integer part */ mpl->imlen--; mpl->image[mpl->imlen] = '\0'; mpl->f_dots = 1; goto conv; } frac: while (isdigit(mpl->c)) append_char(mpl); } /* scan optional decimal exponent */ if (mpl->c == 'e' || mpl->c == 'E') { append_char(mpl); if (mpl->c == '+' || mpl->c == '-') append_char(mpl); if (!isdigit(mpl->c)) { enter_context(mpl); error(mpl, "numeric literal %s incomplete", mpl->image); } while (isdigit(mpl->c)) append_char(mpl); } /* there must be no letter following the numeric literal */ if (isalpha(mpl->c) || mpl->c == '_') { enter_context(mpl); error(mpl, "symbol %s%c... should be enclosed in quotes", mpl->image, mpl->c); } conv: /* convert numeric literal to floating-point */ if (str2num(mpl->image, &mpl->value)) err: { enter_context(mpl); error(mpl, "cannot convert numeric literal %s to floating-p" "oint number", mpl->image); } } else if (mpl->c == '\'' || mpl->c == '"') { /* character string */ int quote = mpl->c; mpl->token = T_STRING; get_char(mpl); for (;;) { if (mpl->c == '\n' || mpl->c == EOF) { enter_context(mpl); error(mpl, "unexpected end of line; string literal incom" "plete"); } if (mpl->c == quote) { get_char(mpl); if (mpl->c != quote) break; } append_char(mpl); } } else if (!mpl->flag_d && mpl->c == '+') mpl->token = T_PLUS, append_char(mpl); else if (!mpl->flag_d && mpl->c == '-') mpl->token = T_MINUS, append_char(mpl); else if (mpl->c == '*') { mpl->token = T_ASTERISK, append_char(mpl); if (mpl->c == '*') mpl->token = T_POWER, append_char(mpl); } else if (mpl->c == '/') { mpl->token = T_SLASH, append_char(mpl); if (mpl->c == '*') { /* comment sequence */ get_char(mpl); for (;;) { if (mpl->c == EOF) { /* do not call enter_context at this point */ error(mpl, "unexpected end of file; comment sequence " "incomplete"); } else if (mpl->c == '*') { get_char(mpl); if (mpl->c == '/') break; } else get_char(mpl); } get_char(mpl); goto loop; } } else if (mpl->c == '^') mpl->token = T_POWER, append_char(mpl); else if (mpl->c == '<') { mpl->token = T_LT, append_char(mpl); if (mpl->c == '=') mpl->token = T_LE, append_char(mpl); else if (mpl->c == '>') mpl->token = T_NE, append_char(mpl); #if 1 /* 11/II-2008 */ else if (mpl->c == '-') mpl->token = T_INPUT, append_char(mpl); #endif } else if (mpl->c == '=') { mpl->token = T_EQ, append_char(mpl); if (mpl->c == '=') append_char(mpl); } else if (mpl->c == '>') { mpl->token = T_GT, append_char(mpl); if (mpl->c == '=') mpl->token = T_GE, append_char(mpl); #if 1 /* 14/VII-2006 */ else if (mpl->c == '>') mpl->token = T_APPEND, append_char(mpl); #endif } else if (mpl->c == '!') { mpl->token = T_NOT, append_char(mpl); if (mpl->c == '=') mpl->token = T_NE, append_char(mpl); } else if (mpl->c == '&') { mpl->token = T_CONCAT, append_char(mpl); if (mpl->c == '&') mpl->token = T_AND, append_char(mpl); } else if (mpl->c == '|') { mpl->token = T_BAR, append_char(mpl); if (mpl->c == '|') mpl->token = T_OR, append_char(mpl); } else if (!mpl->flag_d && mpl->c == '.') { mpl->token = T_POINT, append_char(mpl); if (mpl->f_dots) { /* dots; the first dot was read on the previous call to the scanner, so the current character is the second dot */ mpl->token = T_DOTS; mpl->imlen = 2; strcpy(mpl->image, ".."); mpl->f_dots = 0; } else if (mpl->c == '.') mpl->token = T_DOTS, append_char(mpl); else if (isdigit(mpl->c)) { /* numeric literal that begins with the decimal point */ mpl->token = T_NUMBER, append_char(mpl); goto frac; } } else if (mpl->c == ',') mpl->token = T_COMMA, append_char(mpl); else if (mpl->c == ':') { mpl->token = T_COLON, append_char(mpl); if (mpl->c == '=') mpl->token = T_ASSIGN, append_char(mpl); } else if (mpl->c == ';') mpl->token = T_SEMICOLON, append_char(mpl); else if (mpl->c == '(') mpl->token = T_LEFT, append_char(mpl); else if (mpl->c == ')') mpl->token = T_RIGHT, append_char(mpl); else if (mpl->c == '[') mpl->token = T_LBRACKET, append_char(mpl); else if (mpl->c == ']') mpl->token = T_RBRACKET, append_char(mpl); else if (mpl->c == '{') mpl->token = T_LBRACE, append_char(mpl); else if (mpl->c == '}') mpl->token = T_RBRACE, append_char(mpl); #if 1 /* 11/II-2008 */ else if (mpl->c == '~') mpl->token = T_TILDE, append_char(mpl); #endif else if (isalnum(mpl->c) || strchr("+-._", mpl->c) != NULL) { /* symbol */ xassert(mpl->flag_d); mpl->token = T_SYMBOL; while (isalnum(mpl->c) || strchr("+-._", mpl->c) != NULL) append_char(mpl); switch (str2num(mpl->image, &mpl->value)) { case 0: mpl->token = T_NUMBER; break; case 1: goto err; case 2: break; default: xassert(mpl != mpl); } } else { enter_context(mpl); error(mpl, "character %c not allowed", mpl->c); } /* enter the current token into the context queue */ enter_context(mpl); /* reset the flag, which may be set by indexing_expression() and is used by expression_list() */ mpl->flag_x = 0; done: return; } /*---------------------------------------------------------------------- -- unget_token - return current token back to input stream. -- -- This routine returns the current token back to the input stream, so -- the previously scanned token becomes the current one. */ void unget_token(MPL *mpl) { /* save the current token, which becomes the next one */ xassert(!mpl->f_scan); mpl->f_scan = 1; mpl->f_token = mpl->token; mpl->f_imlen = mpl->imlen; strcpy(mpl->f_image, mpl->image); mpl->f_value = mpl->value; /* restore the previous token, which becomes the current one */ mpl->token = mpl->b_token; mpl->imlen = mpl->b_imlen; strcpy(mpl->image, mpl->b_image); mpl->value = mpl->b_value; return; } /*---------------------------------------------------------------------- -- is_keyword - check if current token is given non-reserved keyword. -- -- If the current token is given (non-reserved) keyword, this routine -- returns non-zero. Otherwise zero is returned. */ int is_keyword(MPL *mpl, char *keyword) { return mpl->token == T_NAME && strcmp(mpl->image, keyword) == 0; } /*---------------------------------------------------------------------- -- is_reserved - check if current token is reserved keyword. -- -- If the current token is a reserved keyword, this routine returns -- non-zero. Otherwise zero is returned. */ int is_reserved(MPL *mpl) { return mpl->token == T_AND && mpl->image[0] == 'a' || mpl->token == T_BY || mpl->token == T_CROSS || mpl->token == T_DIFF || mpl->token == T_DIV || mpl->token == T_ELSE || mpl->token == T_IF || mpl->token == T_IN || mpl->token == T_INTER || mpl->token == T_LESS || mpl->token == T_MOD || mpl->token == T_NOT && mpl->image[0] == 'n' || mpl->token == T_OR && mpl->image[0] == 'o' || mpl->token == T_SYMDIFF || mpl->token == T_THEN || mpl->token == T_UNION || mpl->token == T_WITHIN; } /*---------------------------------------------------------------------- -- make_code - generate pseudo-code (basic routine). -- -- This routine generates specified pseudo-code. It is assumed that all -- other translator routines use this basic routine. */ CODE *make_code(MPL *mpl, int op, OPERANDS *arg, int type, int dim) { CODE *code; DOMAIN *domain; DOMAIN_BLOCK *block; ARG_LIST *e; /* generate pseudo-code */ code = alloc(CODE); code->op = op; code->vflag = 0; /* is inherited from operand(s) */ /* copy operands and also make them referring to the pseudo-code being generated, because the latter becomes the parent for all its operands */ memset(&code->arg, '?', sizeof(OPERANDS)); switch (op) { case O_NUMBER: code->arg.num = arg->num; break; case O_STRING: code->arg.str = arg->str; break; case O_INDEX: code->arg.index.slot = arg->index.slot; code->arg.index.next = arg->index.next; break; case O_MEMNUM: case O_MEMSYM: for (e = arg->par.list; e != NULL; e = e->next) { xassert(e->x != NULL); xassert(e->x->up == NULL); e->x->up = code; code->vflag |= e->x->vflag; } code->arg.par.par = arg->par.par; code->arg.par.list = arg->par.list; break; case O_MEMSET: for (e = arg->set.list; e != NULL; e = e->next) { xassert(e->x != NULL); xassert(e->x->up == NULL); e->x->up = code; code->vflag |= e->x->vflag; } code->arg.set.set = arg->set.set; code->arg.set.list = arg->set.list; break; case O_MEMVAR: for (e = arg->var.list; e != NULL; e = e->next) { xassert(e->x != NULL); xassert(e->x->up == NULL); e->x->up = code; code->vflag |= e->x->vflag; } code->arg.var.var = arg->var.var; code->arg.var.list = arg->var.list; #if 1 /* 15/V-2010 */ code->arg.var.suff = arg->var.suff; #endif break; #if 1 /* 15/V-2010 */ case O_MEMCON: for (e = arg->con.list; e != NULL; e = e->next) { xassert(e->x != NULL); xassert(e->x->up == NULL); e->x->up = code; code->vflag |= e->x->vflag; } code->arg.con.con = arg->con.con; code->arg.con.list = arg->con.list; code->arg.con.suff = arg->con.suff; break; #endif case O_TUPLE: case O_MAKE: for (e = arg->list; e != NULL; e = e->next) { xassert(e->x != NULL); xassert(e->x->up == NULL); e->x->up = code; code->vflag |= e->x->vflag; } code->arg.list = arg->list; break; case O_SLICE: xassert(arg->slice != NULL); code->arg.slice = arg->slice; break; case O_IRAND224: case O_UNIFORM01: case O_NORMAL01: case O_GMTIME: code->vflag = 1; break; case O_CVTNUM: case O_CVTSYM: case O_CVTLOG: case O_CVTTUP: case O_CVTLFM: case O_PLUS: case O_MINUS: case O_NOT: case O_ABS: case O_CEIL: case O_FLOOR: case O_EXP: case O_LOG: case O_LOG10: case O_SQRT: case O_SIN: case O_COS: case O_ATAN: case O_ROUND: case O_TRUNC: case O_CARD: case O_LENGTH: /* unary operation */ xassert(arg->arg.x != NULL); xassert(arg->arg.x->up == NULL); arg->arg.x->up = code; code->vflag |= arg->arg.x->vflag; code->arg.arg.x = arg->arg.x; break; case O_ADD: case O_SUB: case O_LESS: case O_MUL: case O_DIV: case O_IDIV: case O_MOD: case O_POWER: case O_ATAN2: case O_ROUND2: case O_TRUNC2: case O_UNIFORM: if (op == O_UNIFORM) code->vflag = 1; case O_NORMAL: if (op == O_NORMAL) code->vflag = 1; case O_CONCAT: case O_LT: case O_LE: case O_EQ: case O_GE: case O_GT: case O_NE: case O_AND: case O_OR: case O_UNION: case O_DIFF: case O_SYMDIFF: case O_INTER: case O_CROSS: case O_IN: case O_NOTIN: case O_WITHIN: case O_NOTWITHIN: case O_SUBSTR: case O_STR2TIME: case O_TIME2STR: /* binary operation */ xassert(arg->arg.x != NULL); xassert(arg->arg.x->up == NULL); arg->arg.x->up = code; code->vflag |= arg->arg.x->vflag; xassert(arg->arg.y != NULL); xassert(arg->arg.y->up == NULL); arg->arg.y->up = code; code->vflag |= arg->arg.y->vflag; code->arg.arg.x = arg->arg.x; code->arg.arg.y = arg->arg.y; break; case O_DOTS: case O_FORK: case O_SUBSTR3: /* ternary operation */ xassert(arg->arg.x != NULL); xassert(arg->arg.x->up == NULL); arg->arg.x->up = code; code->vflag |= arg->arg.x->vflag; xassert(arg->arg.y != NULL); xassert(arg->arg.y->up == NULL); arg->arg.y->up = code; code->vflag |= arg->arg.y->vflag; if (arg->arg.z != NULL) { xassert(arg->arg.z->up == NULL); arg->arg.z->up = code; code->vflag |= arg->arg.z->vflag; } code->arg.arg.x = arg->arg.x; code->arg.arg.y = arg->arg.y; code->arg.arg.z = arg->arg.z; break; case O_MIN: case O_MAX: /* n-ary operation */ for (e = arg->list; e != NULL; e = e->next) { xassert(e->x != NULL); xassert(e->x->up == NULL); e->x->up = code; code->vflag |= e->x->vflag; } code->arg.list = arg->list; break; case O_SUM: case O_PROD: case O_MINIMUM: case O_MAXIMUM: case O_FORALL: case O_EXISTS: case O_SETOF: case O_BUILD: /* iterated operation */ domain = arg->loop.domain; xassert(domain != NULL); if (domain->code != NULL) { xassert(domain->code->up == NULL); domain->code->up = code; code->vflag |= domain->code->vflag; } for (block = domain->list; block != NULL; block = block->next) { xassert(block->code != NULL); xassert(block->code->up == NULL); block->code->up = code; code->vflag |= block->code->vflag; } if (arg->loop.x != NULL) { xassert(arg->loop.x->up == NULL); arg->loop.x->up = code; code->vflag |= arg->loop.x->vflag; } code->arg.loop.domain = arg->loop.domain; code->arg.loop.x = arg->loop.x; break; default: xassert(op != op); } /* set other attributes of the pseudo-code */ code->type = type; code->dim = dim; code->up = NULL; code->valid = 0; memset(&code->value, '?', sizeof(VALUE)); return code; } /*---------------------------------------------------------------------- -- make_unary - generate pseudo-code for unary operation. -- -- This routine generates pseudo-code for unary operation. */ CODE *make_unary(MPL *mpl, int op, CODE *x, int type, int dim) { CODE *code; OPERANDS arg; xassert(x != NULL); arg.arg.x = x; code = make_code(mpl, op, &arg, type, dim); return code; } /*---------------------------------------------------------------------- -- make_binary - generate pseudo-code for binary operation. -- -- This routine generates pseudo-code for binary operation. */ CODE *make_binary(MPL *mpl, int op, CODE *x, CODE *y, int type, int dim) { CODE *code; OPERANDS arg; xassert(x != NULL); xassert(y != NULL); arg.arg.x = x; arg.arg.y = y; code = make_code(mpl, op, &arg, type, dim); return code; } /*---------------------------------------------------------------------- -- make_ternary - generate pseudo-code for ternary operation. -- -- This routine generates pseudo-code for ternary operation. */ CODE *make_ternary(MPL *mpl, int op, CODE *x, CODE *y, CODE *z, int type, int dim) { CODE *code; OPERANDS arg; xassert(x != NULL); xassert(y != NULL); /* third operand can be NULL */ arg.arg.x = x; arg.arg.y = y; arg.arg.z = z; code = make_code(mpl, op, &arg, type, dim); return code; } /*---------------------------------------------------------------------- -- numeric_literal - parse reference to numeric literal. -- -- This routine parses primary expression using the syntax: -- -- ::= */ CODE *numeric_literal(MPL *mpl) { CODE *code; OPERANDS arg; xassert(mpl->token == T_NUMBER); arg.num = mpl->value; code = make_code(mpl, O_NUMBER, &arg, A_NUMERIC, 0); get_token(mpl /* */); return code; } /*---------------------------------------------------------------------- -- string_literal - parse reference to string literal. -- -- This routine parses primary expression using the syntax: -- -- ::= */ CODE *string_literal(MPL *mpl) { CODE *code; OPERANDS arg; xassert(mpl->token == T_STRING); arg.str = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1); strcpy(arg.str, mpl->image); code = make_code(mpl, O_STRING, &arg, A_SYMBOLIC, 0); get_token(mpl /* */); return code; } /*---------------------------------------------------------------------- -- create_arg_list - create empty operands list. -- -- This routine creates operands list, which is initially empty. */ ARG_LIST *create_arg_list(MPL *mpl) { ARG_LIST *list; xassert(mpl == mpl); list = NULL; return list; } /*---------------------------------------------------------------------- -- expand_arg_list - append operand to operands list. -- -- This routine appends new operand to specified operands list. */ ARG_LIST *expand_arg_list(MPL *mpl, ARG_LIST *list, CODE *x) { ARG_LIST *tail, *temp; xassert(x != NULL); /* create new operands list entry */ tail = alloc(ARG_LIST); tail->x = x; tail->next = NULL; /* and append it to the operands list */ if (list == NULL) list = tail; else { for (temp = list; temp->next != NULL; temp = temp->next); temp->next = tail; } return list; } /*---------------------------------------------------------------------- -- arg_list_len - determine length of operands list. -- -- This routine returns the number of operands in operands list. */ int arg_list_len(MPL *mpl, ARG_LIST *list) { ARG_LIST *temp; int len; xassert(mpl == mpl); len = 0; for (temp = list; temp != NULL; temp = temp->next) len++; return len; } /*---------------------------------------------------------------------- -- subscript_list - parse subscript list. -- -- This routine parses subscript list using the syntax: -- -- ::= -- ::= , -- ::= */ ARG_LIST *subscript_list(MPL *mpl) { ARG_LIST *list; CODE *x; list = create_arg_list(mpl); for (;;) { /* parse subscript expression */ x = expression_5(mpl); /* convert it to symbolic type, if necessary */ if (x->type == A_NUMERIC) x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0); /* check that now the expression is of symbolic type */ if (x->type != A_SYMBOLIC) error(mpl, "subscript expression has invalid type"); xassert(x->dim == 0); /* and append it to the subscript list */ list = expand_arg_list(mpl, list, x); /* check a token that follows the subscript expression */ if (mpl->token == T_COMMA) get_token(mpl /* , */); else if (mpl->token == T_RBRACKET) break; else error(mpl, "syntax error in subscript list"); } return list; } #if 1 /* 15/V-2010 */ /*---------------------------------------------------------------------- -- object_reference - parse reference to named object. -- -- This routine parses primary expression using the syntax: -- -- ::= -- ::= -- ::= [ ] -- ::= -- ::= [ ] -- ::= -- ::= [ ] -- -- ::= -- ::= [ ] -- -- ::= -- ::= -- ::= -- ::= -- ::= -- ::= | .lb | .ub | .status | .val | .dual */ CODE *object_reference(MPL *mpl) { AVLNODE *node; DOMAIN_SLOT *slot; SET *set; PARAMETER *par; VARIABLE *var; CONSTRAINT *con; ARG_LIST *list; OPERANDS arg; CODE *code; char *name; int dim, suff; /* find the object in the symbolic name table */ xassert(mpl->token == T_NAME); node = avl_find_node(mpl->tree, mpl->image); if (node == NULL) error(mpl, "%s not defined", mpl->image); /* check the object type and obtain its dimension */ switch (avl_get_node_type(node)) { case A_INDEX: /* dummy index */ slot = (DOMAIN_SLOT *)avl_get_node_link(node); name = slot->name; dim = 0; break; case A_SET: /* model set */ set = (SET *)avl_get_node_link(node); name = set->name; dim = set->dim; /* if a set object is referenced in its own declaration and the dimen attribute is not specified yet, use dimen 1 by default */ if (set->dimen == 0) set->dimen = 1; break; case A_PARAMETER: /* model parameter */ par = (PARAMETER *)avl_get_node_link(node); name = par->name; dim = par->dim; break; case A_VARIABLE: /* model variable */ var = (VARIABLE *)avl_get_node_link(node); name = var->name; dim = var->dim; break; case A_CONSTRAINT: /* model constraint or objective */ con = (CONSTRAINT *)avl_get_node_link(node); name = con->name; dim = con->dim; break; default: xassert(node != node); } get_token(mpl /* */); /* parse optional subscript list */ if (mpl->token == T_LBRACKET) { /* subscript list is specified */ if (dim == 0) error(mpl, "%s cannot be subscripted", name); get_token(mpl /* [ */); list = subscript_list(mpl); if (dim != arg_list_len(mpl, list)) error(mpl, "%s must have %d subscript%s rather than %d", name, dim, dim == 1 ? "" : "s", arg_list_len(mpl, list)); xassert(mpl->token == T_RBRACKET); get_token(mpl /* ] */); } else { /* subscript list is not specified */ if (dim != 0) error(mpl, "%s must be subscripted", name); list = create_arg_list(mpl); } /* parse optional suffix */ if (!mpl->flag_s && avl_get_node_type(node) == A_VARIABLE) suff = DOT_NONE; else suff = DOT_VAL; if (mpl->token == T_POINT) { get_token(mpl /* . */); if (mpl->token != T_NAME) error(mpl, "invalid use of period"); if (!(avl_get_node_type(node) == A_VARIABLE || avl_get_node_type(node) == A_CONSTRAINT)) error(mpl, "%s cannot have a suffix", name); if (strcmp(mpl->image, "lb") == 0) suff = DOT_LB; else if (strcmp(mpl->image, "ub") == 0) suff = DOT_UB; else if (strcmp(mpl->image, "status") == 0) suff = DOT_STATUS; else if (strcmp(mpl->image, "val") == 0) suff = DOT_VAL; else if (strcmp(mpl->image, "dual") == 0) suff = DOT_DUAL; else error(mpl, "suffix .%s invalid", mpl->image); get_token(mpl /* suffix */); } /* generate pseudo-code to take value of the object */ switch (avl_get_node_type(node)) { case A_INDEX: arg.index.slot = slot; arg.index.next = slot->list; code = make_code(mpl, O_INDEX, &arg, A_SYMBOLIC, 0); slot->list = code; break; case A_SET: arg.set.set = set; arg.set.list = list; code = make_code(mpl, O_MEMSET, &arg, A_ELEMSET, set->dimen); break; case A_PARAMETER: arg.par.par = par; arg.par.list = list; if (par->type == A_SYMBOLIC) code = make_code(mpl, O_MEMSYM, &arg, A_SYMBOLIC, 0); else code = make_code(mpl, O_MEMNUM, &arg, A_NUMERIC, 0); break; case A_VARIABLE: if (!mpl->flag_s && (suff == DOT_STATUS || suff == DOT_VAL || suff == DOT_DUAL)) error(mpl, "invalid reference to status, primal value, o" "r dual value of variable %s above solve statement", var->name); arg.var.var = var; arg.var.list = list; arg.var.suff = suff; code = make_code(mpl, O_MEMVAR, &arg, suff == DOT_NONE ? A_FORMULA : A_NUMERIC, 0); break; case A_CONSTRAINT: if (!mpl->flag_s && (suff == DOT_STATUS || suff == DOT_VAL || suff == DOT_DUAL)) error(mpl, "invalid reference to status, primal value, o" "r dual value of %s %s above solve statement", con->type == A_CONSTRAINT ? "constraint" : "objective" , con->name); arg.con.con = con; arg.con.list = list; arg.con.suff = suff; code = make_code(mpl, O_MEMCON, &arg, A_NUMERIC, 0); break; default: xassert(node != node); } return code; } #endif /*---------------------------------------------------------------------- -- numeric_argument - parse argument passed to built-in function. -- -- This routine parses an argument passed to numeric built-in function -- using the syntax: -- -- ::= */ CODE *numeric_argument(MPL *mpl, char *func) { CODE *x; x = expression_5(mpl); /* convert the argument to numeric type, if necessary */ if (x->type == A_SYMBOLIC) x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0); /* check that now the argument is of numeric type */ if (x->type != A_NUMERIC) error(mpl, "argument for %s has invalid type", func); xassert(x->dim == 0); return x; } #if 1 /* 15/VII-2006 */ CODE *symbolic_argument(MPL *mpl, char *func) { CODE *x; x = expression_5(mpl); /* convert the argument to symbolic type, if necessary */ if (x->type == A_NUMERIC) x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0); /* check that now the argument is of symbolic type */ if (x->type != A_SYMBOLIC) error(mpl, "argument for %s has invalid type", func); xassert(x->dim == 0); return x; } #endif #if 1 /* 15/VII-2006 */ CODE *elemset_argument(MPL *mpl, char *func) { CODE *x; x = expression_9(mpl); if (x->type != A_ELEMSET) error(mpl, "argument for %s has invalid type", func); xassert(x->dim > 0); return x; } #endif /*---------------------------------------------------------------------- -- function_reference - parse reference to built-in function. -- -- This routine parses primary expression using the syntax: -- -- ::= abs ( ) -- ::= ceil ( ) -- ::= floor ( ) -- ::= exp ( ) -- ::= log ( ) -- ::= log10 ( ) -- ::= max ( ) -- ::= min ( ) -- ::= sqrt ( ) -- ::= sin ( ) -- ::= cos ( ) -- ::= atan ( ) -- ::= atan2 ( , ) -- ::= round ( ) -- ::= round ( , ) -- ::= trunc ( ) -- ::= trunc ( , ) -- ::= Irand224 ( ) -- ::= Uniform01 ( ) -- ::= Uniform ( , ) -- ::= Normal01 ( ) -- ::= Normal ( , ) -- ::= card ( ) -- ::= length ( ) -- ::= substr ( , ) -- ::= substr ( , , ) -- ::= str2time ( , ) -- ::= time2str ( , ) -- ::= gmtime ( ) -- ::= -- ::= , */ CODE *function_reference(MPL *mpl) { CODE *code; OPERANDS arg; int op; char func[15+1]; /* determine operation code */ xassert(mpl->token == T_NAME); if (strcmp(mpl->image, "abs") == 0) op = O_ABS; else if (strcmp(mpl->image, "ceil") == 0) op = O_CEIL; else if (strcmp(mpl->image, "floor") == 0) op = O_FLOOR; else if (strcmp(mpl->image, "exp") == 0) op = O_EXP; else if (strcmp(mpl->image, "log") == 0) op = O_LOG; else if (strcmp(mpl->image, "log10") == 0) op = O_LOG10; else if (strcmp(mpl->image, "sqrt") == 0) op = O_SQRT; else if (strcmp(mpl->image, "sin") == 0) op = O_SIN; else if (strcmp(mpl->image, "cos") == 0) op = O_COS; else if (strcmp(mpl->image, "atan") == 0) op = O_ATAN; else if (strcmp(mpl->image, "min") == 0) op = O_MIN; else if (strcmp(mpl->image, "max") == 0) op = O_MAX; else if (strcmp(mpl->image, "round") == 0) op = O_ROUND; else if (strcmp(mpl->image, "trunc") == 0) op = O_TRUNC; else if (strcmp(mpl->image, "Irand224") == 0) op = O_IRAND224; else if (strcmp(mpl->image, "Uniform01") == 0) op = O_UNIFORM01; else if (strcmp(mpl->image, "Uniform") == 0) op = O_UNIFORM; else if (strcmp(mpl->image, "Normal01") == 0) op = O_NORMAL01; else if (strcmp(mpl->image, "Normal") == 0) op = O_NORMAL; else if (strcmp(mpl->image, "card") == 0) op = O_CARD; else if (strcmp(mpl->image, "length") == 0) op = O_LENGTH; else if (strcmp(mpl->image, "substr") == 0) op = O_SUBSTR; else if (strcmp(mpl->image, "str2time") == 0) op = O_STR2TIME; else if (strcmp(mpl->image, "time2str") == 0) op = O_TIME2STR; else if (strcmp(mpl->image, "gmtime") == 0) op = O_GMTIME; else error(mpl, "function %s unknown", mpl->image); /* save symbolic name of the function */ strcpy(func, mpl->image); xassert(strlen(func) < sizeof(func)); get_token(mpl /* */); /* check the left parenthesis that follows the function name */ xassert(mpl->token == T_LEFT); get_token(mpl /* ( */); /* parse argument list */ if (op == O_MIN || op == O_MAX) { /* min and max allow arbitrary number of arguments */ arg.list = create_arg_list(mpl); /* parse argument list */ for (;;) { /* parse argument and append it to the operands list */ arg.list = expand_arg_list(mpl, arg.list, numeric_argument(mpl, func)); /* check a token that follows the argument */ if (mpl->token == T_COMMA) get_token(mpl /* , */); else if (mpl->token == T_RIGHT) break; else error(mpl, "syntax error in argument list for %s", func); } } else if (op == O_IRAND224 || op == O_UNIFORM01 || op == O_NORMAL01 || op == O_GMTIME) { /* Irand224, Uniform01, Normal01, gmtime need no arguments */ if (mpl->token != T_RIGHT) error(mpl, "%s needs no arguments", func); } else if (op == O_UNIFORM || op == O_NORMAL) { /* Uniform and Normal need two arguments */ /* parse the first argument */ arg.arg.x = numeric_argument(mpl, func); /* check a token that follows the first argument */ if (mpl->token == T_COMMA) ; else if (mpl->token == T_RIGHT) error(mpl, "%s needs two arguments", func); else error(mpl, "syntax error in argument for %s", func); get_token(mpl /* , */); /* parse the second argument */ arg.arg.y = numeric_argument(mpl, func); /* check a token that follows the second argument */ if (mpl->token == T_COMMA) error(mpl, "%s needs two argument", func); else if (mpl->token == T_RIGHT) ; else error(mpl, "syntax error in argument for %s", func); } else if (op == O_ATAN || op == O_ROUND || op == O_TRUNC) { /* atan, round, and trunc need one or two arguments */ /* parse the first argument */ arg.arg.x = numeric_argument(mpl, func); /* parse the second argument, if specified */ if (mpl->token == T_COMMA) { switch (op) { case O_ATAN: op = O_ATAN2; break; case O_ROUND: op = O_ROUND2; break; case O_TRUNC: op = O_TRUNC2; break; default: xassert(op != op); } get_token(mpl /* , */); arg.arg.y = numeric_argument(mpl, func); } /* check a token that follows the last argument */ if (mpl->token == T_COMMA) error(mpl, "%s needs one or two arguments", func); else if (mpl->token == T_RIGHT) ; else error(mpl, "syntax error in argument for %s", func); } else if (op == O_SUBSTR) { /* substr needs two or three arguments */ /* parse the first argument */ arg.arg.x = symbolic_argument(mpl, func); /* check a token that follows the first argument */ if (mpl->token == T_COMMA) ; else if (mpl->token == T_RIGHT) error(mpl, "%s needs two or three arguments", func); else error(mpl, "syntax error in argument for %s", func); get_token(mpl /* , */); /* parse the second argument */ arg.arg.y = numeric_argument(mpl, func); /* parse the third argument, if specified */ if (mpl->token == T_COMMA) { op = O_SUBSTR3; get_token(mpl /* , */); arg.arg.z = numeric_argument(mpl, func); } /* check a token that follows the last argument */ if (mpl->token == T_COMMA) error(mpl, "%s needs two or three arguments", func); else if (mpl->token == T_RIGHT) ; else error(mpl, "syntax error in argument for %s", func); } else if (op == O_STR2TIME) { /* str2time needs two arguments, both symbolic */ /* parse the first argument */ arg.arg.x = symbolic_argument(mpl, func); /* check a token that follows the first argument */ if (mpl->token == T_COMMA) ; else if (mpl->token == T_RIGHT) error(mpl, "%s needs two arguments", func); else error(mpl, "syntax error in argument for %s", func); get_token(mpl /* , */); /* parse the second argument */ arg.arg.y = symbolic_argument(mpl, func); /* check a token that follows the second argument */ if (mpl->token == T_COMMA) error(mpl, "%s needs two argument", func); else if (mpl->token == T_RIGHT) ; else error(mpl, "syntax error in argument for %s", func); } else if (op == O_TIME2STR) { /* time2str needs two arguments, numeric and symbolic */ /* parse the first argument */ arg.arg.x = numeric_argument(mpl, func); /* check a token that follows the first argument */ if (mpl->token == T_COMMA) ; else if (mpl->token == T_RIGHT) error(mpl, "%s needs two arguments", func); else error(mpl, "syntax error in argument for %s", func); get_token(mpl /* , */); /* parse the second argument */ arg.arg.y = symbolic_argument(mpl, func); /* check a token that follows the second argument */ if (mpl->token == T_COMMA) error(mpl, "%s needs two argument", func); else if (mpl->token == T_RIGHT) ; else error(mpl, "syntax error in argument for %s", func); } else { /* other functions need one argument */ if (op == O_CARD) arg.arg.x = elemset_argument(mpl, func); else if (op == O_LENGTH) arg.arg.x = symbolic_argument(mpl, func); else arg.arg.x = numeric_argument(mpl, func); /* check a token that follows the argument */ if (mpl->token == T_COMMA) error(mpl, "%s needs one argument", func); else if (mpl->token == T_RIGHT) ; else error(mpl, "syntax error in argument for %s", func); } /* make pseudo-code to call the built-in function */ if (op == O_SUBSTR || op == O_SUBSTR3 || op == O_TIME2STR) code = make_code(mpl, op, &arg, A_SYMBOLIC, 0); else code = make_code(mpl, op, &arg, A_NUMERIC, 0); /* the reference ends with the right parenthesis */ xassert(mpl->token == T_RIGHT); get_token(mpl /* ) */); return code; } /*---------------------------------------------------------------------- -- create_domain - create empty domain. -- -- This routine creates empty domain, which is initially empty, i.e. -- has no domain blocks. */ DOMAIN *create_domain(MPL *mpl) { DOMAIN *domain; domain = alloc(DOMAIN); domain->list = NULL; domain->code = NULL; return domain; } /*---------------------------------------------------------------------- -- create_block - create empty domain block. -- -- This routine creates empty domain block, which is initially empty, -- i.e. has no domain slots. */ DOMAIN_BLOCK *create_block(MPL *mpl) { DOMAIN_BLOCK *block; block = alloc(DOMAIN_BLOCK); block->list = NULL; block->code = NULL; block->backup = NULL; block->next = NULL; return block; } /*---------------------------------------------------------------------- -- append_block - append domain block to specified domain. -- -- This routine adds given domain block to the end of the block list of -- specified domain. */ void append_block(MPL *mpl, DOMAIN *domain, DOMAIN_BLOCK *block) { DOMAIN_BLOCK *temp; xassert(mpl == mpl); xassert(domain != NULL); xassert(block != NULL); xassert(block->next == NULL); if (domain->list == NULL) domain->list = block; else { for (temp = domain->list; temp->next != NULL; temp = temp->next); temp->next = block; } return; } /*---------------------------------------------------------------------- -- append_slot - create and append new slot to domain block. -- -- This routine creates new domain slot and adds it to the end of slot -- list of specified domain block. -- -- The parameter name is symbolic name of the dummy index associated -- with the slot (the character string must be allocated). NULL means -- the dummy index is not explicitly specified. -- -- The parameter code is pseudo-code for computing symbolic value, at -- which the dummy index is bounded. NULL means the dummy index is free -- in the domain scope. */ DOMAIN_SLOT *append_slot(MPL *mpl, DOMAIN_BLOCK *block, char *name, CODE *code) { DOMAIN_SLOT *slot, *temp; xassert(block != NULL); slot = alloc(DOMAIN_SLOT); slot->name = name; slot->code = code; slot->value = NULL; slot->list = NULL; slot->next = NULL; if (block->list == NULL) block->list = slot; else { for (temp = block->list; temp->next != NULL; temp = temp->next); temp->next = slot; } return slot; } /*---------------------------------------------------------------------- -- expression_list - parse expression list. -- -- This routine parses a list of one or more expressions enclosed into -- the parentheses using the syntax: -- -- ::= ( ) -- ::= -- ::= , -- -- Note that this construction may have three different meanings: -- -- 1. If consists of only one expression, is a parenthesized expression, which may be of any -- valid type (not necessarily 1-tuple). -- -- 2. If consists of several expressions separated by -- commae, where no expression is undeclared symbolic name, is a n-tuple. -- -- 3. If consists of several expressions separated by -- commae, where at least one expression is undeclared symbolic name -- (that denotes a dummy index), is a slice and -- can be only used as constituent of indexing expression. */ #define max_dim 20 /* maximal number of components allowed within parentheses */ CODE *expression_list(MPL *mpl) { CODE *code; OPERANDS arg; struct { char *name; CODE *code; } list[1+max_dim]; int flag_x, next_token, dim, j, slice = 0; xassert(mpl->token == T_LEFT); /* the flag, which allows recognizing undeclared symbolic names as dummy indices, will be automatically reset by get_token(), so save it before scanning the next token */ flag_x = mpl->flag_x; get_token(mpl /* ( */); /* parse */ for (dim = 1; ; dim++) { if (dim > max_dim) error(mpl, "too many components within parentheses"); /* current component of can be either dummy index or expression */ if (mpl->token == T_NAME) { /* symbolic name is recognized as dummy index only if: the flag, which allows that, is set, and the name is followed by comma or right parenthesis, and the name is undeclared */ get_token(mpl /* */); next_token = mpl->token; unget_token(mpl); if (!(flag_x && (next_token == T_COMMA || next_token == T_RIGHT) && avl_find_node(mpl->tree, mpl->image) == NULL)) { /* this is not dummy index */ goto expr; } /* all dummy indices within the same slice must have unique symbolic names */ for (j = 1; j < dim; j++) { if (list[j].name != NULL && strcmp(list[j].name, mpl->image) == 0) error(mpl, "duplicate dummy index %s not allowed", mpl->image); } /* current component of is dummy index */ list[dim].name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1); strcpy(list[dim].name, mpl->image); list[dim].code = NULL; get_token(mpl /* */); /* is a slice, because at least one dummy index has appeared */ slice = 1; /* note that the context ( ) is not allowed, i.e. in this case is considered as a parenthesized expression */ if (dim == 1 && mpl->token == T_RIGHT) error(mpl, "%s not defined", list[dim].name); } else expr: { /* current component of is expression */ code = expression_13(mpl); /* if the current expression is followed by comma or it is not the very first expression, entire is n-tuple or slice, in which case the current expression should be converted to symbolic type, if necessary */ if (mpl->token == T_COMMA || dim > 1) { if (code->type == A_NUMERIC) code = make_unary(mpl, O_CVTSYM, code, A_SYMBOLIC, 0); /* now the expression must be of symbolic type */ if (code->type != A_SYMBOLIC) error(mpl, "component expression has invalid type"); xassert(code->dim == 0); } list[dim].name = NULL; list[dim].code = code; } /* check a token that follows the current component */ if (mpl->token == T_COMMA) get_token(mpl /* , */); else if (mpl->token == T_RIGHT) break; else error(mpl, "right parenthesis missing where expected"); } /* generate pseudo-code for */ if (dim == 1 && !slice) { /* is a parenthesized expression */ code = list[1].code; } else if (!slice) { /* is a n-tuple */ arg.list = create_arg_list(mpl); for (j = 1; j <= dim; j++) arg.list = expand_arg_list(mpl, arg.list, list[j].code); code = make_code(mpl, O_TUPLE, &arg, A_TUPLE, dim); } else { /* is a slice */ arg.slice = create_block(mpl); for (j = 1; j <= dim; j++) append_slot(mpl, arg.slice, list[j].name, list[j].code); /* note that actually pseudo-codes with op = O_SLICE are never evaluated */ code = make_code(mpl, O_SLICE, &arg, A_TUPLE, dim); } get_token(mpl /* ) */); /* if is a slice, there must be the keyword 'in', which follows the right parenthesis */ if (slice && mpl->token != T_IN) error(mpl, "keyword in missing where expected"); /* if the slice flag is set and there is the keyword 'in', which follows , the latter must be a slice */ if (flag_x && mpl->token == T_IN && !slice) { if (dim == 1) error(mpl, "syntax error in indexing expression"); else error(mpl, "0-ary slice not allowed"); } return code; } /*---------------------------------------------------------------------- -- literal set - parse literal set. -- -- This routine parses literal set using the syntax: -- -- ::= { } -- ::= -- ::= , -- ::= -- -- It is assumed that the left curly brace and the very first member -- expression that follows it are already parsed. The right curly brace -- remains unscanned on exit. */ CODE *literal_set(MPL *mpl, CODE *code) { OPERANDS arg; int j; xassert(code != NULL); arg.list = create_arg_list(mpl); /* parse */ for (j = 1; ; j++) { /* all member expressions must be n-tuples; so, if the current expression is not n-tuple, convert it to 1-tuple */ if (code->type == A_NUMERIC) code = make_unary(mpl, O_CVTSYM, code, A_SYMBOLIC, 0); if (code->type == A_SYMBOLIC) code = make_unary(mpl, O_CVTTUP, code, A_TUPLE, 1); /* now the expression must be n-tuple */ if (code->type != A_TUPLE) error(mpl, "member expression has invalid type"); /* all member expressions must have identical dimension */ if (arg.list != NULL && arg.list->x->dim != code->dim) error(mpl, "member %d has %d component%s while member %d ha" "s %d component%s", j-1, arg.list->x->dim, arg.list->x->dim == 1 ? "" : "s", j, code->dim, code->dim == 1 ? "" : "s"); /* append the current expression to the member list */ arg.list = expand_arg_list(mpl, arg.list, code); /* check a token that follows the current expression */ if (mpl->token == T_COMMA) get_token(mpl /* , */); else if (mpl->token == T_RBRACE) break; else error(mpl, "syntax error in literal set"); /* parse the next expression that follows the comma */ code = expression_5(mpl); } /* generate pseudo-code for */ code = make_code(mpl, O_MAKE, &arg, A_ELEMSET, arg.list->x->dim); return code; } /*---------------------------------------------------------------------- -- indexing_expression - parse indexing expression. -- -- This routine parses indexing expression using the syntax: -- -- ::= -- ::= { } -- ::= { : } -- ::= -- ::= , -- ::= -- ::= in -- ::= in -- ::= -- ::= ( ) -- ::= -- ::= -- -- This routine creates domain for , where each -- domain block corresponds to , and each domain slot -- corresponds to individual indexing position. */ DOMAIN *indexing_expression(MPL *mpl) { DOMAIN *domain; DOMAIN_BLOCK *block; DOMAIN_SLOT *slot; CODE *code; xassert(mpl->token == T_LBRACE); get_token(mpl /* { */); if (mpl->token == T_RBRACE) error(mpl, "empty indexing expression not allowed"); /* create domain to be constructed */ domain = create_domain(mpl); /* parse either or that follows the left brace */ for (;;) { /* domain block for is not created yet */ block = NULL; /* pseudo-code for is not generated yet */ code = NULL; /* check a token, which begins with */ if (mpl->token == T_NAME) { /* it is a symbolic name */ int next_token; char *name; /* symbolic name is recognized as dummy index only if it is followed by the keyword 'in' and not declared */ get_token(mpl /* */); next_token = mpl->token; unget_token(mpl); if (!(next_token == T_IN && avl_find_node(mpl->tree, mpl->image) == NULL)) { /* this is not dummy index; the symbolic name begins an expression, which is either or the very first in */ goto expr; } /* create domain block with one slot, which is assigned the dummy index */ block = create_block(mpl); name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1); strcpy(name, mpl->image); append_slot(mpl, block, name, NULL); get_token(mpl /* */); /* the keyword 'in' is already checked above */ xassert(mpl->token == T_IN); get_token(mpl /* in */); /* that follows the keyword 'in' will be parsed below */ } else if (mpl->token == T_LEFT) { /* it is the left parenthesis; parse expression that begins with this parenthesis (the flag is set in order to allow recognizing slices; see the routine expression_list) */ mpl->flag_x = 1; code = expression_9(mpl); if (code->op != O_SLICE) { /* this is either or the very first in */ goto expr; } /* this is a slice; besides the corresponding domain block is already created by expression_list() */ block = code->arg.slice; code = NULL; /* is not parsed yet */ /* the keyword 'in' following the slice is already checked by expression_list() */ xassert(mpl->token == T_IN); get_token(mpl /* in */); /* that follows the keyword 'in' will be parsed below */ } expr: /* parse expression that follows either the keyword 'in' (in which case it can be as well as the very first in ); note that this expression can be already parsed above */ if (code == NULL) code = expression_9(mpl); /* check the type of the expression just parsed */ if (code->type != A_ELEMSET) { /* it is not and therefore it can only be the very first in ; however, then there must be no dummy index neither slice between the left brace and this expression */ if (block != NULL) error(mpl, "domain expression has invalid type"); /* parse the rest part of and make this set be , i.e. the construction {a, b, c} is parsed as it were written as {A}, where A = {a, b, c} is a temporary elemental set */ code = literal_set(mpl, code); } /* now pseudo-code for has been built */ xassert(code != NULL); xassert(code->type == A_ELEMSET); xassert(code->dim > 0); /* if domain block for the current is still not created, create it for fake slice of the same dimension as */ if (block == NULL) { int j; block = create_block(mpl); for (j = 1; j <= code->dim; j++) append_slot(mpl, block, NULL, NULL); } /* number of indexing positions in must be the same as dimension of n-tuples in basic set */ { int dim = 0; for (slot = block->list; slot != NULL; slot = slot->next) dim++; if (dim != code->dim) error(mpl,"%d %s specified for set of dimension %d", dim, dim == 1 ? "index" : "indices", code->dim); } /* store pseudo-code for in the domain block */ xassert(block->code == NULL); block->code = code; /* and append the domain block to the domain */ append_block(mpl, domain, block); /* the current has been completely parsed; include all its dummy indices into the symbolic name table to make them available for referencing from expressions; implicit declarations of dummy indices remain valid while the corresponding domain scope is valid */ for (slot = block->list; slot != NULL; slot = slot->next) if (slot->name != NULL) { AVLNODE *node; xassert(avl_find_node(mpl->tree, slot->name) == NULL); node = avl_insert_node(mpl->tree, slot->name); avl_set_node_type(node, A_INDEX); avl_set_node_link(node, (void *)slot); } /* check a token that follows */ if (mpl->token == T_COMMA) get_token(mpl /* , */); else if (mpl->token == T_COLON || mpl->token == T_RBRACE) break; else error(mpl, "syntax error in indexing expression"); } /* parse that follows the colon */ if (mpl->token == T_COLON) { get_token(mpl /* : */); code = expression_13(mpl); /* convert the expression to logical type, if necessary */ if (code->type == A_SYMBOLIC) code = make_unary(mpl, O_CVTNUM, code, A_NUMERIC, 0); if (code->type == A_NUMERIC) code = make_unary(mpl, O_CVTLOG, code, A_LOGICAL, 0); /* now the expression must be of logical type */ if (code->type != A_LOGICAL) error(mpl, "expression following colon has invalid type"); xassert(code->dim == 0); domain->code = code; /* the right brace must follow the logical expression */ if (mpl->token != T_RBRACE) error(mpl, "syntax error in indexing expression"); } get_token(mpl /* } */); return domain; } /*---------------------------------------------------------------------- -- close_scope - close scope of indexing expression. -- -- The routine closes the scope of indexing expression specified by its -- domain and thereby makes all dummy indices introduced in the indexing -- expression no longer available for referencing. */ void close_scope(MPL *mpl, DOMAIN *domain) { DOMAIN_BLOCK *block; DOMAIN_SLOT *slot; AVLNODE *node; xassert(domain != NULL); /* remove all dummy indices from the symbolic names table */ for (block = domain->list; block != NULL; block = block->next) { for (slot = block->list; slot != NULL; slot = slot->next) { if (slot->name != NULL) { node = avl_find_node(mpl->tree, slot->name); xassert(node != NULL); xassert(avl_get_node_type(node) == A_INDEX); avl_delete_node(mpl->tree, node); } } } return; } /*---------------------------------------------------------------------- -- iterated_expression - parse iterated expression. -- -- This routine parses primary expression using the syntax: -- -- ::= -- ::= sum -- ::= prod -- ::= min -- ::= max -- ::= exists -- -- ::= forall -- -- ::= setof -- -- Note that parsing "integrand" depends on the iterated operator. */ #if 1 /* 07/IX-2008 */ static void link_up(CODE *code) { /* if we have something like sum{(i+1,j,k-1) in E} x[i,j,k], where i and k are dummy indices defined out of the iterated expression, we should link up pseudo-code for computing i+1 and k-1 to pseudo-code for computing the iterated expression; this is needed to invalidate current value of the iterated expression once i or k have been changed */ DOMAIN_BLOCK *block; DOMAIN_SLOT *slot; for (block = code->arg.loop.domain->list; block != NULL; block = block->next) { for (slot = block->list; slot != NULL; slot = slot->next) { if (slot->code != NULL) { xassert(slot->code->up == NULL); slot->code->up = code; } } } return; } #endif CODE *iterated_expression(MPL *mpl) { CODE *code; OPERANDS arg; int op; char opstr[8]; /* determine operation code */ xassert(mpl->token == T_NAME); if (strcmp(mpl->image, "sum") == 0) op = O_SUM; else if (strcmp(mpl->image, "prod") == 0) op = O_PROD; else if (strcmp(mpl->image, "min") == 0) op = O_MINIMUM; else if (strcmp(mpl->image, "max") == 0) op = O_MAXIMUM; else if (strcmp(mpl->image, "forall") == 0) op = O_FORALL; else if (strcmp(mpl->image, "exists") == 0) op = O_EXISTS; else if (strcmp(mpl->image, "setof") == 0) op = O_SETOF; else error(mpl, "operator %s unknown", mpl->image); strcpy(opstr, mpl->image); xassert(strlen(opstr) < sizeof(opstr)); get_token(mpl /* */); /* check the left brace that follows the operator name */ xassert(mpl->token == T_LBRACE); /* parse indexing expression that controls iterating */ arg.loop.domain = indexing_expression(mpl); /* parse "integrand" expression and generate pseudo-code */ switch (op) { case O_SUM: case O_PROD: case O_MINIMUM: case O_MAXIMUM: arg.loop.x = expression_3(mpl); /* convert the integrand to numeric type, if necessary */ if (arg.loop.x->type == A_SYMBOLIC) arg.loop.x = make_unary(mpl, O_CVTNUM, arg.loop.x, A_NUMERIC, 0); /* now the integrand must be of numeric type or linear form (the latter is only allowed for the sum operator) */ if (!(arg.loop.x->type == A_NUMERIC || op == O_SUM && arg.loop.x->type == A_FORMULA)) err: error(mpl, "integrand following %s{...} has invalid type" , opstr); xassert(arg.loop.x->dim == 0); /* generate pseudo-code */ code = make_code(mpl, op, &arg, arg.loop.x->type, 0); break; case O_FORALL: case O_EXISTS: arg.loop.x = expression_12(mpl); /* convert the integrand to logical type, if necessary */ if (arg.loop.x->type == A_SYMBOLIC) arg.loop.x = make_unary(mpl, O_CVTNUM, arg.loop.x, A_NUMERIC, 0); if (arg.loop.x->type == A_NUMERIC) arg.loop.x = make_unary(mpl, O_CVTLOG, arg.loop.x, A_LOGICAL, 0); /* now the integrand must be of logical type */ if (arg.loop.x->type != A_LOGICAL) goto err; xassert(arg.loop.x->dim == 0); /* generate pseudo-code */ code = make_code(mpl, op, &arg, A_LOGICAL, 0); break; case O_SETOF: arg.loop.x = expression_5(mpl); /* convert the integrand to 1-tuple, if necessary */ if (arg.loop.x->type == A_NUMERIC) arg.loop.x = make_unary(mpl, O_CVTSYM, arg.loop.x, A_SYMBOLIC, 0); if (arg.loop.x->type == A_SYMBOLIC) arg.loop.x = make_unary(mpl, O_CVTTUP, arg.loop.x, A_TUPLE, 1); /* now the integrand must be n-tuple */ if (arg.loop.x->type != A_TUPLE) goto err; xassert(arg.loop.x->dim > 0); /* generate pseudo-code */ code = make_code(mpl, op, &arg, A_ELEMSET, arg.loop.x->dim); break; default: xassert(op != op); } /* close the scope of the indexing expression */ close_scope(mpl, arg.loop.domain); #if 1 /* 07/IX-2008 */ link_up(code); #endif return code; } /*---------------------------------------------------------------------- -- domain_arity - determine arity of domain. -- -- This routine returns arity of specified domain, which is number of -- its free dummy indices. */ int domain_arity(MPL *mpl, DOMAIN *domain) { DOMAIN_BLOCK *block; DOMAIN_SLOT *slot; int arity; xassert(mpl == mpl); arity = 0; for (block = domain->list; block != NULL; block = block->next) for (slot = block->list; slot != NULL; slot = slot->next) if (slot->code == NULL) arity++; return arity; } /*---------------------------------------------------------------------- -- set_expression - parse set expression. -- -- This routine parses primary expression using the syntax: -- -- ::= { } -- ::= */ CODE *set_expression(MPL *mpl) { CODE *code; OPERANDS arg; xassert(mpl->token == T_LBRACE); get_token(mpl /* { */); /* check a token that follows the left brace */ if (mpl->token == T_RBRACE) { /* it is the right brace, so the resultant is an empty set of dimension 1 */ arg.list = NULL; /* generate pseudo-code to build the resultant set */ code = make_code(mpl, O_MAKE, &arg, A_ELEMSET, 1); get_token(mpl /* } */); } else { /* the next token begins an indexing expression */ unget_token(mpl); arg.loop.domain = indexing_expression(mpl); arg.loop.x = NULL; /* integrand is not used */ /* close the scope of the indexing expression */ close_scope(mpl, arg.loop.domain); /* generate pseudo-code to build the resultant set */ code = make_code(mpl, O_BUILD, &arg, A_ELEMSET, domain_arity(mpl, arg.loop.domain)); #if 1 /* 07/IX-2008 */ link_up(code); #endif } return code; } /*---------------------------------------------------------------------- -- branched_expression - parse conditional expression. -- -- This routine parses primary expression using the syntax: -- -- ::= -- ::= if then -- ::= if then -- else -- ::= */ CODE *branched_expression(MPL *mpl) { CODE *code, *x, *y, *z; xassert(mpl->token == T_IF); get_token(mpl /* if */); /* parse that follows 'if' */ x = expression_13(mpl); /* convert the expression to logical type, if necessary */ if (x->type == A_SYMBOLIC) x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0); if (x->type == A_NUMERIC) x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0); /* now the expression must be of logical type */ if (x->type != A_LOGICAL) error(mpl, "expression following if has invalid type"); xassert(x->dim == 0); /* the keyword 'then' must follow the logical expression */ if (mpl->token != T_THEN) error(mpl, "keyword then missing where expected"); get_token(mpl /* then */); /* parse that follows 'then' and check its type */ y = expression_9(mpl); if (!(y->type == A_NUMERIC || y->type == A_SYMBOLIC || y->type == A_ELEMSET || y->type == A_FORMULA)) error(mpl, "expression following then has invalid type"); /* if the expression that follows the keyword 'then' is elemental set, the keyword 'else' cannot be omitted; otherwise else-part is optional */ if (mpl->token != T_ELSE) { if (y->type == A_ELEMSET) error(mpl, "keyword else missing where expected"); z = NULL; goto skip; } get_token(mpl /* else */); /* parse that follow 'else' and check its type */ z = expression_9(mpl); if (!(z->type == A_NUMERIC || z->type == A_SYMBOLIC || z->type == A_ELEMSET || z->type == A_FORMULA)) error(mpl, "expression following else has invalid type"); /* convert to identical types, if necessary */ if (y->type == A_FORMULA || z->type == A_FORMULA) { if (y->type == A_SYMBOLIC) y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0); if (y->type == A_NUMERIC) y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0); if (z->type == A_SYMBOLIC) z = make_unary(mpl, O_CVTNUM, z, A_NUMERIC, 0); if (z->type == A_NUMERIC) z = make_unary(mpl, O_CVTLFM, z, A_FORMULA, 0); } if (y->type == A_SYMBOLIC || z->type == A_SYMBOLIC) { if (y->type == A_NUMERIC) y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0); if (z->type == A_NUMERIC) z = make_unary(mpl, O_CVTSYM, z, A_SYMBOLIC, 0); } /* now both expressions must have identical types */ if (y->type != z->type) error(mpl, "expressions following then and else have incompati" "ble types"); /* and identical dimensions */ if (y->dim != z->dim) error(mpl, "expressions following then and else have different" " dimensions %d and %d, respectively", y->dim, z->dim); skip: /* generate pseudo-code to perform branching */ code = make_ternary(mpl, O_FORK, x, y, z, y->type, y->dim); return code; } /*---------------------------------------------------------------------- -- primary_expression - parse primary expression. -- -- This routine parses primary expression using the syntax: -- -- ::= -- ::= Infinity -- ::= -- ::= -- ::= -- ::= [ ] -- ::= -- ::= [ ] -- ::= -- ::= [ ] -- ::= ( ) -- ::= ( ) -- ::= -- ::= { } -- ::= -- ::= -- -- For complete list of syntactic rules for see -- comments to the corresponding parsing routines. */ CODE *primary_expression(MPL *mpl) { CODE *code; if (mpl->token == T_NUMBER) { /* parse numeric literal */ code = numeric_literal(mpl); } #if 1 /* 21/VII-2006 */ else if (mpl->token == T_INFINITY) { /* parse "infinity" */ OPERANDS arg; arg.num = DBL_MAX; code = make_code(mpl, O_NUMBER, &arg, A_NUMERIC, 0); get_token(mpl /* Infinity */); } #endif else if (mpl->token == T_STRING) { /* parse string literal */ code = string_literal(mpl); } else if (mpl->token == T_NAME) { int next_token; get_token(mpl /* */); next_token = mpl->token; unget_token(mpl); /* check a token that follows */ switch (next_token) { case T_LBRACKET: /* parse reference to subscripted object */ code = object_reference(mpl); break; case T_LEFT: /* parse reference to built-in function */ code = function_reference(mpl); break; case T_LBRACE: /* parse iterated expression */ code = iterated_expression(mpl); break; default: /* parse reference to unsubscripted object */ code = object_reference(mpl); break; } } else if (mpl->token == T_LEFT) { /* parse parenthesized expression */ code = expression_list(mpl); } else if (mpl->token == T_LBRACE) { /* parse set expression */ code = set_expression(mpl); } else if (mpl->token == T_IF) { /* parse conditional expression */ code = branched_expression(mpl); } else if (is_reserved(mpl)) { /* other reserved keywords cannot be used here */ error(mpl, "invalid use of reserved keyword %s", mpl->image); } else error(mpl, "syntax error in expression"); return code; } /*---------------------------------------------------------------------- -- error_preceding - raise error if preceding operand has wrong type. -- -- This routine is called to raise error if operand that precedes some -- infix operator has invalid type. */ void error_preceding(MPL *mpl, char *opstr) { error(mpl, "operand preceding %s has invalid type", opstr); /* no return */ } /*---------------------------------------------------------------------- -- error_following - raise error if following operand has wrong type. -- -- This routine is called to raise error if operand that follows some -- infix operator has invalid type. */ void error_following(MPL *mpl, char *opstr) { error(mpl, "operand following %s has invalid type", opstr); /* no return */ } /*---------------------------------------------------------------------- -- error_dimension - raise error if operands have different dimension. -- -- This routine is called to raise error if two operands of some infix -- operator have different dimension. */ void error_dimension(MPL *mpl, char *opstr, int dim1, int dim2) { error(mpl, "operands preceding and following %s have different di" "mensions %d and %d, respectively", opstr, dim1, dim2); /* no return */ } /*---------------------------------------------------------------------- -- expression_0 - parse expression of level 0. -- -- This routine parses expression of level 0 using the syntax: -- -- ::= */ CODE *expression_0(MPL *mpl) { CODE *code; code = primary_expression(mpl); return code; } /*---------------------------------------------------------------------- -- expression_1 - parse expression of level 1. -- -- This routine parses expression of level 1 using the syntax: -- -- ::= -- ::= -- ::= -- ::= ^ | ** */ CODE *expression_1(MPL *mpl) { CODE *x, *y; char opstr[8]; x = expression_0(mpl); if (mpl->token == T_POWER) { strcpy(opstr, mpl->image); xassert(strlen(opstr) < sizeof(opstr)); if (x->type == A_SYMBOLIC) x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0); if (x->type != A_NUMERIC) error_preceding(mpl, opstr); get_token(mpl /* ^ | ** */); if (mpl->token == T_PLUS || mpl->token == T_MINUS) y = expression_2(mpl); else y = expression_1(mpl); if (y->type == A_SYMBOLIC) y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0); if (y->type != A_NUMERIC) error_following(mpl, opstr); x = make_binary(mpl, O_POWER, x, y, A_NUMERIC, 0); } return x; } /*---------------------------------------------------------------------- -- expression_2 - parse expression of level 2. -- -- This routine parses expression of level 2 using the syntax: -- -- ::= -- ::= + -- ::= - */ CODE *expression_2(MPL *mpl) { CODE *x; if (mpl->token == T_PLUS) { get_token(mpl /* + */); x = expression_1(mpl); if (x->type == A_SYMBOLIC) x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0); if (!(x->type == A_NUMERIC || x->type == A_FORMULA)) error_following(mpl, "+"); x = make_unary(mpl, O_PLUS, x, x->type, 0); } else if (mpl->token == T_MINUS) { get_token(mpl /* - */); x = expression_1(mpl); if (x->type == A_SYMBOLIC) x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0); if (!(x->type == A_NUMERIC || x->type == A_FORMULA)) error_following(mpl, "-"); x = make_unary(mpl, O_MINUS, x, x->type, 0); } else x = expression_1(mpl); return x; } /*---------------------------------------------------------------------- -- expression_3 - parse expression of level 3. -- -- This routine parses expression of level 3 using the syntax: -- -- ::= -- ::= * -- ::= / -- ::= div -- ::= mod */ CODE *expression_3(MPL *mpl) { CODE *x, *y; x = expression_2(mpl); for (;;) { if (mpl->token == T_ASTERISK) { if (x->type == A_SYMBOLIC) x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0); if (!(x->type == A_NUMERIC || x->type == A_FORMULA)) error_preceding(mpl, "*"); get_token(mpl /* * */); y = expression_2(mpl); if (y->type == A_SYMBOLIC) y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0); if (!(y->type == A_NUMERIC || y->type == A_FORMULA)) error_following(mpl, "*"); if (x->type == A_FORMULA && y->type == A_FORMULA) error(mpl, "multiplication of linear forms not allowed"); if (x->type == A_NUMERIC && y->type == A_NUMERIC) x = make_binary(mpl, O_MUL, x, y, A_NUMERIC, 0); else x = make_binary(mpl, O_MUL, x, y, A_FORMULA, 0); } else if (mpl->token == T_SLASH) { if (x->type == A_SYMBOLIC) x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0); if (!(x->type == A_NUMERIC || x->type == A_FORMULA)) error_preceding(mpl, "/"); get_token(mpl /* / */); y = expression_2(mpl); if (y->type == A_SYMBOLIC) y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0); if (y->type != A_NUMERIC) error_following(mpl, "/"); if (x->type == A_NUMERIC) x = make_binary(mpl, O_DIV, x, y, A_NUMERIC, 0); else x = make_binary(mpl, O_DIV, x, y, A_FORMULA, 0); } else if (mpl->token == T_DIV) { if (x->type == A_SYMBOLIC) x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0); if (x->type != A_NUMERIC) error_preceding(mpl, "div"); get_token(mpl /* div */); y = expression_2(mpl); if (y->type == A_SYMBOLIC) y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0); if (y->type != A_NUMERIC) error_following(mpl, "div"); x = make_binary(mpl, O_IDIV, x, y, A_NUMERIC, 0); } else if (mpl->token == T_MOD) { if (x->type == A_SYMBOLIC) x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0); if (x->type != A_NUMERIC) error_preceding(mpl, "mod"); get_token(mpl /* mod */); y = expression_2(mpl); if (y->type == A_SYMBOLIC) y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0); if (y->type != A_NUMERIC) error_following(mpl, "mod"); x = make_binary(mpl, O_MOD, x, y, A_NUMERIC, 0); } else break; } return x; } /*---------------------------------------------------------------------- -- expression_4 - parse expression of level 4. -- -- This routine parses expression of level 4 using the syntax: -- -- ::= -- ::= + -- ::= - -- ::= less */ CODE *expression_4(MPL *mpl) { CODE *x, *y; x = expression_3(mpl); for (;;) { if (mpl->token == T_PLUS) { if (x->type == A_SYMBOLIC) x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0); if (!(x->type == A_NUMERIC || x->type == A_FORMULA)) error_preceding(mpl, "+"); get_token(mpl /* + */); y = expression_3(mpl); if (y->type == A_SYMBOLIC) y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0); if (!(y->type == A_NUMERIC || y->type == A_FORMULA)) error_following(mpl, "+"); if (x->type == A_NUMERIC && y->type == A_FORMULA) x = make_unary(mpl, O_CVTLFM, x, A_FORMULA, 0); if (x->type == A_FORMULA && y->type == A_NUMERIC) y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0); x = make_binary(mpl, O_ADD, x, y, x->type, 0); } else if (mpl->token == T_MINUS) { if (x->type == A_SYMBOLIC) x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0); if (!(x->type == A_NUMERIC || x->type == A_FORMULA)) error_preceding(mpl, "-"); get_token(mpl /* - */); y = expression_3(mpl); if (y->type == A_SYMBOLIC) y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0); if (!(y->type == A_NUMERIC || y->type == A_FORMULA)) error_following(mpl, "-"); if (x->type == A_NUMERIC && y->type == A_FORMULA) x = make_unary(mpl, O_CVTLFM, x, A_FORMULA, 0); if (x->type == A_FORMULA && y->type == A_NUMERIC) y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0); x = make_binary(mpl, O_SUB, x, y, x->type, 0); } else if (mpl->token == T_LESS) { if (x->type == A_SYMBOLIC) x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0); if (x->type != A_NUMERIC) error_preceding(mpl, "less"); get_token(mpl /* less */); y = expression_3(mpl); if (y->type == A_SYMBOLIC) y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0); if (y->type != A_NUMERIC) error_following(mpl, "less"); x = make_binary(mpl, O_LESS, x, y, A_NUMERIC, 0); } else break; } return x; } /*---------------------------------------------------------------------- -- expression_5 - parse expression of level 5. -- -- This routine parses expression of level 5 using the syntax: -- -- ::= -- ::= & */ CODE *expression_5(MPL *mpl) { CODE *x, *y; x = expression_4(mpl); for (;;) { if (mpl->token == T_CONCAT) { if (x->type == A_NUMERIC) x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0); if (x->type != A_SYMBOLIC) error_preceding(mpl, "&"); get_token(mpl /* & */); y = expression_4(mpl); if (y->type == A_NUMERIC) y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0); if (y->type != A_SYMBOLIC) error_following(mpl, "&"); x = make_binary(mpl, O_CONCAT, x, y, A_SYMBOLIC, 0); } else break; } return x; } /*---------------------------------------------------------------------- -- expression_6 - parse expression of level 6. -- -- This routine parses expression of level 6 using the syntax: -- -- ::= -- ::= .. -- ::= .. by -- */ CODE *expression_6(MPL *mpl) { CODE *x, *y, *z; x = expression_5(mpl); if (mpl->token == T_DOTS) { if (x->type == A_SYMBOLIC) x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0); if (x->type != A_NUMERIC) error_preceding(mpl, ".."); get_token(mpl /* .. */); y = expression_5(mpl); if (y->type == A_SYMBOLIC) y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0); if (y->type != A_NUMERIC) error_following(mpl, ".."); if (mpl->token == T_BY) { get_token(mpl /* by */); z = expression_5(mpl); if (z->type == A_SYMBOLIC) z = make_unary(mpl, O_CVTNUM, z, A_NUMERIC, 0); if (z->type != A_NUMERIC) error_following(mpl, "by"); } else z = NULL; x = make_ternary(mpl, O_DOTS, x, y, z, A_ELEMSET, 1); } return x; } /*---------------------------------------------------------------------- -- expression_7 - parse expression of level 7. -- -- This routine parses expression of level 7 using the syntax: -- -- ::= -- ::= cross */ CODE *expression_7(MPL *mpl) { CODE *x, *y; x = expression_6(mpl); for (;;) { if (mpl->token == T_CROSS) { if (x->type != A_ELEMSET) error_preceding(mpl, "cross"); get_token(mpl /* cross */); y = expression_6(mpl); if (y->type != A_ELEMSET) error_following(mpl, "cross"); x = make_binary(mpl, O_CROSS, x, y, A_ELEMSET, x->dim + y->dim); } else break; } return x; } /*---------------------------------------------------------------------- -- expression_8 - parse expression of level 8. -- -- This routine parses expression of level 8 using the syntax: -- -- ::= -- ::= inter */ CODE *expression_8(MPL *mpl) { CODE *x, *y; x = expression_7(mpl); for (;;) { if (mpl->token == T_INTER) { if (x->type != A_ELEMSET) error_preceding(mpl, "inter"); get_token(mpl /* inter */); y = expression_7(mpl); if (y->type != A_ELEMSET) error_following(mpl, "inter"); if (x->dim != y->dim) error_dimension(mpl, "inter", x->dim, y->dim); x = make_binary(mpl, O_INTER, x, y, A_ELEMSET, x->dim); } else break; } return x; } /*---------------------------------------------------------------------- -- expression_9 - parse expression of level 9. -- -- This routine parses expression of level 9 using the syntax: -- -- ::= -- ::= union -- ::= diff -- ::= symdiff */ CODE *expression_9(MPL *mpl) { CODE *x, *y; x = expression_8(mpl); for (;;) { if (mpl->token == T_UNION) { if (x->type != A_ELEMSET) error_preceding(mpl, "union"); get_token(mpl /* union */); y = expression_8(mpl); if (y->type != A_ELEMSET) error_following(mpl, "union"); if (x->dim != y->dim) error_dimension(mpl, "union", x->dim, y->dim); x = make_binary(mpl, O_UNION, x, y, A_ELEMSET, x->dim); } else if (mpl->token == T_DIFF) { if (x->type != A_ELEMSET) error_preceding(mpl, "diff"); get_token(mpl /* diff */); y = expression_8(mpl); if (y->type != A_ELEMSET) error_following(mpl, "diff"); if (x->dim != y->dim) error_dimension(mpl, "diff", x->dim, y->dim); x = make_binary(mpl, O_DIFF, x, y, A_ELEMSET, x->dim); } else if (mpl->token == T_SYMDIFF) { if (x->type != A_ELEMSET) error_preceding(mpl, "symdiff"); get_token(mpl /* symdiff */); y = expression_8(mpl); if (y->type != A_ELEMSET) error_following(mpl, "symdiff"); if (x->dim != y->dim) error_dimension(mpl, "symdiff", x->dim, y->dim); x = make_binary(mpl, O_SYMDIFF, x, y, A_ELEMSET, x->dim); } else break; } return x; } /*---------------------------------------------------------------------- -- expression_10 - parse expression of level 10. -- -- This routine parses expression of level 10 using the syntax: -- -- ::= -- ::= -- ::= < | <= | = | == | >= | > | <> | != | in | not in | ! in | -- within | not within | ! within */ CODE *expression_10(MPL *mpl) { CODE *x, *y; int op = -1; char opstr[16]; x = expression_9(mpl); strcpy(opstr, ""); switch (mpl->token) { case T_LT: op = O_LT; break; case T_LE: op = O_LE; break; case T_EQ: op = O_EQ; break; case T_GE: op = O_GE; break; case T_GT: op = O_GT; break; case T_NE: op = O_NE; break; case T_IN: op = O_IN; break; case T_WITHIN: op = O_WITHIN; break; case T_NOT: strcpy(opstr, mpl->image); get_token(mpl /* not | ! */); if (mpl->token == T_IN) op = O_NOTIN; else if (mpl->token == T_WITHIN) op = O_NOTWITHIN; else error(mpl, "invalid use of %s", opstr); strcat(opstr, " "); break; default: goto done; } strcat(opstr, mpl->image); xassert(strlen(opstr) < sizeof(opstr)); switch (op) { case O_EQ: case O_NE: #if 1 /* 02/VIII-2008 */ case O_LT: case O_LE: case O_GT: case O_GE: #endif if (!(x->type == A_NUMERIC || x->type == A_SYMBOLIC)) error_preceding(mpl, opstr); get_token(mpl /* */); y = expression_9(mpl); if (!(y->type == A_NUMERIC || y->type == A_SYMBOLIC)) error_following(mpl, opstr); if (x->type == A_NUMERIC && y->type == A_SYMBOLIC) x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0); if (x->type == A_SYMBOLIC && y->type == A_NUMERIC) y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0); x = make_binary(mpl, op, x, y, A_LOGICAL, 0); break; #if 0 /* 02/VIII-2008 */ case O_LT: case O_LE: case O_GT: case O_GE: if (x->type == A_SYMBOLIC) x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0); if (x->type != A_NUMERIC) error_preceding(mpl, opstr); get_token(mpl /* */); y = expression_9(mpl); if (y->type == A_SYMBOLIC) y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0); if (y->type != A_NUMERIC) error_following(mpl, opstr); x = make_binary(mpl, op, x, y, A_LOGICAL, 0); break; #endif case O_IN: case O_NOTIN: if (x->type == A_NUMERIC) x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0); if (x->type == A_SYMBOLIC) x = make_unary(mpl, O_CVTTUP, x, A_TUPLE, 1); if (x->type != A_TUPLE) error_preceding(mpl, opstr); get_token(mpl /* */); y = expression_9(mpl); if (y->type != A_ELEMSET) error_following(mpl, opstr); if (x->dim != y->dim) error_dimension(mpl, opstr, x->dim, y->dim); x = make_binary(mpl, op, x, y, A_LOGICAL, 0); break; case O_WITHIN: case O_NOTWITHIN: if (x->type != A_ELEMSET) error_preceding(mpl, opstr); get_token(mpl /* */); y = expression_9(mpl); if (y->type != A_ELEMSET) error_following(mpl, opstr); if (x->dim != y->dim) error_dimension(mpl, opstr, x->dim, y->dim); x = make_binary(mpl, op, x, y, A_LOGICAL, 0); break; default: xassert(op != op); } done: return x; } /*---------------------------------------------------------------------- -- expression_11 - parse expression of level 11. -- -- This routine parses expression of level 11 using the syntax: -- -- ::= -- ::= not -- ::= ! */ CODE *expression_11(MPL *mpl) { CODE *x; char opstr[8]; if (mpl->token == T_NOT) { strcpy(opstr, mpl->image); xassert(strlen(opstr) < sizeof(opstr)); get_token(mpl /* not | ! */); x = expression_10(mpl); if (x->type == A_SYMBOLIC) x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0); if (x->type == A_NUMERIC) x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0); if (x->type != A_LOGICAL) error_following(mpl, opstr); x = make_unary(mpl, O_NOT, x, A_LOGICAL, 0); } else x = expression_10(mpl); return x; } /*---------------------------------------------------------------------- -- expression_12 - parse expression of level 12. -- -- This routine parses expression of level 12 using the syntax: -- -- ::= -- ::= and -- ::= && */ CODE *expression_12(MPL *mpl) { CODE *x, *y; char opstr[8]; x = expression_11(mpl); for (;;) { if (mpl->token == T_AND) { strcpy(opstr, mpl->image); xassert(strlen(opstr) < sizeof(opstr)); if (x->type == A_SYMBOLIC) x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0); if (x->type == A_NUMERIC) x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0); if (x->type != A_LOGICAL) error_preceding(mpl, opstr); get_token(mpl /* and | && */); y = expression_11(mpl); if (y->type == A_SYMBOLIC) y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0); if (y->type == A_NUMERIC) y = make_unary(mpl, O_CVTLOG, y, A_LOGICAL, 0); if (y->type != A_LOGICAL) error_following(mpl, opstr); x = make_binary(mpl, O_AND, x, y, A_LOGICAL, 0); } else break; } return x; } /*---------------------------------------------------------------------- -- expression_13 - parse expression of level 13. -- -- This routine parses expression of level 13 using the syntax: -- -- ::= -- ::= or -- ::= || */ CODE *expression_13(MPL *mpl) { CODE *x, *y; char opstr[8]; x = expression_12(mpl); for (;;) { if (mpl->token == T_OR) { strcpy(opstr, mpl->image); xassert(strlen(opstr) < sizeof(opstr)); if (x->type == A_SYMBOLIC) x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0); if (x->type == A_NUMERIC) x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0); if (x->type != A_LOGICAL) error_preceding(mpl, opstr); get_token(mpl /* or | || */); y = expression_12(mpl); if (y->type == A_SYMBOLIC) y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0); if (y->type == A_NUMERIC) y = make_unary(mpl, O_CVTLOG, y, A_LOGICAL, 0); if (y->type != A_LOGICAL) error_following(mpl, opstr); x = make_binary(mpl, O_OR, x, y, A_LOGICAL, 0); } else break; } return x; } /*---------------------------------------------------------------------- -- set_statement - parse set statement. -- -- This routine parses set statement using the syntax: -- -- ::= set -- ; -- ::= -- ::= -- ::= -- ::= -- ::= -- ::= , dimen -- ::= , within -- ::= , := -- ::= , default -- -- Commae in are optional and may be omitted anywhere. */ SET *set_statement(MPL *mpl) { SET *set; int dimen_used = 0; xassert(is_keyword(mpl, "set")); get_token(mpl /* set */); /* symbolic name must follow the keyword 'set' */ if (mpl->token == T_NAME) ; else if (is_reserved(mpl)) error(mpl, "invalid use of reserved keyword %s", mpl->image); else error(mpl, "symbolic name missing where expected"); /* there must be no other object with the same name */ if (avl_find_node(mpl->tree, mpl->image) != NULL) error(mpl, "%s multiply declared", mpl->image); /* create model set */ set = alloc(SET); set->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1); strcpy(set->name, mpl->image); set->alias = NULL; set->dim = 0; set->domain = NULL; set->dimen = 0; set->within = NULL; set->assign = NULL; set->option = NULL; set->gadget = NULL; set->data = 0; set->array = NULL; get_token(mpl /* */); /* parse optional alias */ if (mpl->token == T_STRING) { set->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1); strcpy(set->alias, mpl->image); get_token(mpl /* */); } /* parse optional indexing expression */ if (mpl->token == T_LBRACE) { set->domain = indexing_expression(mpl); set->dim = domain_arity(mpl, set->domain); } /* include the set name in the symbolic names table */ { AVLNODE *node; node = avl_insert_node(mpl->tree, set->name); avl_set_node_type(node, A_SET); avl_set_node_link(node, (void *)set); } /* parse the list of optional attributes */ for (;;) { if (mpl->token == T_COMMA) get_token(mpl /* , */); else if (mpl->token == T_SEMICOLON) break; if (is_keyword(mpl, "dimen")) { /* dimension of set members */ int dimen; get_token(mpl /* dimen */); if (!(mpl->token == T_NUMBER && 1.0 <= mpl->value && mpl->value <= 20.0 && floor(mpl->value) == mpl->value)) error(mpl, "dimension must be integer between 1 and 20"); dimen = (int)(mpl->value + 0.5); if (dimen_used) error(mpl, "at most one dimension attribute allowed"); if (set->dimen > 0) error(mpl, "dimension %d conflicts with dimension %d alr" "eady determined", dimen, set->dimen); set->dimen = dimen; dimen_used = 1; get_token(mpl /* */); } else if (mpl->token == T_WITHIN || mpl->token == T_IN) { /* restricting superset */ WITHIN *within, *temp; if (mpl->token == T_IN && !mpl->as_within) { warning(mpl, "keyword in understood as within"); mpl->as_within = 1; } get_token(mpl /* within */); /* create new restricting superset list entry and append it to the within-list */ within = alloc(WITHIN); within->code = NULL; within->next = NULL; if (set->within == NULL) set->within = within; else { for (temp = set->within; temp->next != NULL; temp = temp->next); temp->next = within; } /* parse an expression that follows 'within' */ within->code = expression_9(mpl); if (within->code->type != A_ELEMSET) error(mpl, "expression following within has invalid type" ); xassert(within->code->dim > 0); /* check/set dimension of set members */ if (set->dimen == 0) set->dimen = within->code->dim; if (set->dimen != within->code->dim) error(mpl, "set expression following within must have di" "mension %d rather than %d", set->dimen, within->code->dim); } else if (mpl->token == T_ASSIGN) { /* assignment expression */ if (!(set->assign == NULL && set->option == NULL && set->gadget == NULL)) err: error(mpl, "at most one := or default/data allowed"); get_token(mpl /* := */); /* parse an expression that follows ':=' */ set->assign = expression_9(mpl); if (set->assign->type != A_ELEMSET) error(mpl, "expression following := has invalid type"); xassert(set->assign->dim > 0); /* check/set dimension of set members */ if (set->dimen == 0) set->dimen = set->assign->dim; if (set->dimen != set->assign->dim) error(mpl, "set expression following := must have dimens" "ion %d rather than %d", set->dimen, set->assign->dim); } else if (is_keyword(mpl, "default")) { /* expression for default value */ if (!(set->assign == NULL && set->option == NULL)) goto err; get_token(mpl /* := */); /* parse an expression that follows 'default' */ set->option = expression_9(mpl); if (set->option->type != A_ELEMSET) error(mpl, "expression following default has invalid typ" "e"); xassert(set->option->dim > 0); /* check/set dimension of set members */ if (set->dimen == 0) set->dimen = set->option->dim; if (set->dimen != set->option->dim) error(mpl, "set expression following default must have d" "imension %d rather than %d", set->dimen, set->option->dim); } #if 1 /* 12/XII-2008 */ else if (is_keyword(mpl, "data")) { /* gadget to initialize the set by data from plain set */ GADGET *gadget; AVLNODE *node; int i, k, fff[20]; if (!(set->assign == NULL && set->gadget == NULL)) goto err; get_token(mpl /* data */); set->gadget = gadget = alloc(GADGET); /* set name must follow the keyword 'data' */ if (mpl->token == T_NAME) ; else if (is_reserved(mpl)) error(mpl, "invalid use of reserved keyword %s", mpl->image); else error(mpl, "set name missing where expected"); /* find the set in the symbolic name table */ node = avl_find_node(mpl->tree, mpl->image); if (node == NULL) error(mpl, "%s not defined", mpl->image); if (avl_get_node_type(node) != A_SET) err1: error(mpl, "%s not a plain set", mpl->image); gadget->set = avl_get_node_link(node); if (gadget->set->dim != 0) goto err1; if (gadget->set == set) error(mpl, "set cannot be initialized by itself"); /* check and set dimensions */ if (set->dim >= gadget->set->dimen) err2: error(mpl, "dimension of %s too small", mpl->image); if (set->dimen == 0) set->dimen = gadget->set->dimen - set->dim; if (set->dim + set->dimen > gadget->set->dimen) goto err2; else if (set->dim + set->dimen < gadget->set->dimen) error(mpl, "dimension of %s too big", mpl->image); get_token(mpl /* set name */); /* left parenthesis must follow the set name */ if (mpl->token == T_LEFT) get_token(mpl /* ( */); else error(mpl, "left parenthesis missing where expected"); /* parse permutation of component numbers */ for (k = 0; k < gadget->set->dimen; k++) fff[k] = 0; k = 0; for (;;) { if (mpl->token != T_NUMBER) error(mpl, "component number missing where expected"); if (str2int(mpl->image, &i) != 0) err3: error(mpl, "component number must be integer between " "1 and %d", gadget->set->dimen); if (!(1 <= i && i <= gadget->set->dimen)) goto err3; if (fff[i-1] != 0) error(mpl, "component %d multiply specified", i); gadget->ind[k++] = i, fff[i-1] = 1; xassert(k <= gadget->set->dimen); get_token(mpl /* number */); if (mpl->token == T_COMMA) get_token(mpl /* , */); else if (mpl->token == T_RIGHT) break; else error(mpl, "syntax error in data attribute"); } if (k < gadget->set->dimen) error(mpl, "there are must be %d components rather than " "%d", gadget->set->dimen, k); get_token(mpl /* ) */); } #endif else error(mpl, "syntax error in set statement"); } /* close the domain scope */ if (set->domain != NULL) close_scope(mpl, set->domain); /* if dimension of set members is still unknown, set it to 1 */ if (set->dimen == 0) set->dimen = 1; /* the set statement has been completely parsed */ xassert(mpl->token == T_SEMICOLON); get_token(mpl /* ; */); return set; } /*---------------------------------------------------------------------- -- parameter_statement - parse parameter statement. -- -- This routine parses parameter statement using the syntax: -- -- ::= param -- ; -- ::= -- ::= -- ::= -- ::= -- ::= -- ::= , integer -- ::= , binary -- ::= , symbolic -- ::= , -- ::= , in -- ::= , := -- ::= , default -- ::= < | <= | = | == | >= | > | <> | != -- -- Commae in are optional and may be omitted anywhere. */ PARAMETER *parameter_statement(MPL *mpl) { PARAMETER *par; int integer_used = 0, binary_used = 0, symbolic_used = 0; xassert(is_keyword(mpl, "param")); get_token(mpl /* param */); /* symbolic name must follow the keyword 'param' */ if (mpl->token == T_NAME) ; else if (is_reserved(mpl)) error(mpl, "invalid use of reserved keyword %s", mpl->image); else error(mpl, "symbolic name missing where expected"); /* there must be no other object with the same name */ if (avl_find_node(mpl->tree, mpl->image) != NULL) error(mpl, "%s multiply declared", mpl->image); /* create model parameter */ par = alloc(PARAMETER); par->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1); strcpy(par->name, mpl->image); par->alias = NULL; par->dim = 0; par->domain = NULL; par->type = A_NUMERIC; par->cond = NULL; par->in = NULL; par->assign = NULL; par->option = NULL; par->data = 0; par->defval = NULL; par->array = NULL; get_token(mpl /* */); /* parse optional alias */ if (mpl->token == T_STRING) { par->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1); strcpy(par->alias, mpl->image); get_token(mpl /* */); } /* parse optional indexing expression */ if (mpl->token == T_LBRACE) { par->domain = indexing_expression(mpl); par->dim = domain_arity(mpl, par->domain); } /* include the parameter name in the symbolic names table */ { AVLNODE *node; node = avl_insert_node(mpl->tree, par->name); avl_set_node_type(node, A_PARAMETER); avl_set_node_link(node, (void *)par); } /* parse the list of optional attributes */ for (;;) { if (mpl->token == T_COMMA) get_token(mpl /* , */); else if (mpl->token == T_SEMICOLON) break; if (is_keyword(mpl, "integer")) { if (integer_used) error(mpl, "at most one integer allowed"); if (par->type == A_SYMBOLIC) error(mpl, "symbolic parameter cannot be integer"); if (par->type != A_BINARY) par->type = A_INTEGER; integer_used = 1; get_token(mpl /* integer */); } else if (is_keyword(mpl, "binary")) bin: { if (binary_used) error(mpl, "at most one binary allowed"); if (par->type == A_SYMBOLIC) error(mpl, "symbolic parameter cannot be binary"); par->type = A_BINARY; binary_used = 1; get_token(mpl /* binary */); } else if (is_keyword(mpl, "logical")) { if (!mpl->as_binary) { warning(mpl, "keyword logical understood as binary"); mpl->as_binary = 1; } goto bin; } else if (is_keyword(mpl, "symbolic")) { if (symbolic_used) error(mpl, "at most one symbolic allowed"); if (par->type != A_NUMERIC) error(mpl, "integer or binary parameter cannot be symbol" "ic"); /* the parameter may be referenced from expressions given in the same parameter declaration, so its type must be completed before parsing that expressions */ if (!(par->cond == NULL && par->in == NULL && par->assign == NULL && par->option == NULL)) error(mpl, "keyword symbolic must precede any other para" "meter attributes"); par->type = A_SYMBOLIC; symbolic_used = 1; get_token(mpl /* symbolic */); } else if (mpl->token == T_LT || mpl->token == T_LE || mpl->token == T_EQ || mpl->token == T_GE || mpl->token == T_GT || mpl->token == T_NE) { /* restricting condition */ CONDITION *cond, *temp; char opstr[8]; /* create new restricting condition list entry and append it to the conditions list */ cond = alloc(CONDITION); switch (mpl->token) { case T_LT: cond->rho = O_LT, strcpy(opstr, mpl->image); break; case T_LE: cond->rho = O_LE, strcpy(opstr, mpl->image); break; case T_EQ: cond->rho = O_EQ, strcpy(opstr, mpl->image); break; case T_GE: cond->rho = O_GE, strcpy(opstr, mpl->image); break; case T_GT: cond->rho = O_GT, strcpy(opstr, mpl->image); break; case T_NE: cond->rho = O_NE, strcpy(opstr, mpl->image); break; default: xassert(mpl->token != mpl->token); } xassert(strlen(opstr) < sizeof(opstr)); cond->code = NULL; cond->next = NULL; if (par->cond == NULL) par->cond = cond; else { for (temp = par->cond; temp->next != NULL; temp = temp->next); temp->next = cond; } #if 0 /* 13/VIII-2008 */ if (par->type == A_SYMBOLIC && !(cond->rho == O_EQ || cond->rho == O_NE)) error(mpl, "inequality restriction not allowed"); #endif get_token(mpl /* rho */); /* parse an expression that follows relational operator */ cond->code = expression_5(mpl); if (!(cond->code->type == A_NUMERIC || cond->code->type == A_SYMBOLIC)) error(mpl, "expression following %s has invalid type", opstr); xassert(cond->code->dim == 0); /* convert to the parameter type, if necessary */ if (par->type != A_SYMBOLIC && cond->code->type == A_SYMBOLIC) cond->code = make_unary(mpl, O_CVTNUM, cond->code, A_NUMERIC, 0); if (par->type == A_SYMBOLIC && cond->code->type != A_SYMBOLIC) cond->code = make_unary(mpl, O_CVTSYM, cond->code, A_SYMBOLIC, 0); } else if (mpl->token == T_IN || mpl->token == T_WITHIN) { /* restricting superset */ WITHIN *in, *temp; if (mpl->token == T_WITHIN && !mpl->as_in) { warning(mpl, "keyword within understood as in"); mpl->as_in = 1; } get_token(mpl /* in */); /* create new restricting superset list entry and append it to the in-list */ in = alloc(WITHIN); in->code = NULL; in->next = NULL; if (par->in == NULL) par->in = in; else { for (temp = par->in; temp->next != NULL; temp = temp->next); temp->next = in; } /* parse an expression that follows 'in' */ in->code = expression_9(mpl); if (in->code->type != A_ELEMSET) error(mpl, "expression following in has invalid type"); xassert(in->code->dim > 0); if (in->code->dim != 1) error(mpl, "set expression following in must have dimens" "ion 1 rather than %d", in->code->dim); } else if (mpl->token == T_ASSIGN) { /* assignment expression */ if (!(par->assign == NULL && par->option == NULL)) err: error(mpl, "at most one := or default allowed"); get_token(mpl /* := */); /* parse an expression that follows ':=' */ par->assign = expression_5(mpl); /* the expression must be of numeric/symbolic type */ if (!(par->assign->type == A_NUMERIC || par->assign->type == A_SYMBOLIC)) error(mpl, "expression following := has invalid type"); xassert(par->assign->dim == 0); /* convert to the parameter type, if necessary */ if (par->type != A_SYMBOLIC && par->assign->type == A_SYMBOLIC) par->assign = make_unary(mpl, O_CVTNUM, par->assign, A_NUMERIC, 0); if (par->type == A_SYMBOLIC && par->assign->type != A_SYMBOLIC) par->assign = make_unary(mpl, O_CVTSYM, par->assign, A_SYMBOLIC, 0); } else if (is_keyword(mpl, "default")) { /* expression for default value */ if (!(par->assign == NULL && par->option == NULL)) goto err; get_token(mpl /* default */); /* parse an expression that follows 'default' */ par->option = expression_5(mpl); if (!(par->option->type == A_NUMERIC || par->option->type == A_SYMBOLIC)) error(mpl, "expression following default has invalid typ" "e"); xassert(par->option->dim == 0); /* convert to the parameter type, if necessary */ if (par->type != A_SYMBOLIC && par->option->type == A_SYMBOLIC) par->option = make_unary(mpl, O_CVTNUM, par->option, A_NUMERIC, 0); if (par->type == A_SYMBOLIC && par->option->type != A_SYMBOLIC) par->option = make_unary(mpl, O_CVTSYM, par->option, A_SYMBOLIC, 0); } else error(mpl, "syntax error in parameter statement"); } /* close the domain scope */ if (par->domain != NULL) close_scope(mpl, par->domain); /* the parameter statement has been completely parsed */ xassert(mpl->token == T_SEMICOLON); get_token(mpl /* ; */); return par; } /*---------------------------------------------------------------------- -- variable_statement - parse variable statement. -- -- This routine parses variable statement using the syntax: -- -- ::= var -- ; -- ::= -- ::= -- ::= -- ::= -- ::= -- ::= , integer -- ::= , binary -- ::= , -- ::= >= | <= | = | == -- -- Commae in are optional and may be omitted anywhere. */ VARIABLE *variable_statement(MPL *mpl) { VARIABLE *var; int integer_used = 0, binary_used = 0; xassert(is_keyword(mpl, "var")); if (mpl->flag_s) error(mpl, "variable statement must precede solve statement"); get_token(mpl /* var */); /* symbolic name must follow the keyword 'var' */ if (mpl->token == T_NAME) ; else if (is_reserved(mpl)) error(mpl, "invalid use of reserved keyword %s", mpl->image); else error(mpl, "symbolic name missing where expected"); /* there must be no other object with the same name */ if (avl_find_node(mpl->tree, mpl->image) != NULL) error(mpl, "%s multiply declared", mpl->image); /* create model variable */ var = alloc(VARIABLE); var->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1); strcpy(var->name, mpl->image); var->alias = NULL; var->dim = 0; var->domain = NULL; var->type = A_NUMERIC; var->lbnd = NULL; var->ubnd = NULL; var->array = NULL; get_token(mpl /* */); /* parse optional alias */ if (mpl->token == T_STRING) { var->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1); strcpy(var->alias, mpl->image); get_token(mpl /* */); } /* parse optional indexing expression */ if (mpl->token == T_LBRACE) { var->domain = indexing_expression(mpl); var->dim = domain_arity(mpl, var->domain); } /* include the variable name in the symbolic names table */ { AVLNODE *node; node = avl_insert_node(mpl->tree, var->name); avl_set_node_type(node, A_VARIABLE); avl_set_node_link(node, (void *)var); } /* parse the list of optional attributes */ for (;;) { if (mpl->token == T_COMMA) get_token(mpl /* , */); else if (mpl->token == T_SEMICOLON) break; if (is_keyword(mpl, "integer")) { if (integer_used) error(mpl, "at most one integer allowed"); if (var->type != A_BINARY) var->type = A_INTEGER; integer_used = 1; get_token(mpl /* integer */); } else if (is_keyword(mpl, "binary")) bin: { if (binary_used) error(mpl, "at most one binary allowed"); var->type = A_BINARY; binary_used = 1; get_token(mpl /* binary */); } else if (is_keyword(mpl, "logical")) { if (!mpl->as_binary) { warning(mpl, "keyword logical understood as binary"); mpl->as_binary = 1; } goto bin; } else if (is_keyword(mpl, "symbolic")) error(mpl, "variable cannot be symbolic"); else if (mpl->token == T_GE) { /* lower bound */ if (var->lbnd != NULL) { if (var->lbnd == var->ubnd) error(mpl, "both fixed value and lower bound not allo" "wed"); else error(mpl, "at most one lower bound allowed"); } get_token(mpl /* >= */); /* parse an expression that specifies the lower bound */ var->lbnd = expression_5(mpl); if (var->lbnd->type == A_SYMBOLIC) var->lbnd = make_unary(mpl, O_CVTNUM, var->lbnd, A_NUMERIC, 0); if (var->lbnd->type != A_NUMERIC) error(mpl, "expression following >= has invalid type"); xassert(var->lbnd->dim == 0); } else if (mpl->token == T_LE) { /* upper bound */ if (var->ubnd != NULL) { if (var->ubnd == var->lbnd) error(mpl, "both fixed value and upper bound not allo" "wed"); else error(mpl, "at most one upper bound allowed"); } get_token(mpl /* <= */); /* parse an expression that specifies the upper bound */ var->ubnd = expression_5(mpl); if (var->ubnd->type == A_SYMBOLIC) var->ubnd = make_unary(mpl, O_CVTNUM, var->ubnd, A_NUMERIC, 0); if (var->ubnd->type != A_NUMERIC) error(mpl, "expression following <= has invalid type"); xassert(var->ubnd->dim == 0); } else if (mpl->token == T_EQ) { /* fixed value */ char opstr[8]; if (!(var->lbnd == NULL && var->ubnd == NULL)) { if (var->lbnd == var->ubnd) error(mpl, "at most one fixed value allowed"); else if (var->lbnd != NULL) error(mpl, "both lower bound and fixed value not allo" "wed"); else error(mpl, "both upper bound and fixed value not allo" "wed"); } strcpy(opstr, mpl->image); xassert(strlen(opstr) < sizeof(opstr)); get_token(mpl /* = | == */); /* parse an expression that specifies the fixed value */ var->lbnd = expression_5(mpl); if (var->lbnd->type == A_SYMBOLIC) var->lbnd = make_unary(mpl, O_CVTNUM, var->lbnd, A_NUMERIC, 0); if (var->lbnd->type != A_NUMERIC) error(mpl, "expression following %s has invalid type", opstr); xassert(var->lbnd->dim == 0); /* indicate that the variable is fixed, not bounded */ var->ubnd = var->lbnd; } else if (mpl->token == T_LT || mpl->token == T_GT || mpl->token == T_NE) error(mpl, "strict bound not allowed"); else error(mpl, "syntax error in variable statement"); } /* close the domain scope */ if (var->domain != NULL) close_scope(mpl, var->domain); /* the variable statement has been completely parsed */ xassert(mpl->token == T_SEMICOLON); get_token(mpl /* ; */); return var; } /*---------------------------------------------------------------------- -- constraint_statement - parse constraint statement. -- -- This routine parses constraint statement using the syntax: -- -- ::= -- : ; -- ::= -- ::= subject to -- ::= subj to -- ::= s.t. -- ::= -- ::= -- ::= -- ::= -- ::= , >= -- ::= , <= -- ::= , = -- ::= , <= , <= -- ::= , >= , >= -- ::= -- -- Commae in are optional and may be omitted anywhere. */ CONSTRAINT *constraint_statement(MPL *mpl) { CONSTRAINT *con; CODE *first, *second, *third; int rho; char opstr[8]; if (mpl->flag_s) error(mpl, "constraint statement must precede solve statement") ; if (is_keyword(mpl, "subject")) { get_token(mpl /* subject */); if (!is_keyword(mpl, "to")) error(mpl, "keyword subject to incomplete"); get_token(mpl /* to */); } else if (is_keyword(mpl, "subj")) { get_token(mpl /* subj */); if (!is_keyword(mpl, "to")) error(mpl, "keyword subj to incomplete"); get_token(mpl /* to */); } else if (mpl->token == T_SPTP) get_token(mpl /* s.t. */); /* the current token must be symbolic name of constraint */ if (mpl->token == T_NAME) ; else if (is_reserved(mpl)) error(mpl, "invalid use of reserved keyword %s", mpl->image); else error(mpl, "symbolic name missing where expected"); /* there must be no other object with the same name */ if (avl_find_node(mpl->tree, mpl->image) != NULL) error(mpl, "%s multiply declared", mpl->image); /* create model constraint */ con = alloc(CONSTRAINT); con->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1); strcpy(con->name, mpl->image); con->alias = NULL; con->dim = 0; con->domain = NULL; con->type = A_CONSTRAINT; con->code = NULL; con->lbnd = NULL; con->ubnd = NULL; con->array = NULL; get_token(mpl /* */); /* parse optional alias */ if (mpl->token == T_STRING) { con->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1); strcpy(con->alias, mpl->image); get_token(mpl /* */); } /* parse optional indexing expression */ if (mpl->token == T_LBRACE) { con->domain = indexing_expression(mpl); con->dim = domain_arity(mpl, con->domain); } /* include the constraint name in the symbolic names table */ { AVLNODE *node; node = avl_insert_node(mpl->tree, con->name); avl_set_node_type(node, A_CONSTRAINT); avl_set_node_link(node, (void *)con); } /* the colon must precede the first expression */ if (mpl->token != T_COLON) error(mpl, "colon missing where expected"); get_token(mpl /* : */); /* parse the first expression */ first = expression_5(mpl); if (first->type == A_SYMBOLIC) first = make_unary(mpl, O_CVTNUM, first, A_NUMERIC, 0); if (!(first->type == A_NUMERIC || first->type == A_FORMULA)) error(mpl, "expression following colon has invalid type"); xassert(first->dim == 0); /* relational operator must follow the first expression */ if (mpl->token == T_COMMA) get_token(mpl /* , */); switch (mpl->token) { case T_LE: case T_GE: case T_EQ: break; case T_LT: case T_GT: case T_NE: error(mpl, "strict inequality not allowed"); case T_SEMICOLON: error(mpl, "constraint must be equality or inequality"); default: goto err; } rho = mpl->token; strcpy(opstr, mpl->image); xassert(strlen(opstr) < sizeof(opstr)); get_token(mpl /* rho */); /* parse the second expression */ second = expression_5(mpl); if (second->type == A_SYMBOLIC) second = make_unary(mpl, O_CVTNUM, second, A_NUMERIC, 0); if (!(second->type == A_NUMERIC || second->type == A_FORMULA)) error(mpl, "expression following %s has invalid type", opstr); xassert(second->dim == 0); /* check a token that follow the second expression */ if (mpl->token == T_COMMA) { get_token(mpl /* , */); if (mpl->token == T_SEMICOLON) goto err; } if (mpl->token == T_LT || mpl->token == T_LE || mpl->token == T_EQ || mpl->token == T_GE || mpl->token == T_GT || mpl->token == T_NE) { /* it is another relational operator, therefore the constraint is double inequality */ if (rho == T_EQ || mpl->token != rho) error(mpl, "double inequality must be ... <= ... <= ... or " "... >= ... >= ..."); /* the first expression cannot be linear form */ if (first->type == A_FORMULA) error(mpl, "leftmost expression in double inequality cannot" " be linear form"); get_token(mpl /* rho */); /* parse the third expression */ third = expression_5(mpl); if (third->type == A_SYMBOLIC) third = make_unary(mpl, O_CVTNUM, second, A_NUMERIC, 0); if (!(third->type == A_NUMERIC || third->type == A_FORMULA)) error(mpl, "rightmost expression in double inequality const" "raint has invalid type"); xassert(third->dim == 0); /* the third expression also cannot be linear form */ if (third->type == A_FORMULA) error(mpl, "rightmost expression in double inequality canno" "t be linear form"); } else { /* the constraint is equality or single inequality */ third = NULL; } /* close the domain scope */ if (con->domain != NULL) close_scope(mpl, con->domain); /* convert all expressions to linear form, if necessary */ if (first->type != A_FORMULA) first = make_unary(mpl, O_CVTLFM, first, A_FORMULA, 0); if (second->type != A_FORMULA) second = make_unary(mpl, O_CVTLFM, second, A_FORMULA, 0); if (third != NULL) third = make_unary(mpl, O_CVTLFM, third, A_FORMULA, 0); /* arrange expressions in the constraint */ if (third == NULL) { /* the constraint is equality or single inequality */ switch (rho) { case T_LE: /* first <= second */ con->code = first; con->lbnd = NULL; con->ubnd = second; break; case T_GE: /* first >= second */ con->code = first; con->lbnd = second; con->ubnd = NULL; break; case T_EQ: /* first = second */ con->code = first; con->lbnd = second; con->ubnd = second; break; default: xassert(rho != rho); } } else { /* the constraint is double inequality */ switch (rho) { case T_LE: /* first <= second <= third */ con->code = second; con->lbnd = first; con->ubnd = third; break; case T_GE: /* first >= second >= third */ con->code = second; con->lbnd = third; con->ubnd = first; break; default: xassert(rho != rho); } } /* the constraint statement has been completely parsed */ if (mpl->token != T_SEMICOLON) err: error(mpl, "syntax error in constraint statement"); get_token(mpl /* ; */); return con; } /*---------------------------------------------------------------------- -- objective_statement - parse objective statement. -- -- This routine parses objective statement using the syntax: -- -- ::= : -- ; -- ::= minimize -- ::= maximize -- ::= -- ::= -- ::= -- ::= -- ::= */ CONSTRAINT *objective_statement(MPL *mpl) { CONSTRAINT *obj; int type; if (is_keyword(mpl, "minimize")) type = A_MINIMIZE; else if (is_keyword(mpl, "maximize")) type = A_MAXIMIZE; else xassert(mpl != mpl); if (mpl->flag_s) error(mpl, "objective statement must precede solve statement"); get_token(mpl /* minimize | maximize */); /* symbolic name must follow the verb 'minimize' or 'maximize' */ if (mpl->token == T_NAME) ; else if (is_reserved(mpl)) error(mpl, "invalid use of reserved keyword %s", mpl->image); else error(mpl, "symbolic name missing where expected"); /* there must be no other object with the same name */ if (avl_find_node(mpl->tree, mpl->image) != NULL) error(mpl, "%s multiply declared", mpl->image); /* create model objective */ obj = alloc(CONSTRAINT); obj->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1); strcpy(obj->name, mpl->image); obj->alias = NULL; obj->dim = 0; obj->domain = NULL; obj->type = type; obj->code = NULL; obj->lbnd = NULL; obj->ubnd = NULL; obj->array = NULL; get_token(mpl /* */); /* parse optional alias */ if (mpl->token == T_STRING) { obj->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1); strcpy(obj->alias, mpl->image); get_token(mpl /* */); } /* parse optional indexing expression */ if (mpl->token == T_LBRACE) { obj->domain = indexing_expression(mpl); obj->dim = domain_arity(mpl, obj->domain); } /* include the constraint name in the symbolic names table */ { AVLNODE *node; node = avl_insert_node(mpl->tree, obj->name); avl_set_node_type(node, A_CONSTRAINT); avl_set_node_link(node, (void *)obj); } /* the colon must precede the objective expression */ if (mpl->token != T_COLON) error(mpl, "colon missing where expected"); get_token(mpl /* : */); /* parse the objective expression */ obj->code = expression_5(mpl); if (obj->code->type == A_SYMBOLIC) obj->code = make_unary(mpl, O_CVTNUM, obj->code, A_NUMERIC, 0); if (obj->code->type == A_NUMERIC) obj->code = make_unary(mpl, O_CVTLFM, obj->code, A_FORMULA, 0); if (obj->code->type != A_FORMULA) error(mpl, "expression following colon has invalid type"); xassert(obj->code->dim == 0); /* close the domain scope */ if (obj->domain != NULL) close_scope(mpl, obj->domain); /* the objective statement has been completely parsed */ if (mpl->token != T_SEMICOLON) error(mpl, "syntax error in objective statement"); get_token(mpl /* ; */); return obj; } #if 1 /* 11/II-2008 */ /*********************************************************************** * table_statement - parse table statement * * This routine parses table statement using the syntax: * * ::= *
::= * * ::= * table
IN : * [ ] , ; * ::= * ::= * ::= * ::= * ::= , * ::= * ::= <- * ::= * ::= , * ::= * ::= , * ::= * ::= ~ * * ::= * table
OUT : * ; * ::= * ::= * ::= , * ::= * ::= ~ */ TABLE *table_statement(MPL *mpl) { TABLE *tab; TABARG *last_arg, *arg; TABFLD *last_fld, *fld; TABIN *last_in, *in; TABOUT *last_out, *out; AVLNODE *node; int nflds; char name[MAX_LENGTH+1]; xassert(is_keyword(mpl, "table")); get_token(mpl /* solve */); /* symbolic name must follow the keyword table */ if (mpl->token == T_NAME) ; else if (is_reserved(mpl)) error(mpl, "invalid use of reserved keyword %s", mpl->image); else error(mpl, "symbolic name missing where expected"); /* there must be no other object with the same name */ if (avl_find_node(mpl->tree, mpl->image) != NULL) error(mpl, "%s multiply declared", mpl->image); /* create data table */ tab = alloc(TABLE); tab->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1); strcpy(tab->name, mpl->image); get_token(mpl /* */); /* parse optional alias */ if (mpl->token == T_STRING) { tab->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1); strcpy(tab->alias, mpl->image); get_token(mpl /* */); } else tab->alias = NULL; /* parse optional indexing expression */ if (mpl->token == T_LBRACE) { /* this is output table */ tab->type = A_OUTPUT; tab->u.out.domain = indexing_expression(mpl); if (!is_keyword(mpl, "OUT")) error(mpl, "keyword OUT missing where expected"); get_token(mpl /* OUT */); } else { /* this is input table */ tab->type = A_INPUT; if (!is_keyword(mpl, "IN")) error(mpl, "keyword IN missing where expected"); get_token(mpl /* IN */); } /* parse argument list */ tab->arg = last_arg = NULL; for (;;) { /* create argument list entry */ arg = alloc(TABARG); /* parse argument expression */ if (mpl->token == T_COMMA || mpl->token == T_COLON || mpl->token == T_SEMICOLON) error(mpl, "argument expression missing where expected"); arg->code = expression_5(mpl); /* convert the result to symbolic type, if necessary */ if (arg->code->type == A_NUMERIC) arg->code = make_unary(mpl, O_CVTSYM, arg->code, A_SYMBOLIC, 0); /* check that now the result is of symbolic type */ if (arg->code->type != A_SYMBOLIC) error(mpl, "argument expression has invalid type"); /* add the entry to the end of the list */ arg->next = NULL; if (last_arg == NULL) tab->arg = arg; else last_arg->next = arg; last_arg = arg; /* argument expression has been parsed */ if (mpl->token == T_COMMA) get_token(mpl /* , */); else if (mpl->token == T_COLON || mpl->token == T_SEMICOLON) break; } xassert(tab->arg != NULL); /* argument list must end with colon */ if (mpl->token == T_COLON) get_token(mpl /* : */); else error(mpl, "colon missing where expected"); /* parse specific part of the table statement */ switch (tab->type) { case A_INPUT: goto input_table; case A_OUTPUT: goto output_table; default: xassert(tab != tab); } input_table: /* parse optional set name */ if (mpl->token == T_NAME) { node = avl_find_node(mpl->tree, mpl->image); if (node == NULL) error(mpl, "%s not defined", mpl->image); if (avl_get_node_type(node) != A_SET) error(mpl, "%s not a set", mpl->image); tab->u.in.set = (SET *)avl_get_node_link(node); if (tab->u.in.set->assign != NULL) error(mpl, "%s needs no data", mpl->image); if (tab->u.in.set->dim != 0) error(mpl, "%s must be a simple set", mpl->image); get_token(mpl /* */); if (mpl->token == T_INPUT) get_token(mpl /* <- */); else error(mpl, "delimiter <- missing where expected"); } else if (is_reserved(mpl)) error(mpl, "invalid use of reserved keyword %s", mpl->image); else tab->u.in.set = NULL; /* parse field list */ tab->u.in.fld = last_fld = NULL; nflds = 0; if (mpl->token == T_LBRACKET) get_token(mpl /* [ */); else error(mpl, "field list missing where expected"); for (;;) { /* create field list entry */ fld = alloc(TABFLD); /* parse field name */ if (mpl->token == T_NAME) ; else if (is_reserved(mpl)) error(mpl, "invalid use of reserved keyword %s", mpl->image); else error(mpl, "field name missing where expected"); fld->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1); strcpy(fld->name, mpl->image); get_token(mpl /* */); /* add the entry to the end of the list */ fld->next = NULL; if (last_fld == NULL) tab->u.in.fld = fld; else last_fld->next = fld; last_fld = fld; nflds++; /* field name has been parsed */ if (mpl->token == T_COMMA) get_token(mpl /* , */); else if (mpl->token == T_RBRACKET) break; else error(mpl, "syntax error in field list"); } /* check that the set dimen is equal to the number of fields */ if (tab->u.in.set != NULL && tab->u.in.set->dimen != nflds) error(mpl, "there must be %d field%s rather than %d", tab->u.in.set->dimen, tab->u.in.set->dimen == 1 ? "" : "s", nflds); get_token(mpl /* ] */); /* parse optional input list */ tab->u.in.list = last_in = NULL; while (mpl->token == T_COMMA) { get_token(mpl /* , */); /* create input list entry */ in = alloc(TABIN); /* parse parameter name */ if (mpl->token == T_NAME) ; else if (is_reserved(mpl)) error(mpl, "invalid use of reserved keyword %s", mpl->image); else error(mpl, "parameter name missing where expected"); node = avl_find_node(mpl->tree, mpl->image); if (node == NULL) error(mpl, "%s not defined", mpl->image); if (avl_get_node_type(node) != A_PARAMETER) error(mpl, "%s not a parameter", mpl->image); in->par = (PARAMETER *)avl_get_node_link(node); if (in->par->dim != nflds) error(mpl, "%s must have %d subscript%s rather than %d", mpl->image, nflds, nflds == 1 ? "" : "s", in->par->dim); if (in->par->assign != NULL) error(mpl, "%s needs no data", mpl->image); get_token(mpl /* */); /* parse optional field name */ if (mpl->token == T_TILDE) { get_token(mpl /* ~ */); /* parse field name */ if (mpl->token == T_NAME) ; else if (is_reserved(mpl)) error(mpl, "invalid use of reserved keyword %s", mpl->image); else error(mpl, "field name missing where expected"); xassert(strlen(mpl->image) < sizeof(name)); strcpy(name, mpl->image); get_token(mpl /* */); } else { /* field name is the same as the parameter name */ xassert(strlen(in->par->name) < sizeof(name)); strcpy(name, in->par->name); } /* assign field name */ in->name = dmp_get_atomv(mpl->pool, strlen(name)+1); strcpy(in->name, name); /* add the entry to the end of the list */ in->next = NULL; if (last_in == NULL) tab->u.in.list = in; else last_in->next = in; last_in = in; } goto end_of_table; output_table: /* parse output list */ tab->u.out.list = last_out = NULL; for (;;) { /* create output list entry */ out = alloc(TABOUT); /* parse expression */ if (mpl->token == T_COMMA || mpl->token == T_SEMICOLON) error(mpl, "expression missing where expected"); if (mpl->token == T_NAME) { xassert(strlen(mpl->image) < sizeof(name)); strcpy(name, mpl->image); } else name[0] = '\0'; out->code = expression_5(mpl); /* parse optional field name */ if (mpl->token == T_TILDE) { get_token(mpl /* ~ */); /* parse field name */ if (mpl->token == T_NAME) ; else if (is_reserved(mpl)) error(mpl, "invalid use of reserved keyword %s", mpl->image); else error(mpl, "field name missing where expected"); xassert(strlen(mpl->image) < sizeof(name)); strcpy(name, mpl->image); get_token(mpl /* */); } /* assign field name */ if (name[0] == '\0') error(mpl, "field name required"); out->name = dmp_get_atomv(mpl->pool, strlen(name)+1); strcpy(out->name, name); /* add the entry to the end of the list */ out->next = NULL; if (last_out == NULL) tab->u.out.list = out; else last_out->next = out; last_out = out; /* output item has been parsed */ if (mpl->token == T_COMMA) get_token(mpl /* , */); else if (mpl->token == T_SEMICOLON) break; else error(mpl, "syntax error in output list"); } /* close the domain scope */ close_scope(mpl,tab->u.out.domain); end_of_table: /* the table statement must end with semicolon */ if (mpl->token != T_SEMICOLON) error(mpl, "syntax error in table statement"); get_token(mpl /* ; */); return tab; } #endif /*---------------------------------------------------------------------- -- solve_statement - parse solve statement. -- -- This routine parses solve statement using the syntax: -- -- ::= solve ; -- -- The solve statement can be used at most once. */ void *solve_statement(MPL *mpl) { xassert(is_keyword(mpl, "solve")); if (mpl->flag_s) error(mpl, "at most one solve statement allowed"); mpl->flag_s = 1; get_token(mpl /* solve */); /* semicolon must follow solve statement */ if (mpl->token != T_SEMICOLON) error(mpl, "syntax error in solve statement"); get_token(mpl /* ; */); return NULL; } /*---------------------------------------------------------------------- -- check_statement - parse check statement. -- -- This routine parses check statement using the syntax: -- -- ::= check : ; -- ::= -- ::= -- -- If is omitted, colon following it may also be omitted. */ CHECK *check_statement(MPL *mpl) { CHECK *chk; xassert(is_keyword(mpl, "check")); /* create check descriptor */ chk = alloc(CHECK); chk->domain = NULL; chk->code = NULL; get_token(mpl /* check */); /* parse optional indexing expression */ if (mpl->token == T_LBRACE) { chk->domain = indexing_expression(mpl); #if 0 if (mpl->token != T_COLON) error(mpl, "colon missing where expected"); #endif } /* skip optional colon */ if (mpl->token == T_COLON) get_token(mpl /* : */); /* parse logical expression */ chk->code = expression_13(mpl); if (chk->code->type != A_LOGICAL) error(mpl, "expression has invalid type"); xassert(chk->code->dim == 0); /* close the domain scope */ if (chk->domain != NULL) close_scope(mpl, chk->domain); /* the check statement has been completely parsed */ if (mpl->token != T_SEMICOLON) error(mpl, "syntax error in check statement"); get_token(mpl /* ; */); return chk; } #if 1 /* 15/V-2010 */ /*---------------------------------------------------------------------- -- display_statement - parse display statement. -- -- This routine parses display statement using the syntax: -- -- ::= display : ; -- ::= display ; -- ::= -- ::= -- ::= -- ::= , -- ::= -- ::= -- ::= [ ] -- ::= -- ::= [ ] -- ::= -- ::= [ ] -- ::= -- ::= [ ] -- ::= */ DISPLAY *display_statement(MPL *mpl) { DISPLAY *dpy; DISPLAY1 *entry, *last_entry; xassert(is_keyword(mpl, "display")); /* create display descriptor */ dpy = alloc(DISPLAY); dpy->domain = NULL; dpy->list = last_entry = NULL; get_token(mpl /* display */); /* parse optional indexing expression */ if (mpl->token == T_LBRACE) dpy->domain = indexing_expression(mpl); /* skip optional colon */ if (mpl->token == T_COLON) get_token(mpl /* : */); /* parse display list */ for (;;) { /* create new display entry */ entry = alloc(DISPLAY1); entry->type = 0; entry->next = NULL; /* and append it to the display list */ if (dpy->list == NULL) dpy->list = entry; else last_entry->next = entry; last_entry = entry; /* parse display entry */ if (mpl->token == T_NAME) { AVLNODE *node; int next_token; get_token(mpl /* */); next_token = mpl->token; unget_token(mpl); if (!(next_token == T_COMMA || next_token == T_SEMICOLON)) { /* symbolic name begins expression */ goto expr; } /* display entry is dummy index or model object */ node = avl_find_node(mpl->tree, mpl->image); if (node == NULL) error(mpl, "%s not defined", mpl->image); entry->type = avl_get_node_type(node); switch (avl_get_node_type(node)) { case A_INDEX: entry->u.slot = (DOMAIN_SLOT *)avl_get_node_link(node); break; case A_SET: entry->u.set = (SET *)avl_get_node_link(node); break; case A_PARAMETER: entry->u.par = (PARAMETER *)avl_get_node_link(node); break; case A_VARIABLE: entry->u.var = (VARIABLE *)avl_get_node_link(node); if (!mpl->flag_s) error(mpl, "invalid reference to variable %s above" " solve statement", entry->u.var->name); break; case A_CONSTRAINT: entry->u.con = (CONSTRAINT *)avl_get_node_link(node); if (!mpl->flag_s) error(mpl, "invalid reference to %s %s above solve" " statement", entry->u.con->type == A_CONSTRAINT ? "constraint" : "objective", entry->u.con->name); break; default: xassert(node != node); } get_token(mpl /* */); } else expr: { /* display entry is expression */ entry->type = A_EXPRESSION; entry->u.code = expression_13(mpl); } /* check a token that follows the entry parsed */ if (mpl->token == T_COMMA) get_token(mpl /* , */); else break; } /* close the domain scope */ if (dpy->domain != NULL) close_scope(mpl, dpy->domain); /* the display statement has been completely parsed */ if (mpl->token != T_SEMICOLON) error(mpl, "syntax error in display statement"); get_token(mpl /* ; */); return dpy; } #endif /*---------------------------------------------------------------------- -- printf_statement - parse printf statement. -- -- This routine parses print statement using the syntax: -- -- ::= ; -- ::= > ; -- ::= >> ; -- ::= printf : -- ::= printf -- ::= -- ::= -- ::= -- ::= -- ::= , -- ::= -- ::= */ PRINTF *printf_statement(MPL *mpl) { PRINTF *prt; PRINTF1 *entry, *last_entry; xassert(is_keyword(mpl, "printf")); /* create printf descriptor */ prt = alloc(PRINTF); prt->domain = NULL; prt->fmt = NULL; prt->list = last_entry = NULL; get_token(mpl /* printf */); /* parse optional indexing expression */ if (mpl->token == T_LBRACE) { prt->domain = indexing_expression(mpl); #if 0 if (mpl->token != T_COLON) error(mpl, "colon missing where expected"); #endif } /* skip optional colon */ if (mpl->token == T_COLON) get_token(mpl /* : */); /* parse expression for format string */ prt->fmt = expression_5(mpl); /* convert it to symbolic type, if necessary */ if (prt->fmt->type == A_NUMERIC) prt->fmt = make_unary(mpl, O_CVTSYM, prt->fmt, A_SYMBOLIC, 0); /* check that now the expression is of symbolic type */ if (prt->fmt->type != A_SYMBOLIC) error(mpl, "format expression has invalid type"); /* parse printf list */ while (mpl->token == T_COMMA) { get_token(mpl /* , */); /* create new printf entry */ entry = alloc(PRINTF1); entry->code = NULL; entry->next = NULL; /* and append it to the printf list */ if (prt->list == NULL) prt->list = entry; else last_entry->next = entry; last_entry = entry; /* parse printf entry */ entry->code = expression_9(mpl); if (!(entry->code->type == A_NUMERIC || entry->code->type == A_SYMBOLIC || entry->code->type == A_LOGICAL)) error(mpl, "only numeric, symbolic, or logical expression a" "llowed"); } /* close the domain scope */ if (prt->domain != NULL) close_scope(mpl, prt->domain); #if 1 /* 14/VII-2006 */ /* parse optional redirection */ prt->fname = NULL, prt->app = 0; if (mpl->token == T_GT || mpl->token == T_APPEND) { prt->app = (mpl->token == T_APPEND); get_token(mpl /* > or >> */); /* parse expression for file name string */ prt->fname = expression_5(mpl); /* convert it to symbolic type, if necessary */ if (prt->fname->type == A_NUMERIC) prt->fname = make_unary(mpl, O_CVTSYM, prt->fname, A_SYMBOLIC, 0); /* check that now the expression is of symbolic type */ if (prt->fname->type != A_SYMBOLIC) error(mpl, "file name expression has invalid type"); } #endif /* the printf statement has been completely parsed */ if (mpl->token != T_SEMICOLON) error(mpl, "syntax error in printf statement"); get_token(mpl /* ; */); return prt; } /*---------------------------------------------------------------------- -- for_statement - parse for statement. -- -- This routine parses for statement using the syntax: -- -- ::= for -- ::= for { } -- ::= -- ::= -- ::= -- ::= -- ::= -- ::= -- ::= */ FOR *for_statement(MPL *mpl) { FOR *fur; STATEMENT *stmt, *last_stmt; xassert(is_keyword(mpl, "for")); /* create for descriptor */ fur = alloc(FOR); fur->domain = NULL; fur->list = last_stmt = NULL; get_token(mpl /* for */); /* parse indexing expression */ if (mpl->token != T_LBRACE) error(mpl, "indexing expression missing where expected"); fur->domain = indexing_expression(mpl); /* skip optional colon */ if (mpl->token == T_COLON) get_token(mpl /* : */); /* parse for statement body */ if (mpl->token != T_LBRACE) { /* parse simple statement */ fur->list = simple_statement(mpl, 1); } else { /* parse compound statement */ get_token(mpl /* { */); while (mpl->token != T_RBRACE) { /* parse statement */ stmt = simple_statement(mpl, 1); /* and append it to the end of the statement list */ if (last_stmt == NULL) fur->list = stmt; else last_stmt->next = stmt; last_stmt = stmt; } get_token(mpl /* } */); } /* close the domain scope */ xassert(fur->domain != NULL); close_scope(mpl, fur->domain); /* the for statement has been completely parsed */ return fur; } /*---------------------------------------------------------------------- -- end_statement - parse end statement. -- -- This routine parses end statement using the syntax: -- -- ::= end ; */ void end_statement(MPL *mpl) { if (!mpl->flag_d && is_keyword(mpl, "end") || mpl->flag_d && is_literal(mpl, "end")) { get_token(mpl /* end */); if (mpl->token == T_SEMICOLON) get_token(mpl /* ; */); else warning(mpl, "no semicolon following end statement; missing" " semicolon inserted"); } else warning(mpl, "unexpected end of file; missing end statement in" "serted"); if (mpl->token != T_EOF) warning(mpl, "some text detected beyond end statement; text ig" "nored"); return; } /*---------------------------------------------------------------------- -- simple_statement - parse simple statement. -- -- This routine parses simple statement using the syntax: -- -- ::= -- ::= -- ::= -- ::= -- ::= -- ::= -- ::= -- ::= -- ::= -- ::= -- -- If the flag spec is set, some statements cannot be used. */ STATEMENT *simple_statement(MPL *mpl, int spec) { STATEMENT *stmt; stmt = alloc(STATEMENT); stmt->line = mpl->line; stmt->next = NULL; if (is_keyword(mpl, "set")) { if (spec) error(mpl, "set statement not allowed here"); stmt->type = A_SET; stmt->u.set = set_statement(mpl); } else if (is_keyword(mpl, "param")) { if (spec) error(mpl, "parameter statement not allowed here"); stmt->type = A_PARAMETER; stmt->u.par = parameter_statement(mpl); } else if (is_keyword(mpl, "var")) { if (spec) error(mpl, "variable statement not allowed here"); stmt->type = A_VARIABLE; stmt->u.var = variable_statement(mpl); } else if (is_keyword(mpl, "subject") || is_keyword(mpl, "subj") || mpl->token == T_SPTP) { if (spec) error(mpl, "constraint statement not allowed here"); stmt->type = A_CONSTRAINT; stmt->u.con = constraint_statement(mpl); } else if (is_keyword(mpl, "minimize") || is_keyword(mpl, "maximize")) { if (spec) error(mpl, "objective statement not allowed here"); stmt->type = A_CONSTRAINT; stmt->u.con = objective_statement(mpl); } #if 1 /* 11/II-2008 */ else if (is_keyword(mpl, "table")) { if (spec) error(mpl, "table statement not allowed here"); stmt->type = A_TABLE; stmt->u.tab = table_statement(mpl); } #endif else if (is_keyword(mpl, "solve")) { if (spec) error(mpl, "solve statement not allowed here"); stmt->type = A_SOLVE; stmt->u.slv = solve_statement(mpl); } else if (is_keyword(mpl, "check")) { stmt->type = A_CHECK; stmt->u.chk = check_statement(mpl); } else if (is_keyword(mpl, "display")) { stmt->type = A_DISPLAY; stmt->u.dpy = display_statement(mpl); } else if (is_keyword(mpl, "printf")) { stmt->type = A_PRINTF; stmt->u.prt = printf_statement(mpl); } else if (is_keyword(mpl, "for")) { stmt->type = A_FOR; stmt->u.fur = for_statement(mpl); } else if (mpl->token == T_NAME) { if (spec) error(mpl, "constraint statement not allowed here"); stmt->type = A_CONSTRAINT; stmt->u.con = constraint_statement(mpl); } else if (is_reserved(mpl)) error(mpl, "invalid use of reserved keyword %s", mpl->image); else error(mpl, "syntax error in model section"); return stmt; } /*---------------------------------------------------------------------- -- model_section - parse model section. -- -- This routine parses model section using the syntax: -- -- ::= -- ::= -- -- Parsing model section is terminated by either the keyword 'data', or -- the keyword 'end', or the end of file. */ void model_section(MPL *mpl) { STATEMENT *stmt, *last_stmt; xassert(mpl->model == NULL); last_stmt = NULL; while (!(mpl->token == T_EOF || is_keyword(mpl, "data") || is_keyword(mpl, "end"))) { /* parse statement */ stmt = simple_statement(mpl, 0); /* and append it to the end of the statement list */ if (last_stmt == NULL) mpl->model = stmt; else last_stmt->next = stmt; last_stmt = stmt; } return; } /* eof */ Rglpk/src/GLPK/glpenv07.c0000644000176000001440000003730412245352174014527 0ustar ripleyusers/* glpenv07.c (stream input/output) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env2.h" #include "zlib/zlib.h" #if 1 /* 11/VI-2013 */ #define IOERR_MSG_SIZE 1024 /* i/o error message buffer size, in bytes */ static char env_ioerr_msg[IOERR_MSG_SIZE] = "No error"; /* input/output error message buffer */ struct XFILE { /* input/output stream descriptor */ int type; /* stream handle type: */ #define FH_FILE 0x11 /* FILE */ #define FH_ZLIB 0x22 /* gzFile */ void *fh; /* pointer to stream handle */ #if 0 /* 11/VI-2013 */ XFILE *prev; /* pointer to previous stream descriptor */ XFILE *next; /* pointer to next stream descriptor */ #endif }; #endif /*********************************************************************** * NAME * * lib_err_msg - save error message string * * SYNOPSIS * * #include "glpenv.h" * void lib_err_msg(const char *msg); * * DESCRIPTION * * The routine lib_err_msg saves an error message string specified by * the parameter msg. The message is obtained by some library routines * with a call to strerror(errno). */ void lib_err_msg(const char *msg) { /*ENV *env = get_env_ptr();*/ int len = strlen(msg); if (len >= IOERR_MSG_SIZE) len = IOERR_MSG_SIZE - 1; #if 0 /* 11/VI-2013 */ memcpy(env->ioerr_msg, msg, len); if (len > 0 && env->ioerr_msg[len-1] == '\n') len--; env->ioerr_msg[len] = '\0'; #else memcpy(env_ioerr_msg, msg, len); if (len > 0 && env_ioerr_msg[len-1] == '\n') len--; env_ioerr_msg[len] = '\0'; #endif return; } /*********************************************************************** * NAME * * xerrmsg - retrieve error message string * * SYNOPSIS * * #include "glpenv.h" * const char *xerrmsg(void); * * RETURNS * * The routine xerrmsg returns a pointer to an error message string * previously set by some library routine to indicate an error. */ const char *xerrmsg(void) { /*ENV *env = get_env_ptr();*/ #if 0 /* 11/VI-2013 */ return env->ioerr_msg; #else return env_ioerr_msg; #endif } /*********************************************************************** * NAME * * xfopen - open a stream * * SYNOPSIS * * #include "glpenv.h" * XFILE *xfopen(const char *fname, const char *mode); * * DESCRIPTION * * The routine xfopen opens the file whose name is a string pointed to * by fname and associates a stream with it. * * The parameter mode points to a string, which indicates the open mode * and should be one of the following: * * "r" open text file for reading; * "w" truncate to zero length or create text file for writing; * "rb" open binary file for reading; * "wb" truncate to zero length or create binary file for writing. * * RETURNS * * The routine xfopen returns a pointer to the object controlling the * stream. If the open operation fails, xfopen returns NULL. */ static void *c_fopen(const char *fname, const char *mode); static void *z_fopen(const char *fname, const char *mode); static int is_gz_file(const char *fname) { char *ext = strrchr(fname, '.'); return ext != NULL && strcmp(ext, ".gz") == 0; } XFILE *xfopen(const char *fname, const char *mode) { /*ENV *env = get_env_ptr();*/ XFILE *fp; int type; void *fh; if (!is_gz_file(fname)) { type = FH_FILE; fh = c_fopen(fname, mode); } else { type = FH_ZLIB; fh = z_fopen(fname, mode); } if (fh == NULL) { fp = NULL; goto done; } fp = xmalloc(sizeof(XFILE)); fp->type = type; fp->fh = fh; #if 0 /* 11/VI-2013 */ fp->prev = NULL; fp->next = env->file_ptr; if (fp->next != NULL) fp->next->prev = fp; env->file_ptr = fp; #endif done: return fp; } /*********************************************************************** * NAME * * xfgetc - read character from the stream * * SYNOPSIS * * #include "glpenv.h" * int xfgetc(XFILE *fp); * * DESCRIPTION * * If the end-of-file indicator for the input stream pointed to by fp * is not set and a next character is present, the routine xfgetc * obtains that character as an unsigned char converted to an int and * advances the associated file position indicator for the stream (if * defined). * * RETURNS * * If the end-of-file indicator for the stream is set, or if the * stream is at end-of-file, the end-of-file indicator for the stream * is set and the routine xfgetc returns XEOF. Otherwise, the routine * xfgetc returns the next character from the input stream pointed to * by fp. If a read error occurs, the error indicator for the stream is * set and the xfgetc routine returns XEOF. * * Note: An end-of-file and a read error can be distinguished by use of * the routines xfeof and xferror. */ static int c_fgetc(void *fh); static int z_fgetc(void *fh); int xfgetc(XFILE *fp) { int c; switch (fp->type) { case FH_FILE: c = c_fgetc(fp->fh); break; case FH_ZLIB: c = z_fgetc(fp->fh); break; default: xassert(fp != fp); } return c; } /*********************************************************************** * NAME * * xfputc - write character to the stream * * SYNOPSIS * * #include "glpenv.h" * int xfputc(int c, XFILE *fp); * * DESCRIPTION * * The routine xfputc writes the character specified by c (converted * to an unsigned char) to the output stream pointed to by fp, at the * position indicated by the associated file position indicator (if * defined), and advances the indicator appropriately. * * RETURNS * * The routine xfputc returns the character written. If a write error * occurs, the error indicator for the stream is set and xfputc returns * XEOF. */ static int c_fputc(int c, void *fh); static int z_fputc(int c, void *fh); int xfputc(int c, XFILE *fp) { switch (fp->type) { case FH_FILE: c = c_fputc(c, fp->fh); break; case FH_ZLIB: c = z_fputc(c, fp->fh); break; default: xassert(fp != fp); } return c; } /*********************************************************************** * NAME * * xferror - test error indicator for the stream * * SYNOPSIS * * #include "glpenv.h" * int xferror(XFILE *fp); * * DESCRIPTION * * The routine xferror tests the error indicator for the stream * pointed to by fp. * * RETURNS * * The routine xferror returns non-zero if and only if the error * indicator is set for the stream. */ static int c_ferror(void *fh); static int z_ferror(void *fh); int xferror(XFILE *fp) { int ret; switch (fp->type) { case FH_FILE: ret = c_ferror(fp->fh); break; case FH_ZLIB: ret = z_ferror(fp->fh); break; default: xassert(fp != fp); } return ret; } /*********************************************************************** * NAME * * xfeof - test end-of-file indicator for the stream * * SYNOPSIS * * #include "glpenv.h" * int xfeof(XFILE *fp); * * DESCRIPTION * * The routine xfeof tests the end-of-file indicator for the stream * pointed to by fp. * * RETURNS * * The routine xfeof returns non-zero if and only if the end-of-file * indicator is set for the stream. */ static int c_feof(void *fh); static int z_feof(void *fh); int xfeof(XFILE *fp) { int ret; switch (fp->type) { case FH_FILE: ret = c_feof(fp->fh); break; case FH_ZLIB: ret = z_feof(fp->fh); break; default: xassert(fp != fp); } return ret; } int xfprintf(XFILE *file, const char *fmt, ...) { ENV *env = get_env_ptr(); int cnt, j; va_list arg; va_start(arg, fmt); cnt = vsprintf(env->term_buf, fmt, arg); va_end(arg); for (j = 0; j < cnt; j++) { if (xfputc(env->term_buf[j], file) < 0) { cnt = -1; break; } } return cnt; } /*********************************************************************** * NAME * * xfflush - flush the stream * * SYNOPSIS * * #include "glpenv.h" * int xfflush(XFILE *fp); * * DESCRIPTION * * The routine xfflush causes any unwritten data for the output stream * pointed to by fp to be written to the associated file. * * RETURNS * * The routine xfflush returns zero if the stream was successfully * flushed. Otherwise, xfflush sets the error indicator for the stream * and returns XEOF. */ static int c_fflush(void *fh); static int z_fflush(void *fh); int xfflush(XFILE *fp) { int ret; switch (fp->type) { case FH_FILE: ret = c_fflush(fp->fh); break; case FH_ZLIB: ret = z_fflush(fp->fh); break; default: xassert(fp != fp); } return ret; } /*********************************************************************** * NAME * * xfclose - close the stream * * SYNOPSIS * * #include "glpenv.h" * int xfclose(XFILE *fp); * * DESCRIPTION * * A successful call to the routine xfclose causes the stream pointed * to by fp to be flushed and the associated file to be closed. Whether * or not the call succeeds, the stream is disassociated from the file. * * RETURNS * * The routine xfclose returns zero if the stream was successfully * closed, or XEOF if any errors were detected. */ static int c_fclose(void *fh); static int z_fclose(void *fh); int xfclose(XFILE *fp) { /*ENV *env = get_env_ptr();*/ int ret; switch (fp->type) { case FH_FILE: ret = c_fclose(fp->fh); break; case FH_ZLIB: ret = z_fclose(fp->fh); break; default: xassert(fp != fp); } fp->type = 0xF00BAD; #if 0 /* 11/VI-2013 */ if (fp->prev == NULL) env->file_ptr = fp->next; else fp->prev->next = fp->next; if (fp->next == NULL) ; else fp->next->prev = fp->prev; #endif xfree(fp); return ret; } /*********************************************************************** * The following routines implement stream input/output based on the * standard C streams. */ static void *c_fopen(const char *fname, const char *mode) { FILE *fh; if (strcmp(fname, "/dev/stdin") == 0) fh = stdin; else if (strcmp(fname, "/dev/stdout") == 0) fh = stdout; else if (strcmp(fname, "/dev/stderr") == 0) fh = stderr; else fh = fopen(fname, mode); if (fh == NULL) lib_err_msg(strerror(errno)); return fh; } static int c_fgetc(void *_fh) { FILE *fh = _fh; int c; if (ferror(fh) || feof(fh)) { c = XEOF; goto done; } c = fgetc(fh); if (ferror(fh)) { lib_err_msg(strerror(errno)); c = XEOF; } else if (feof(fh)) c = XEOF; else xassert(0x00 <= c && c <= 0xFF); done: return c; } static int c_fputc(int c, void *_fh) { FILE *fh = _fh; if (ferror(fh)) { c = XEOF; goto done; } c = (unsigned char)c; fputc(c, fh); if (ferror(fh)) { lib_err_msg(strerror(errno)); c = XEOF; } done: return c; } static int c_ferror(void *_fh) { FILE *fh = _fh; return ferror(fh); } static int c_feof(void *_fh) { FILE *fh = _fh; return feof(fh); } static int c_fflush(void *_fh) { FILE *fh = _fh; int ret; ret = fflush(fh); if (ret != 0) { lib_err_msg(strerror(errno)); ret = XEOF; } return ret; } static int c_fclose(void *_fh) { FILE *fh = _fh; int ret; if (fh == stdin) ret = 0; else if (fh == stdout || fh == stderr) fflush(fh), ret = 0; else ret = fclose(fh); if (ret != 0) { lib_err_msg(strerror(errno)); ret = XEOF; } return ret; } /*********************************************************************** * The following routines implement stream input/output based on the * zlib library, which provides processing .gz files "on the fly". */ struct z_file { /* .gz file handle */ gzFile file; /* pointer to .gz stream */ int err; /* i/o error indicator */ int eof; /* end-of-file indicator */ }; static void *z_fopen(const char *fname, const char *mode) { struct z_file *fh; gzFile file; if (strcmp(mode, "r") == 0 || strcmp(mode, "rb") == 0) mode = "rb"; else if (strcmp(mode, "w") == 0 || strcmp(mode, "wb") == 0) mode = "wb"; else { lib_err_msg("Invalid open mode"); fh = NULL; goto done; } file = gzopen(fname, mode); if (file == NULL) { lib_err_msg(strerror(errno)); fh = NULL; goto done; } fh = xmalloc(sizeof(struct z_file)); fh->file = file; fh->err = fh->eof = 0; done: return fh; } static int z_fgetc(void *_fh) { struct z_file *fh = _fh; int c; if (fh->err || fh->eof) { c = XEOF; goto done; } c = gzgetc(fh->file); if (c < 0) { int errnum; const char *msg; msg = gzerror(fh->file, &errnum); if (errnum == Z_STREAM_END) fh->eof = 1; else if (errnum == Z_ERRNO) { fh->err = 1; lib_err_msg(strerror(errno)); } else { fh->err = 1; lib_err_msg(msg); } c = XEOF; } else xassert(0x00 <= c && c <= 0xFF); done: return c; } static int z_fputc(int c, void *_fh) { struct z_file *fh = _fh; if (fh->err) { c = XEOF; goto done; } c = (unsigned char)c; if (gzputc(fh->file, c) < 0) { int errnum; const char *msg; fh->err = 1; msg = gzerror(fh->file, &errnum); if (errnum == Z_ERRNO) lib_err_msg(strerror(errno)); else lib_err_msg(msg); c = XEOF; } done: return c; } static int z_ferror(void *_fh) { struct z_file *fh = _fh; return fh->err; } static int z_feof(void *_fh) { struct z_file *fh = _fh; return fh->eof; } static int z_fflush(void *_fh) { struct z_file *fh = _fh; int ret; ret = gzflush(fh->file, Z_FINISH); if (ret == Z_OK) ret = 0; else { int errnum; const char *msg; fh->err = 1; msg = gzerror(fh->file, &errnum); if (errnum == Z_ERRNO) lib_err_msg(strerror(errno)); else lib_err_msg(msg); ret = XEOF; } return ret; } static int z_fclose(void *_fh) { struct z_file *fh = _fh; gzclose(fh->file); xfree(fh); return 0; } /* eof */ Rglpk/src/GLPK/relax4.c0000644000176000001440000027304312245352174014266 0ustar ripleyusers/* relax4.c (relaxation method of Bertsekas and Tseng) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * THIS CODE IS THE RESULT OF TRANSLATION OF THE FORTRAN CODE RELAX4. * * THE TRANSLATION HAS BEEN DONE WITH THE PERMISSION OF THE AUTHOR OF * THE ORIGINAL FORTRAN CODE PROF. DIMITRI P. BERTSEKAS, MASSACHUSETTS * INSTITUTE OF TECHNOLOGY, CAMBRIDGE, MASSACHUSETTS, USA. * * The translation was made by Andrew Makhorin . * * 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 . ***********************************************************************/ #include "relax4.h" /*********************************************************************** * WARNING * * A serious bug was *tentatively* fixed in this code (see #if/#endif * marked by 'mao'). * * This bug is inherited from the original Fortran version of the * RELAX-IV code. Unfortunately, the code is very intricate, so this * bug is still under investigation. Thanks to Sylvain Fournier for bug * report. * * RELAX-IV bug details * -------------------- * In the original RELAX-IV code there are four similar fragments in * subroutines ascnt1 and ascnt2 like this: * * C * C DECREASE THE PRICES OF THE SCANNED NODES BY DELPRC. * C ADJUST FLOW TO MAINTAIN COMPLEMENTARY SLACKNESS WITH * C THE PRICES. * C * NB = 0 * DO 6 I=1,NSAVE * . . . * IF (RC(ARC).EQ.0) THEN * DELX=DELX+U(ARC) * NB = NB + 1 * PRDCSR(NB) = ARC * END IF * . . . * * On some instances the variable NB becomes greater than N (the number * of nodes) that leads to indexing error, because the array PRDCSR is * declared as array of N elements (more precisely, as array of MAXNN * elements, however, NB becomes even much greater than MAXNN). ***********************************************************************/ #define false 0 #define true 1 /*********************************************************************** * NAME * * RELAX-IV (version of October 1994) * * PURPOSE * * This routine implements the relaxation method of Bertsekas and Tseng * (see [1], [2]) for linear cost ordinary network flow problems. * * [1] Bertsekas, D. P., "A Unified Framework for Primal-Dual Methods" * Mathematical Programming, Vol. 32, 1985, pp. 125-145. * [2] Bertsekas, D. P., and Tseng, P., "Relaxation Methods for * Minimum Cost" Operations Research, Vol. 26, 1988, pp. 93-114. * * The relaxation method is also described in the books: * * [3] Bertsekas, D. P., "Linear Network Optimization: Algorithms and * Codes" MIT Press, 1991. * [4] Bertsekas, D. P. and Tsitsiklis, J. N., "Parallel and Distributed * Computation: Numerical Methods", Prentice-Hall, 1989. * [5] Bertsekas, D. P., "Network Optimization: Continuous and Discrete * Models", Athena Scientific, 1998. * * RELEASE NOTE * * This version of relaxation code has option for a special crash * procedure for the initial price-flow pair. This is recommended for * difficult problems where the default initialization results in long * running times. crash = 1 corresponds to an auction/shortest path * method * * These initializations are recommended in the absence of any prior * information on a favorable initial flow-price vector pair that * satisfies complementary slackness. * * The relaxation portion of the code differs from the code RELAXT-III * and other earlier relaxation codes in that it maintains the set of * nodes with nonzero deficit in a fifo queue. Like its predecessor * RELAXT-III, this code maintains a linked list of balanced (i.e., of * zero reduced cost) arcs so to reduce the work in labeling and * scanning. Unlike RELAXT-III, it does not use selectively shortest * path iterations for initialization. * * SOURCE * * The original Fortran code was written by Dimitri P. Bertsekas and * Paul Tseng, with a contribution by Jonathan Eckstein in the phase II * initialization. The original Fortran routine AUCTION was written by * Dimitri P. Bertsekas and is based on the method described in the * paper: * * [6] Bertsekas, D. P., "An Auction/Sequential Shortest Path Algorithm * for the Minimum Cost Flow Problem", LIDS Report P-2146, MIT, * Nov. 1992. * * For inquiries about the original Fortran code, please contact: * * Dimitri P. Bertsekas * Laboratory for information and decision systems * Massachusetts Institute of Technology * Cambridge, MA 02139 * (617) 253-7267, dimitrib@mit.edu * * This code is the result of translation of the original Fortran code. * The translation was made by Andrew Makhorin . * * USER GUIDELINES * * This routine is in the public domain to be used only for research * purposes. It cannot be used as part of a commercial product, or to * satisfy in any part commercial delivery requirements to government * or industry, without prior agreement with the authors. Users are * requested to acknowledge the authorship of the code, and the * relaxation method. * * No modification should be made to this code other than the minimal * necessary to make it compatible with specific platforms. * * INPUT PARAMETERS (see notes 1, 2, 4) * * n = number of nodes * na = number of arcs * large = a very large integer to represent infinity * (see note 3) * repeat = true if initialization is to be skipped * (false otherwise) * crash = 0 if default initialization is used * 1 if auction initialization is used * startn[j] = starting node for arc j, j = 1,...,na * endn[j] = ending node for arc j, j = 1,...,na * fou[i] = first arc out of node i, i = 1,...,n * nxtou[j] = next arc out of the starting node of arc j, j = 1,...,na * fin[i] = first arc into node i, i = 1,...,n * nxtin[j] = next arc into the ending node of arc j, j = 1,...,na * * UPDATED PARAMETERS (see notes 1, 3, 4) * * rc[j] = reduced cost of arc j, j = 1,...,na * u[j] = capacity of arc j on input * and (capacity of arc j) - x[j] on output, j = 1,...,na * dfct[i] = demand at node i on input * and zero on output, i = 1,...,n * * OUTPUT PARAMETERS (see notes 1, 3, 4) * * x[j] = flow on arc j, j = 1,...,na * nmultinode = number of multinode relaxation iterations in RELAX4 * iter = number of relaxation iterations in RELAX4 * num_augm = number of flow augmentation steps in RELAX4 * num_ascnt = number of multinode ascent steps in RELAX4 * nsp = number of auction/shortest path iterations * * WORKING PARAMETERS (see notes 1, 4, 5) * * label[1+n], prdcsr[1+n], save[1+na], tfstou[1+n], tnxtou[1+na], * tfstin[1+n], tnxtin[1+na], nxtqueue[1+n], scan[1+n], mark[1+n], * extend_arc[1+n], sb_level[1+n], sb_arc[1+n] * * RETURNS * * 0 = normal return * 1,...,8 = problem is found to be infeasible * * NOTE 1 * * To run in limited memory systems, declare the arrays startn, endn, * nxtin, nxtou, fin, fou, label, prdcsr, save, tfstou, tnxtou, tfstin, * tnxtin, ddpos, ddneg, nxtqueue as short instead. * * NOTE 2 * * This routine makes no effort to initialize with a favorable x from * amongst those flow vectors that satisfy complementary slackness with * the initial reduced cost vector rc. If a favorable x is known, then * it can be passed, together with the corresponding arrays u and dfct, * to this routine directly. This, however, requires that the capacity * tightening portion and the flow initialization portion of this * routine (up to line labeled 90) be skipped. * * NOTE 3 * * All problem data should be less than large in magnitude, and large * should be less than, say, 1/4 the largest int of the machine used. * This will guard primarily against overflow in uncapacitated problems * where the arc capacities are taken finite but very large. Note, * however, that as in all codes operating with integers, overflow may * occur if some of the problem data takes very large values. * * NOTE 4 * * [This note being specific to Fortran was removed.-A.M.] * * NOTE 5 * * ddpos and ddneg are arrays that give the directional derivatives for * all positive and negative single-node price changes. These are used * only in phase II of the initialization procedure, before the linked * list of balanced arcs comes to play. Therefore, to reduce storage, * they are equivalence to tfstou and tfstin, which are of the same size * (number of nodes) and are used only after the tree comes into use. */ static void ascnt1(struct relax4_csa *csa, int dm, int *delx, int *nlabel, int *feasbl, int *svitch, int nscan, int curnode, int *prevnode); static void ascnt2(struct relax4_csa *csa, int dm, int *delx, int *nlabel, int *feasbl, int *svitch, int nscan, int curnode, int *prevnode); static int auction(struct relax4_csa *csa); int relax4(struct relax4_csa *csa) { /* input parameters */ int n = csa->n; int na = csa->na; int large = csa->large; int repeat = csa->repeat; int crash = csa->crash; int *startn = csa->startn; int *endn = csa->endn; int *fou = csa->fou; int *nxtou = csa->nxtou; int *fin = csa->fin; int *nxtin = csa->nxtin; /* updated parameters */ int *rc = csa->rc; int *u = csa->u; int *dfct = csa->dfct; /* output parameters */ int *x = csa->x; # define nmultinode (csa->nmultinode) # define iter (csa->iter) # define num_augm (csa->num_augm) # define num_ascnt (csa->num_ascnt) # define nsp (csa->nsp) /* working parameters */ int *label = csa->label; int *prdcsr = csa->prdcsr; int *save = csa->save; int *tfstou = csa->tfstou; int *tnxtou = csa->tnxtou; int *tfstin = csa->tfstin; int *tnxtin = csa->tnxtin; int *nxtqueue = csa->nxtqueue; char *scan = csa->scan; char *mark = csa->mark; int *ddpos = tfstou; int *ddneg = tfstin; /* local variables */ int arc, augnod, capin, capout, defcit, delprc, delx, dm, dp, dx, feasbl, i, ib, indef, j, lastqueue, maxcap, narc, nb, nlabel, node, node2, node_def, naugnod, nscan, num_passes, numnz, numnz_new, numpasses, nxtarc, nxtbrk, nxtnode, passes, pchange, posit, prevnode, prvarc, quit, rdcost, scapin, scapou, svitch, t, t1, t2, tmparc, tp, trc, ts; /*--------------------------------------------------------------*/ /* Initialization phase I */ /* In this phase, we reduce the arc capacities by as much as * possible without changing the problem; then we set the initial * flow array x, together with the corresponding arrays u and * dfct. */ /* This phase and phase II (from here up to line labeled 90) can * be skipped (by setting repeat to true) if the calling program * places in common user-chosen values for the arc flows, the * residual arc capacities, and the nodal deficits. When this is * done, it is critical that the flow and the reduced cost for * each arc satisfy complementary slackness and the dfct array * properly correspond to the initial arc/flows. */ if (repeat) goto L90; for (node = 1; node <= n; node++) { node_def = dfct[node]; ddpos[node] = node_def; ddneg[node] = -node_def; maxcap = 0; scapou = 0; for (arc = fou[node]; arc > 0; arc = nxtou[arc]) { if (scapou <= large - u[arc]) scapou += u[arc]; else goto L10; } if (scapou <= large - node_def) capout = scapou + node_def; else goto L10; if (capout < 0) { /* problem is infeasible */ /* exogenous flow into node exceeds out capacity */ return 1; } scapin = 0; for (arc = fin[node]; arc > 0; arc = nxtin[arc]) { if (u[arc] > capout) u[arc] = capout; if (maxcap < u[arc]) maxcap = u[arc]; if (scapin <= large - u[arc]) scapin += u[arc]; else goto L10; } if (scapin <= large + node_def) capin = scapin - node_def; else goto L10; if (capin < 0) { /* problem is infeasible */ /* exogenous flow out of node exceeds in capacity */ return 2; } for (arc = fou[node]; arc > 0; arc = nxtou[arc]) { if (u[arc] > capin) u[arc] = capin; } L10: ; } /*--------------------------------------------------------------*/ /* Initialization phase II */ /* In this phase, we initialize the prices and flows by either * calling the routine auction or by performing only single node * (coordinate) relaxation iterations. */ if (crash == 1) { nsp = 0; if (auction(csa) != 0) { /* problem is found to be infeasible */ return 3; } goto L70; } /* Initialize the arc flows to satisfy complementary slackness * with the prices. u[arc] is the residual capacity of arc, and * x[arc] is the flow. These two always add up to the total * capacity for arc. Also compute the directional derivatives for * each coordinate and compute the actual deficits. */ for (arc = 1; arc <= na; arc++) { x[arc] = 0; if (rc[arc] <= 0) { t = u[arc]; t1 = startn[arc]; t2 = endn[arc]; ddpos[t1] += t; ddneg[t2] += t; if (rc[arc] < 0) { x[arc] = t; u[arc] = 0; dfct[t1] += t; dfct[t2] -= t; ddneg[t1] -= t; ddpos[t2] -= t; } } } /* Make 2 or 3 passes through all nodes, performing only single * node relaxation iterations. The number of passes depends on the * density of the network. */ if (na > n * 10) numpasses = 2; else numpasses = 3; for (passes = 1; passes <= numpasses; passes++) for (node = 1; node <= n; node++) { if (dfct[node] == 0) continue; if (ddpos[node] <= 0) { /* Compute delprc, the stepsize to the next breakpoint in * the dual cost as the price of node is increased. * [Since the reduced cost of all outgoing (resp., incoming) * arcs will decrease (resp., increase) as the price of node * is increased, the next breakpoint is the minimum of the * positive reduced cost on outgoing arcs and of the * negative reduced cost on incoming arcs.] */ delprc = large; for (arc = fou[node]; arc > 0; arc = nxtou[arc]) { trc = rc[arc]; if ((trc > 0) && (trc < delprc)) delprc = trc; } for (arc = fin[node]; arc > 0; arc = nxtin[arc]) { trc = rc[arc]; if ((trc < 0) && (trc > -delprc)) delprc = -trc; } /* If no breakpoint is left and dual ascent is still * possible, the problem is infeasible. */ if (delprc >= large) { if (ddpos[node] == 0) continue; return 4; } /* delprc is the stepsize to next breakpoint. Increase * price of node by delprc and compute the stepsize to the * next breakpoint in the dual cost. */ L53: nxtbrk = large; /* Look at all arcs out of node. */ for (arc = fou[node]; arc > 0; arc = nxtou[arc]) { trc = rc[arc]; if (trc == 0) { t1 = endn[arc]; t = u[arc]; if (t > 0) { dfct[node] += t; dfct[t1] -= t; x[arc] = t; u[arc] = 0; } else t = x[arc]; ddneg[node] -= t; ddpos[t1] -= t; } /* Decrease the reduced costs on all outgoing arcs. */ trc -= delprc; if ((trc > 0) && (trc < nxtbrk)) nxtbrk = trc; else if (trc == 0) { /* Arc goes from inactive to balanced. Update the rate * of dual ascent at node and at its neighbor. */ ddpos[node] += u[arc]; ddneg[endn[arc]] += u[arc]; } rc[arc] = trc; } /* Look at all arcs into node. */ for (arc = fin[node]; arc > 0; arc = nxtin[arc]) { trc = rc[arc]; if (trc == 0) { t1 = startn[arc]; t = x[arc]; if (t > 0) { dfct[node] += t; dfct[t1] -= t; u[arc] = t; x[arc] = 0; } else t = u[arc]; ddpos[t1] -= t; ddneg[node] -= t; } /* Increase the reduced cost on all incoming arcs. */ trc += delprc; if ((trc < 0) && (trc > -nxtbrk)) nxtbrk = -trc; else if (trc == 0) { /* Arc goes from active to balanced. Update the rate * of dual ascent at node and at its neighbor. */ ddneg[startn[arc]] += x[arc]; ddpos[node] += x[arc]; } rc[arc] = trc; } /* If price of node can be increased further without * decreasing the dual cost (even the dual cost doesn't * increase), return to increase the price further. */ if ((ddpos[node] <= 0) && (nxtbrk < large)) { delprc = nxtbrk; goto L53; } } else if (ddneg[node] <= 0) { /* Compute delprc, the stepsize to the next breakpoint in * the dual cost as the price of node is decreased. * [Since the reduced cost of all outgoing (resp., incoming) * arcs will increase (resp., decrease) as the price of node * is decreased, the next breakpoint is the minimum of the * negative reduced cost on outgoing arcs and of the * positive reduced cost on incoming arcs.] */ delprc = large; for (arc = fou[node]; arc > 0; arc = nxtou[arc]) { trc = rc[arc]; if ((trc < 0) && (trc > -delprc)) delprc = -trc; } for (arc = fin[node]; arc > 0; arc = nxtin[arc]) { trc = rc[arc]; if ((trc > 0) && (trc < delprc)) delprc = trc; } /* If no breakpoint is left and dual ascent is still * possible, the problem is infeasible. */ if (delprc == large) { if (ddneg[node] == 0) continue; return 5; } /* delprc is the stepsize to next breakpoint. Decrease * price of node by delprc and compute the stepsize to the * next breakpoint in the dual cost. */ L63: nxtbrk = large; /* Look at all arcs out of node. */ for (arc = fou[node]; arc > 0; arc = nxtou[arc]) { trc = rc[arc]; if (trc == 0) { t1 = endn[arc]; t = x[arc]; if (t > 0) { dfct[node] -= t; dfct[t1] += t; u[arc] = t; x[arc] = 0; } else t = u[arc]; ddpos[node] -= t; ddneg[t1] -= t; } /* Increase the reduced cost on all outgoing arcs. */ trc += delprc; if ((trc < 0) && (trc > -nxtbrk)) nxtbrk = -trc; else if (trc == 0) { /* Arc goes from active to balanced. Update the rate * of dual ascent at node and at its neighbor. */ ddneg[node] += x[arc]; ddpos[endn[arc]] += x[arc]; } rc[arc] = trc; } /* Look at all arcs into node. */ for (arc = fin[node]; arc > 0; arc = nxtin[arc]) { trc = rc[arc]; if (trc == 0) { t1 = startn[arc]; t = u[arc]; if (t > 0) { dfct[node] -= t; dfct[t1] += t; x[arc] = t; u[arc] = 0; } else t = x[arc]; ddneg[t1] -= t; ddpos[node] -= t; } /* Decrease the reduced cost on all incoming arcs. */ trc -= delprc; if ((trc > 0) && (trc < nxtbrk)) nxtbrk = trc; else if (trc == 0) { /* Arc goes from inactive to balanced. Update the rate * of dual ascent at node and at its neighbor. */ ddpos[startn[arc]] += u[arc]; ddneg[node] += u[arc]; } rc[arc] = trc; } /* If price of node can be decreased further without * decreasing the dual cost (even the dual cost doesn't * increase), return to decrease the price further. */ if ((ddneg[node] <= 0) && (nxtbrk < large)) { delprc = nxtbrk; goto L63; } } } /*--------------------------------------------------------------*/ L70: /* Initialize tree data structure. */ for (i = 1; i <= n; i++) tfstou[i] = tfstin[i] = 0; for (i = 1; i <= na; i++) { tnxtin[i] = tnxtou[i] = -1; if (rc[i] == 0) { tnxtou[i] = tfstou[startn[i]]; tfstou[startn[i]] = i; tnxtin[i] = tfstin[endn[i]]; tfstin[endn[i]] = i; } } L90: /* Initialize other variables. */ feasbl = true; iter = 0; nmultinode = 0; num_augm = 0; num_ascnt = 0; num_passes = 0; numnz = n; numnz_new = 0; svitch = false; for (i = 1; i <= n; i++) mark[i] = scan[i] = false; nlabel = 0; /* RELAX4 uses an adaptive strategy to decide whether to continue * the scanning process after a multinode price change. * The threshold parameter tp and ts that control this strategy * are set in the next two lines. */ tp = 10; ts = n / 15; /* Initialize the queue of nodes with nonzero deficit. */ for (node = 1; node <= n - 1; node++) nxtqueue[node] = node + 1; nxtqueue[n] = 1; node = lastqueue = n; /*--------------------------------------------------------------*/ /* Start the relaxation algorithm. */ L100: /* Code for advancing the queue of nonzero deficit nodes. */ prevnode = node; node = nxtqueue[node]; defcit = dfct[node]; if (node == lastqueue) { numnz = numnz_new; numnz_new = 0; lastqueue = prevnode; num_passes++; } /* Code for deleting a node from the queue. */ if (defcit == 0) { nxtnode = nxtqueue[node]; if (node == nxtnode) return 0; else { nxtqueue[prevnode] = nxtnode; nxtqueue[node] = 0; node = nxtnode; goto L100; } } else posit = (defcit > 0); iter++; numnz_new++; if (posit) { /* Attempt a single node iteration from node with positive * deficit. */ pchange = false; indef = defcit; delx = 0; nb = 0; /* Check outgoing (probably) balanced arcs from node. */ for (arc = tfstou[node]; arc > 0; arc = tnxtou[arc]) { if ((rc[arc] == 0) && (x[arc] > 0)) { delx += x[arc]; nb++; save[nb] = arc; } } /* Check incoming arcs. */ for (arc = tfstin[node]; arc > 0; arc = tnxtin[arc]) { if ((rc[arc] == 0) && (u[arc] > 0)) { delx += u[arc]; nb++; save[nb] = -arc; } } /* End of initial node scan. */ L4018: /* If no price change is possible, exit. */ if (delx > defcit) { quit = (defcit < indef); goto L4016; } /* RELAX4 searches along the ascent direction for the best * price by checking the slope of the dual cost at successive * break points. First, we compute the distance to the next * break point. */ delprc = large; for (arc = fou[node]; arc > 0; arc = nxtou[arc]) { rdcost = rc[arc]; if ((rdcost < 0) && (rdcost > -delprc)) delprc = -rdcost; } for (arc = fin[node]; arc > 0; arc = nxtin[arc]) { rdcost = rc[arc]; if ((rdcost > 0) && (rdcost < delprc)) delprc = rdcost; } /* Check if problem is infeasible. */ if ((delx < defcit) && (delprc == large)) { /* The dual cost can be decreased without bound. */ return 6; } /* Skip flow adjustment if there is no flow to modify. */ if (delx == 0) goto L4014; /* Adjust the flow on the balanced arcs incident to node to * maintain complementary slackness after the price change. */ for (j = 1; j <= nb; j++) { arc = save[j]; if (arc > 0) { node2 = endn[arc]; t1 = x[arc]; dfct[node2] += t1; if (nxtqueue[node2] == 0) { nxtqueue[prevnode] = node2; nxtqueue[node2] = node; prevnode = node2; } u[arc] += t1; x[arc] = 0; } else { narc = -arc; node2 = startn[narc]; t1 = u[narc]; dfct[node2] += t1; if (nxtqueue[node2] == 0) { nxtqueue[prevnode] = node2; nxtqueue[node2] = node; prevnode = node2; } x[narc] += t1; u[narc] = 0; } } defcit -= delx; L4014: if (delprc == large) { quit = true; goto L4019; } /* Node corresponds to a dual ascent direction. Decrease the * price of node by delprc and compute the stepsize to the next * breakpoint in the dual cost. */ nb = 0; pchange = true; dp = delprc; delprc = large; delx = 0; for (arc = fou[node]; arc > 0; arc = nxtou[arc]) { rdcost = rc[arc] + dp; rc[arc] = rdcost; if (rdcost == 0) { nb++; save[nb] = arc; delx += x[arc]; } if ((rdcost < 0) && (rdcost > -delprc)) delprc = -rdcost; } for (arc = fin[node]; arc > 0; arc = nxtin[arc]) { rdcost = rc[arc] - dp; rc[arc] = rdcost; if (rdcost == 0) { nb++; save[nb] = -arc; delx += u[arc]; } if ((rdcost > 0) && (rdcost < delprc)) delprc = rdcost; } /* Return to check if another price change is possible. */ goto L4018; L4016: /* Perform flow augmentation at node. */ for (j = 1; j <= nb; j++) { arc = save[j]; if (arc > 0) { /* arc is an outgoing arc from node. */ node2 = endn[arc]; t1 = dfct[node2]; if (t1 < 0) { /* Decrease the total deficit by decreasing flow of * arc. */ quit = true; t2 = x[arc]; dx = defcit; if (dx > -t1) dx = -t1; if (dx > t2) dx = t2; defcit -= dx; dfct[node2] = t1 + dx; if (nxtqueue[node2] == 0) { nxtqueue[prevnode] = node2; nxtqueue[node2] = node; prevnode = node2; } x[arc] = t2 - dx; u[arc] += dx; if (defcit == 0) break; } } else { /* -arc is an incoming arc to node. */ narc = -arc; node2 = startn[narc]; t1 = dfct[node2]; if (t1 < 0) { /* Decrease the total deficit by increasing flow of * -arc. */ quit = true; t2 = u[narc]; dx = defcit; if (dx > -t1) dx = -t1; if (dx > t2) dx = t2; defcit -= dx; dfct[node2] = t1 + dx; if (nxtqueue[node2] == 0) { nxtqueue[prevnode] = node2; nxtqueue[node2] = node; prevnode = node2; } x[narc] += dx; u[narc] = t2 - dx; if (defcit == 0) break; } } } L4019: dfct[node] = defcit; /* Reconstruct the linked list of balance arcs incident to this * node. For each adjacent node, we add any newly balanced arcs * to the list, but do not bother removing formerly balanced * ones (they will be removed the next time each adjacent node * is scanned). */ if (pchange) { arc = tfstou[node]; tfstou[node] = 0; while (arc > 0) { nxtarc = tnxtou[arc]; tnxtou[arc] = -1; arc = nxtarc; } arc = tfstin[node]; tfstin[node] = 0; while (arc > 0) { nxtarc = tnxtin[arc]; tnxtin[arc] = -1; arc = nxtarc; } /* Now add the currently balanced arcs to the list for this * node (which is now empty), and the appropriate adjacent * ones. */ for (j = 1; j <= nb; j++) { arc = save[j]; if (arc < 0) arc = -arc; if (tnxtou[arc] < 0) { tnxtou[arc] = tfstou[startn[arc]]; tfstou[startn[arc]] = arc; } if (tnxtin[arc] < 0) { tnxtin[arc] = tfstin[endn[arc]]; tfstin[endn[arc]] = arc; } } } /* End of single node iteration for positive deficit node. */ } else { /* Attempt a single node iteration from node with negative * deficit. */ pchange = false; defcit = -defcit; indef = defcit; delx = 0; nb = 0; for (arc = tfstin[node]; arc > 0; arc = tnxtin[arc]) { if ((rc[arc] == 0) && (x[arc] > 0)) { delx += x[arc]; nb++; save[nb] = arc; } } for (arc = tfstou[node]; arc > 0; arc = tnxtou[arc]) { if ((rc[arc] == 0) && (u[arc] > 0)) { delx += u[arc]; nb++; save[nb] = -arc; } } L4028: if (delx >= defcit) { quit = (defcit < indef); goto L4026; } /* Compute distance to next breakpoint. */ delprc = large; for (arc = fin[node]; arc > 0; arc = nxtin[arc]) { rdcost = rc[arc]; if ((rdcost < 0) && (rdcost > -delprc)) delprc = -rdcost; } for (arc = fou[node]; arc > 0; arc = nxtou[arc]) { rdcost = rc[arc]; if ((rdcost > 0) && (rdcost < delprc)) delprc = rdcost; } /* Check if problem is infeasible. */ if ((delx < defcit) && (delprc == large)) return 7; if (delx == 0) goto L4024; /* Flow augmentation is possible. */ for (j = 1; j <= nb; j++) { arc = save[j]; if (arc > 0) { node2 = startn[arc]; t1 = x[arc]; dfct[node2] -= t1; if (nxtqueue[node2] == 0) { nxtqueue[prevnode] = node2; nxtqueue[node2] = node; prevnode = node2; } u[arc] += t1; x[arc] = 0; } else { narc = -arc; node2 = endn[narc]; t1 = u[narc]; dfct[node2] -= t1; if (nxtqueue[node2] == 0) { nxtqueue[prevnode] = node2; nxtqueue[node2] = node; prevnode = node2; } x[narc] += t1; u[narc] = 0; } } defcit -= delx; L4024: if (delprc == large) { quit = true; goto L4029; } /* Price increase at node is possible. */ nb = 0; pchange = true; dp = delprc; delprc = large; delx = 0; for (arc = fin[node]; arc > 0; arc = nxtin[arc]) { rdcost = rc[arc] + dp; rc[arc] = rdcost; if (rdcost == 0) { nb++; save[nb] = arc; delx += x[arc]; } if ((rdcost < 0) && (rdcost > -delprc)) delprc = -rdcost; } for (arc = fou[node]; arc > 0; arc = nxtou[arc]) { rdcost = rc[arc] - dp; rc[arc] = rdcost; if (rdcost == 0) { nb++; save[nb] = -arc; delx += u[arc]; } if ((rdcost > 0) && (rdcost < delprc)) delprc = rdcost; } goto L4028; L4026: /* Perform flow augmentation at node. */ for (j = 1; j <= nb; j++) { arc = save[j]; if (arc > 0) { /* arc is an incoming arc to node. */ node2 = startn[arc]; t1 = dfct[node2]; if (t1 > 0) { quit = true; t2 = x[arc]; dx = defcit; if (dx > t1) dx = t1; if (dx > t2) dx = t2; defcit -= dx; dfct[node2] = t1 - dx; if (nxtqueue[node2] == 0) { nxtqueue[prevnode] = node2; nxtqueue[node2] = node; prevnode = node2; } x[arc] = t2 - dx; u[arc] += dx; if (defcit == 0) break; } } else { /* -arc is an outgoing arc from node. */ narc = -arc; node2 = endn[narc]; t1 = dfct[node2]; if (t1 > 0) { quit = true; t2 = u[narc]; dx = defcit; if (dx > t1) dx = t1; if (dx > t2) dx = t2; defcit -= dx; dfct[node2] = t1 - dx; if (nxtqueue[node2] == 0) { nxtqueue[prevnode] = node2; nxtqueue[node2] = node; prevnode = node2; } x[narc] += dx; u[narc] = t2 - dx; if (defcit == 0) break; } } } L4029: dfct[node] = -defcit; /* Reconstruct the list of balanced arcs incident to node. */ if (pchange) { arc = tfstou[node]; tfstou[node] = 0; while (arc > 0) { nxtarc = tnxtou[arc]; tnxtou[arc] = -1; arc = nxtarc; } arc = tfstin[node]; tfstin[node] = 0; while (arc > 0) { nxtarc = tnxtin[arc]; tnxtin[arc] = -1; arc = nxtarc; } /* Now add the currently balanced arcs to the list for this * node (which is now empty), and the appropriate adjacent * ones. */ for (j = 1; j <= nb; j++) { arc = save[j]; if (arc <= 0) arc = -arc; if (tnxtou[arc] < 0) { tnxtou[arc] = tfstou[startn[arc]]; tfstou[startn[arc]] = arc; } if (tnxtin[arc] < 0) { tnxtin[arc] = tfstin[endn[arc]]; tfstin[endn[arc]] = arc; } } } /* End of single node iteration for a negative deficit node. */ } if (quit || (num_passes <= 3)) goto L100; /* Do a multinode iteration from node. */ nmultinode++; /* If number of nonzero deficit nodes is small, continue labeling * until a flow augmentation is done. */ svitch = (numnz < tp); /* Unmark nodes labeled earlier. */ for (j = 1; j <= nlabel; j++) { node2 = label[j]; mark[node2] = scan[node2] = false; } /* Initialize labeling. */ nlabel = 1; label[1] = node; mark[node] = true; prdcsr[node] = 0; /* Scan starting node. */ scan[node] = true; nscan = 1; dm = dfct[node]; delx = 0; for (j = 1; j <= nb; j++) { arc = save[j]; if (arc > 0) { if (posit) node2 = endn[arc]; else node2 = startn[arc]; if (!mark[node2]) { nlabel++; label[nlabel] = node2; prdcsr[node2] = arc; mark[node2] = true; delx += x[arc]; } } else { narc = -arc; if (posit) node2 = startn[narc]; else node2 = endn[narc]; if (!mark[node2]) { nlabel++; label[nlabel] = node2; prdcsr[node2] = arc; mark[node2] = true; delx += u[narc]; } } } L4120:/* Start scanning a labeled but unscanned node. */ nscan++; /* Check to see if switch needs to be set to true so to continue * scanning even after a price change. */ svitch = svitch || ((nscan > ts) && (numnz < ts)); /* Scanning will continue until either an overestimate of the * residual capacity across the cut corresponding to the scanned * set of nodes (called delx) exceeds the absolute value of the * total deficit of the scanned nodes (called dm), or else an * augmenting path is found. Arcs that are in the tree but are not * balanced are removed as part of the scanning process. */ i = label[nscan]; scan[i] = true; naugnod = 0; if (posit) { /* Scanning node i in case of positive deficit. */ prvarc = 0; arc = tfstou[i]; while (arc > 0) { /* arc is an outgoing arc from node. */ if (rc[arc] == 0) { if (x[arc] > 0) { node2 = endn[arc]; if (!mark[node2]) { /* node2 is not labeled, so add node2 to the labeled set. */ prdcsr[node2] = arc; if (dfct[node2] < 0) { naugnod++; save[naugnod] = node2; } nlabel++; label[nlabel] = node2; mark[node2] = true; delx += x[arc]; } } prvarc = arc; arc = tnxtou[arc]; } else { tmparc = arc; arc = tnxtou[arc]; tnxtou[tmparc] = -1; if (prvarc == 0) tfstou[i] = arc; else tnxtou[prvarc] = arc; } } prvarc = 0; arc = tfstin[i]; while (arc > 0) { /* arc is an incoming arc into node. */ if (rc[arc] == 0) { if (u[arc] > 0) { node2 = startn[arc]; if (!mark[node2]) { /* node2 is not labeled, so add node2 to the * labeled set. */ prdcsr[node2] = -arc; if (dfct[node2] < 0) { naugnod++; save[naugnod] = node2; } nlabel++; label[nlabel] = node2; mark[node2] = true; delx += u[arc]; } } prvarc = arc; arc = tnxtin[arc]; } else { tmparc = arc; arc = tnxtin[arc]; tnxtin[tmparc] = -1; if (prvarc == 0) tfstin[i] = arc; else tnxtin[prvarc] = arc; } } /* Correct the residual capacity of the scanned node cut. */ arc = prdcsr[i]; if (arc > 0) delx -= x[arc]; else delx -= u[-arc]; /* End of scanning of node i for positive deficit case. */ } else { /* Scanning node i for negative deficit case. */ prvarc = 0; arc = tfstin[i]; while (arc > 0) { if (rc[arc] == 0) { if (x[arc] > 0) { node2 = startn[arc]; if (!mark[node2]) { prdcsr[node2] = arc; if (dfct[node2] > 0) { naugnod++; save[naugnod] = node2; } nlabel++; label[nlabel] = node2; mark[node2] = true; delx += x[arc]; } } prvarc = arc; arc = tnxtin[arc]; } else { tmparc = arc; arc = tnxtin[arc]; tnxtin[tmparc] = -1; if (prvarc == 0) tfstin[i] = arc; else tnxtin[prvarc] = arc; } } prvarc = 0; arc = tfstou[i]; while (arc > 0) { if (rc[arc] == 0) { if (u[arc] > 0) { node2 = endn[arc]; if (!mark[node2]) { prdcsr[node2] = -arc; if (dfct[node2] > 0) { naugnod++; save[naugnod] = node2; } nlabel++; label[nlabel] = node2; mark[node2] = true; delx += u[arc]; } } prvarc = arc; arc = tnxtou[arc]; } else { tmparc = arc; arc = tnxtou[arc]; tnxtou[tmparc] = -1; if (prvarc == 0) tfstou[i] = arc; else tnxtou[prvarc] = arc; } } arc = prdcsr[i]; if (arc > 0) delx -= x[arc]; else delx -= u[-arc]; } /* Add deficit of node scanned to dm. */ dm += dfct[i]; /* Check if the set of scanned nodes correspond to a dual ascent * direction; if yes, perform a price adjustment step, otherwise * continue labeling. */ if (nscan < nlabel) { if (svitch) goto L4210; if ((delx >= dm) && (delx >= -dm)) goto L4210; } /* Try a price change. * [Note that since delx - abs(dm) is an overestimate of ascent * slope, we may occasionally try a direction that is not an * ascent direction. In this case the ascnt routines return with * quit = false, so we continue labeling nodes.] */ if (posit) { ascnt1(csa, dm, &delx, &nlabel, &feasbl, &svitch, nscan, node, &prevnode); num_ascnt++; } else { ascnt2(csa, dm, &delx, &nlabel, &feasbl, &svitch, nscan, node, &prevnode); num_ascnt++; } if (!feasbl) return 8; if (!svitch) goto L100; /* Store those newly labeled nodes to which flow augmentation is * possible. */ naugnod = 0; for (j = nscan + 1; j <= nlabel; j++) { node2 = label[j]; if (posit && (dfct[node2] < 0)) { naugnod++; save[naugnod] = node2; } else if ((!posit) && (dfct[node2] > 0)) { naugnod++; save[naugnod] = node2; } } L4210:/* Check if flow augmentation is possible. If not, return to scan * another node. */ if (naugnod == 0) goto L4120; for (j = 1; j <= naugnod; j++) { num_augm++; augnod = save[j]; if (posit) { /* Do the augmentation from node with positive deficit. */ dx = -dfct[augnod]; ib = augnod; while (ib != node) { arc = prdcsr[ib]; if (arc > 0) { if (dx > x[arc]) dx = x[arc]; ib = startn[arc]; } else { if (dx > u[-arc]) dx = u[-arc]; ib = endn[-arc]; } } if (dx > dfct[node]) dx = dfct[node]; if (dx > 0) { /* Increase (decrease) the flow of all forward (backward) * arcs in the flow augmenting path. Adjust node deficit * accordingly. */ if (nxtqueue[augnod] == 0) { nxtqueue[prevnode] = augnod; nxtqueue[augnod] = node; prevnode = augnod; } dfct[augnod] += dx; dfct[node] -= dx; ib = augnod; while (ib != node) { arc = prdcsr[ib]; if (arc > 0) { x[arc] -= dx; u[arc] += dx; ib = startn[arc]; } else { narc = -arc; x[narc] += dx; u[narc] -= dx; ib = endn[narc]; } } } } else { /* Do the augmentation from node with negative deficit. */ dx = dfct[augnod]; ib = augnod; while (ib != node) { arc = prdcsr[ib]; if (arc > 0) { if (dx > x[arc]) dx = x[arc]; ib = endn[arc]; } else { if (dx > u[-arc]) dx = u[-arc]; ib = startn[-arc]; } } if (dx > -dfct[node]) dx = -dfct[node]; if (dx > 0) { /* Update the flow and deficits. */ if (nxtqueue[augnod] == 0) { nxtqueue[prevnode] = augnod; nxtqueue[augnod] = node; prevnode = augnod; } dfct[augnod] -= dx; dfct[node] += dx; ib = augnod; while (ib != node) { arc = prdcsr[ib]; if (arc > 0) { x[arc] -= dx; u[arc] += dx; ib = endn[arc]; } else { narc = -arc; x[narc] += dx; u[narc] -= dx; ib = startn[narc]; } } } } if (dfct[node] == 0) goto L100; if (dfct[augnod] != 0) svitch = false; } /* If node still has nonzero deficit and all newly labeled nodes * have same sign for their deficit as node, we can continue * labeling. In this case, continue labeling only when flow * augmentation is done relatively infrequently. */ if (svitch && (iter > 8 * num_augm)) goto L4120; /* Return to do another relaxation iteration. */ goto L100; # undef nmultinode # undef iter # undef num_augm # undef num_ascnt # undef nsp } /*********************************************************************** * NAME * * relax4_inidat - construct linked lists for network topology * * PURPOSE * * This routine constructs two linked lists for the network topology: * one list (given by fou, nxtou) for the outgoing arcs of nodes and * one list (given by fin, nxtin) for the incoming arcs of nodes. These * two lists are required by RELAX4. * * INPUT PARAMETERS * * n = number of nodes * na = number of arcs * startn[j] = starting node for arc j, j = 1,...,na * endn[j] = ending node for arc j, j = 1,...,na * * OUTPUT PARAMETERS * * fou[i] = first arc out of node i, i = 1,...,n * nxtou[j] = next arc out of the starting node of arc j, j = 1,...,na * fin[i] = first arc into node i, i = 1,...,n * nxtin[j] = next arc into the ending node of arc j, j = 1,...,na * * WORKING PARAMETERS * * tempin[1+n], tempou[1+n] */ void relax4_inidat(struct relax4_csa *csa) { /* input parameters */ int n = csa->n; int na = csa->na; int *startn = csa->startn; int *endn = csa->endn; /* output parameters */ int *fou = csa->fou; int *nxtou = csa->nxtou; int *fin = csa->fin; int *nxtin = csa->nxtin; /* working parameters */ int *tempin = csa->label; int *tempou = csa->prdcsr; /* local variables */ int i, i1, i2; for (i = 1; i <= n; i++) { fin[i] = fou[i] = 0; tempin[i] = tempou[i] = 0; } for (i = 1; i <= na; i++) { nxtin[i] = nxtou[i] = 0; i1 = startn[i]; i2 = endn[i]; if (fou[i1] != 0) nxtou[tempou[i1]] = i; else fou[i1] = i; tempou[i1] = i; if (fin[i2] != 0) nxtin[tempin[i2]] = i; else fin[i2] = i; tempin[i2] = i; } return; } /*********************************************************************** * NAME * * ascnt1 - multi-node price adjustment for positive deficit case * * PURPOSE * * This subroutine performs the multi-node price adjustment step for * the case where the scanned nodes have positive deficit. It first * checks if decreasing the price of the scanned nodes increases the * dual cost. If yes, then it decreases the price of all scanned nodes. * There are two possibilities for price decrease: if switch = true, * then the set of scanned nodes corresponds to an elementary direction * of maximal rate of ascent, in which case the price of all scanned * nodes are decreased until the next breakpoint in the dual cost is * encountered. At this point, some arc becomes balanced and more * node(s) are added to the labeled set and the subroutine is exited. * If switch = false, then the price of all scanned nodes are decreased * until the rate of ascent becomes negative (this corresponds to the * price adjustment step in which both the line search and the * degenerate ascent iteration are implemented). * * INPUT PARAMETERS * * dm = total deficit of scanned nodes * switch = true if labeling is to continue after price change * nscan = number of scanned nodes * curnode = most recently scanned node * n = number of nodes * na = number of arcs * large = a very large integer to represent infinity (see note 3) * startn[i] = starting node for the i-th arc, i = 1,...,na * endn[i] = ending node for the i-th arc, i = 1,...,na * fou[i] = first arc leaving i-th node, i = 1,...,n * nxtou[i] = next arc leaving the starting node of j-th arc, * i = 1,...,na * fin[i] = first arc entering i-th node, i = 1,...,n * nxtin[i] = next arc entering the ending node of j-th arc, * i = 1,...,na * * UPDATED PARAMETERS * * delx = a lower estimate of the total flow on balanced arcs in * the scanned-nodes cut * nlabel = number of labeled nodes * feasbl = false if problem is found to be infeasible * prevnode = the node before curnode in queue * rc[j] = reduced cost of arc j, j = 1,...,na * u[j] = residual capacity of arc j, j = 1,...,na * x[j] = flow on arc j, j = 1,...,na * dfct[i] = deficit at node i, i = 1,...,n * label[k] = k-th node labeled, k = 1,...,nlabel * prdcsr[i] = predecessor of node i in tree of labeled nodes (0 if i * is unlabeled), i = 1,...,n * tfstou[i] = first balanced arc out of node i, i = 1,...,n * tnxtou[j] = next balanced arc out of the starting node of arc j, * j = 1,...,na * tfstin[i] = first balanced arc into node i, i = 1,...,n * tnxtin[j] = next balanced arc into the ending node of arc j, * j = 1,...,na * nxtqueue[i] = node following node i in the fifo queue (0 if node is * not in the queue), i = 1,...,n * scan[i] = true if node i is scanned, i = 1,...,n * mark[i] = true if node i is labeled, i = 1,...,n * * WORKING PARAMETERS * * save[1+na] */ static void ascnt1(struct relax4_csa *csa, int dm, int *delx, int *nlabel, int *feasbl, int *svitch, int nscan, int curnode, int *prevnode) { /* input parameters */ int n = csa->n; /* int na = csa->na; */ int large = csa->large; int *startn = csa->startn; int *endn = csa->endn; int *fou = csa->fou; int *nxtou = csa->nxtou; int *fin = csa->fin; int *nxtin = csa->nxtin; /* updated parameters */ # define delx (*delx) # define nlabel (*nlabel) # define feasbl (*feasbl) # define svitch (*svitch) # define prevnode (*prevnode) int *rc = csa->rc; int *u = csa->u; int *x = csa->x; int *dfct = csa->dfct; int *label = csa->label; int *prdcsr = csa->prdcsr; int *tfstou = csa->tfstou; int *tnxtou = csa->tnxtou; int *tfstin = csa->tfstin; int *tnxtin = csa->tnxtin; int *nxtqueue = csa->nxtqueue; char *scan = csa->scan; char *mark = csa->mark; int *save = csa->save; /* local variables */ int arc, delprc, dlx, i, j, nb, node, node2, nsave, rdcost, t1, t2, t3; /* Store the arcs between the set of scanned nodes and its * complement in save and compute delprc, the stepsize to the next * breakpoint in the dual cost in the direction of decreasing * prices of the scanned nodes. * [The arcs are stored into save by looking at the arcs incident * to either the set of scanned nodes or its complement, depending * on whether nscan > n/2 or not. This improves the efficiency of * storing.] */ delprc = large; dlx = 0; nsave = 0; if (nscan <= n / 2) { for (i = 1; i <= nscan; i++) { node = label[i]; for (arc = fou[node]; arc > 0; arc = nxtou[arc]) { /* arc points from scanned node to an unscanned node. */ node2 = endn[arc]; if (!scan[node2]) { nsave++; save[nsave] = arc; rdcost = rc[arc]; if ((rdcost == 0) && (prdcsr[node2] != arc)) dlx += x[arc]; if ((rdcost < 0) && (rdcost > -delprc)) delprc = -rdcost; } } for (arc = fin[node]; arc > 0; arc = nxtin[arc]) { /* arc points from unscanned node to scanned node. */ node2 = startn[arc]; if (!scan[node2]) { nsave++; save[nsave] = -arc; rdcost = rc[arc]; if ((rdcost == 0) && (prdcsr[node2] != -arc)) dlx += u[arc]; if ((rdcost > 0) && (rdcost < delprc)) delprc = rdcost; } } } } else { for (node = 1; node <= n; node++) { if (scan[node]) continue; for (arc = fin[node]; arc > 0; arc = nxtin[arc]) { node2 = startn[arc]; if (scan[node2]) { nsave++; save[nsave] = arc; rdcost = rc[arc]; if ((rdcost == 0) && (prdcsr[node] != arc)) dlx += x[arc]; if ((rdcost < 0) && (rdcost > -delprc)) delprc = -rdcost; } } for (arc = fou[node]; arc > 0; arc = nxtou[arc]) { node2 = endn[arc]; if (scan[node2]) { nsave++; save[nsave] = -arc; rdcost = rc[arc]; if ((rdcost == 0) && (prdcsr[node] != -arc)) dlx += u[arc]; if ((rdcost > 0) && (rdcost < delprc)) delprc = rdcost; } } } } /* Check if the set of scanned nodes truly corresponds to a dual * ascent direction. [Here delx + dlx is the exact sum of the flow * on arcs from the scanned set to the unscanned set plus the * (capacity - flow) on arcs from the unscanned set to the scanned * set.] If this were not the case, set switch to true and exit * subroutine. */ if ((!svitch) && (delx + dlx >= dm)) { svitch = true; return; } delx += dlx; L4: /* Check that the problem is feasible. */ if (delprc == large) { /* We can increase the dual cost without bound, so the primal * problem is infeasible. */ feasbl = false; return; } /* Decrease the prices of the scanned nodes, add more nodes to * the labeled set and check if a newly labeled node has negative * deficit. */ if (svitch) { for (i = 1; i <= nsave; i++) { arc = save[i]; if (arc > 0) { rc[arc] += delprc; if (rc[arc] == 0) { node2 = endn[arc]; if (tnxtou[arc] < 0) { tnxtou[arc] = tfstou[startn[arc]]; tfstou[startn[arc]] = arc; } if (tnxtin[arc] < 0) { tnxtin[arc] = tfstin[node2]; tfstin[node2] = arc; } if (!mark[node2]) { prdcsr[node2] = arc; nlabel++; label[nlabel] = node2; mark[node2] = true; } } } else { arc = -arc; rc[arc] -= delprc; if (rc[arc] == 0) { node2 = startn[arc]; if (tnxtou[arc] < 0) { tnxtou[arc] = tfstou[node2]; tfstou[node2] = arc; } if (tnxtin[arc] < 0) { tnxtin[arc] = tfstin[endn[arc]]; tfstin[endn[arc]] = arc; } if (!mark[node2]) { prdcsr[node2] = -arc; nlabel++; label[nlabel] = node2; mark[node2] = true; } } } } return; } else { /* Decrease the prices of the scanned nodes by delprc. Adjust * flow to maintain complementary slackness with the prices. */ nb = 0; for (i = 1; i <= nsave; i++) { arc = save[i]; if (arc > 0) { t1 = rc[arc]; if (t1 == 0) { t2 = x[arc]; t3 = startn[arc]; dfct[t3] -= t2; if (nxtqueue[t3] == 0) { nxtqueue[prevnode] = t3; nxtqueue[t3] = curnode; prevnode = t3; } t3 = endn[arc]; dfct[t3] += t2; if (nxtqueue[t3] == 0) { nxtqueue[prevnode] = t3; nxtqueue[t3] = curnode; prevnode = t3; } u[arc] += t2; x[arc] = 0; } rc[arc] = t1 + delprc; #if 0 /* by mao; 26/IV-2013 */ if (rc[arc] == 0) #else if (rc[arc] == 0 && nb < n) #endif { delx += x[arc]; nb++; prdcsr[nb] = arc; } } else { arc = -arc; t1 = rc[arc]; if (t1 == 0) { t2 = u[arc]; t3 = startn[arc]; dfct[t3] += t2; if (nxtqueue[t3] == 0) { nxtqueue[prevnode] = t3; nxtqueue[t3] = curnode; prevnode = t3; } t3 = endn[arc]; dfct[t3] -= t2; if (nxtqueue[t3] == 0) { nxtqueue[prevnode] = t3; nxtqueue[t3] = curnode; prevnode = t3; } x[arc] += t2; u[arc] = 0; } rc[arc] = t1 - delprc; #if 0 /* by mao; 26/IV-2013 */ if (rc[arc] == 0) #else if (rc[arc] == 0 && nb < n) #endif { delx += u[arc]; nb++; prdcsr[nb] = arc; } } } } if (delx <= dm) { /* The set of scanned nodes still corresponds to a dual * (possibly degenerate) ascent direction. Compute the stepsize * delprc to the next breakpoint in the dual cost. */ delprc = large; for (i = 1; i <= nsave; i++) { arc = save[i]; if (arc > 0) { rdcost = rc[arc]; if ((rdcost < 0) && (rdcost > -delprc)) delprc = -rdcost; } else { arc = -arc; rdcost = rc[arc]; if ((rdcost > 0) && (rdcost < delprc)) delprc = rdcost; } } if ((delprc != large) || (delx < dm)) goto L4; } /* Add new balanced arcs to the superset of balanced arcs. */ for (i = 1; i <= nb; i++) { arc = prdcsr[i]; if (tnxtin[arc] == -1) { j = endn[arc]; tnxtin[arc] = tfstin[j]; tfstin[j] = arc; } if (tnxtou[arc] == -1) { j = startn[arc]; tnxtou[arc] = tfstou[j]; tfstou[j] = arc; } } return; # undef delx # undef nlabel # undef feasbl # undef svitch # undef prevnode } /*********************************************************************** * NAME * * ascnt2 - multi-node price adjustment for negative deficit case * * PURPOSE * * This routine is analogous to ascnt1 but for the case where the * scanned nodes have negative deficit. */ static void ascnt2(struct relax4_csa *csa, int dm, int *delx, int *nlabel, int *feasbl, int *svitch, int nscan, int curnode, int *prevnode) { /* input parameters */ int n = csa->n; /* int na = csa->na; */ int large = csa->large; int *startn = csa->startn; int *endn = csa->endn; int *fou = csa->fou; int *nxtou = csa->nxtou; int *fin = csa->fin; int *nxtin = csa->nxtin; /* updated parameters */ # define delx (*delx) # define nlabel (*nlabel) # define feasbl (*feasbl) # define svitch (*svitch) # define prevnode (*prevnode) int *rc = csa->rc; int *u = csa->u; int *x = csa->x; int *dfct = csa->dfct; int *label = csa->label; int *prdcsr = csa->prdcsr; int *tfstou = csa->tfstou; int *tnxtou = csa->tnxtou; int *tfstin = csa->tfstin; int *tnxtin = csa->tnxtin; int *nxtqueue = csa->nxtqueue; char *scan = csa->scan; char *mark = csa->mark; int *save = csa->save; /* local variables */ int arc, delprc, dlx, i, j, nb, node, node2, nsave, rdcost, t1, t2, t3; /* Store the arcs between the set of scanned nodes and its * complement in save and compute delprc, the stepsize to the next * breakpoint in the dual cost in the direction of increasing * prices of the scanned nodes. */ delprc = large; dlx = 0; nsave = 0; if (nscan <= n / 2) { for (i = 1; i <= nscan; i++) { node = label[i]; for (arc = fin[node]; arc > 0; arc = nxtin[arc]) { node2 = startn[arc]; if (!scan[node2]) { nsave++; save[nsave] = arc; rdcost = rc[arc]; if ((rdcost == 0) && (prdcsr[node2] != arc)) dlx += x[arc]; if ((rdcost < 0) && (rdcost > -delprc)) delprc = -rdcost; } } for (arc = fou[node]; arc > 0; arc = nxtou[arc]) { node2 = endn[arc]; if (!scan[node2]) { nsave++; save[nsave] = -arc; rdcost = rc[arc]; if ((rdcost == 0) && (prdcsr[node2] != -arc)) dlx += u[arc]; if ((rdcost > 0) && (rdcost < delprc)) delprc = rdcost; } } } } else { for (node = 1; node <= n; node++) { if (scan[node]) continue; for (arc = fou[node]; arc > 0; arc = nxtou[arc]) { node2 = endn[arc]; if (scan[node2]) { nsave++; save[nsave] = arc; rdcost = rc[arc]; if ((rdcost == 0) && (prdcsr[node] != arc)) dlx += x[arc]; if ((rdcost < 0) && (rdcost > -delprc)) delprc = -rdcost; } } for (arc = fin[node]; arc > 0; arc = nxtin[arc]) { node2 = startn[arc]; if (scan[node2]) { nsave++; save[nsave] = -arc; rdcost = rc[arc]; if ((rdcost == 0) && (prdcsr[node] != -arc)) dlx += u[arc]; if ((rdcost > 0) && (rdcost < delprc)) delprc = rdcost; } } } } if ((!svitch) && (delx + dlx >= -dm)) { svitch = true; return; } delx += dlx; /* Check that the problem is feasible. */ L4: if (delprc == large) { feasbl = false; return; } /* Increase the prices of the scanned nodes, add more nodes to * the labeled set and check if a newly labeled node has positive * deficit. */ if (svitch) { for (i = 1; i <= nsave; i++) { arc = save[i]; if (arc > 0) { rc[arc] += delprc; if (rc[arc] == 0) { node2 = startn[arc]; if (tnxtou[arc] < 0) { tnxtou[arc] = tfstou[node2]; tfstou[node2] = arc; } if (tnxtin[arc] < 0) { tnxtin[arc] = tfstin[endn[arc]]; tfstin[endn[arc]] = arc; } if (!mark[node2]) { prdcsr[node2] = arc; nlabel++; label[nlabel] = node2; mark[node2] = true; } } } else { arc = -arc; rc[arc] -= delprc; if (rc[arc] == 0) { node2 = endn[arc]; if (tnxtou[arc] < 0) { tnxtou[arc] = tfstou[startn[arc]]; tfstou[startn[arc]] = arc; } if (tnxtin[arc] < 0) { tnxtin[arc] = tfstin[node2]; tfstin[node2] = arc; } if (!mark[node2]) { prdcsr[node2] = -arc; nlabel++; label[nlabel] = node2; mark[node2] = true; } } } } return; } else { nb = 0; for (i = 1; i <= nsave; i++) { arc = save[i]; if (arc > 0) { t1 = rc[arc]; if (t1 == 0) { t2 = x[arc]; t3 = startn[arc]; dfct[t3] -= t2; if (nxtqueue[t3] == 0) { nxtqueue[prevnode] = t3; nxtqueue[t3] = curnode; prevnode = t3; } t3 = endn[arc]; dfct[t3] += t2; if (nxtqueue[t3] == 0) { nxtqueue[prevnode] = t3; nxtqueue[t3] = curnode; prevnode = t3; } u[arc] += t2; x[arc] = 0; } rc[arc] = t1 + delprc; #if 0 /* by mao; 26/IV-2013 */ if (rc[arc] == 0) #else if (rc[arc] == 0 && nb < n) #endif { delx += x[arc]; nb++; prdcsr[nb] = arc; } } else { arc = -arc; t1 = rc[arc]; if (t1 == 0) { t2 = u[arc]; t3 = startn[arc]; dfct[t3] += t2; if (nxtqueue[t3] == 0) { nxtqueue[prevnode] = t3; nxtqueue[t3] = curnode; prevnode = t3; } t3 = endn[arc]; dfct[t3] -= t2; if (nxtqueue[t3] == 0) { nxtqueue[prevnode] = t3; nxtqueue[t3] = curnode; prevnode = t3; } x[arc] += t2; u[arc] = 0; } rc[arc] = t1 - delprc; #if 0 /* by mao; 26/IV-2013 */ if (rc[arc] == 0) #else if (rc[arc] == 0 && nb < n) #endif { delx += u[arc]; nb++; prdcsr[nb] = arc; } } } } if (delx <= -dm) { delprc = large; for (i = 1; i <= nsave; i++) { arc = save[i]; if (arc > 0) { rdcost = rc[arc]; if ((rdcost < 0) && (rdcost > -delprc)) delprc = -rdcost; } else { arc = -arc; rdcost = rc[arc]; if ((rdcost > 0) && (rdcost < delprc)) delprc = rdcost; } } if ((delprc != large) || (delx < -dm)) goto L4; } /* Add new balanced arcs to the superset of balanced arcs. */ for (i = 1; i <= nb; i++) { arc = prdcsr[i]; if (tnxtin[arc] == -1) { j = endn[arc]; tnxtin[arc] = tfstin[j]; tfstin[j] = arc; } if (tnxtou[arc] == -1) { j = startn[arc]; tnxtou[arc] = tfstou[j]; tfstou[j] = arc; } } return; # undef delx # undef nlabel # undef feasbl # undef svitch # undef prevnode } /*********************************************************************** * NAME * * auction - compute good initial flow and prices * * PURPOSE * * This subroutine uses a version of the auction algorithm for min * cost network flow to compute a good initial flow and prices for the * problem. * * INPUT PARAMETERS * * n = number of nodes * na = number of arcs * large = a very large integer to represent infinity (see note 3) * startn[i] = starting node for the i-th arc, i = 1,...,na * endn[i] = ending node for the i-th arc, i = 1,...,na * fou[i] = first arc leaving i-th node, i = 1,...,n * nxtou[i] = next arc leaving the starting node of j-th arc, * i = 1,...,na * fin[i] = first arc entering i-th node, i = 1,...,n * nxtin[i] = next arc entering the ending node of j-th arc, * i = 1,...,na * * UPDATED PARAMETERS * * rc[j] = reduced cost of arc j, j = 1,...,na * u[j] = residual capacity of arc j, j = 1,...,na * x[j] = flow on arc j, j = 1,...,na * dfct[i] = deficit at node i, i = 1,...,n * * OUTPUT PARAMETERS * * nsp = number of auction/shortest path iterations * * WORKING PARAMETERS * * p[1+n], prdcsr[1+n], save[1+na], fpushf[1+n], nxtpushf[1+na], * fpushb[1+n], nxtpushb[1+na], nxtqueue[1+n], extend_arc[1+n], * sb_level[1+n], sb_arc[1+n], path_id[1+n] * * RETURNS * * 0 = normal return * 1 = problem is found to be infeasible */ static int auction(struct relax4_csa *csa) { /* input parameters */ int n = csa->n; int na = csa->na; int large = csa->large; int *startn = csa->startn; int *endn = csa->endn; int *fou = csa->fou; int *nxtou = csa->nxtou; int *fin = csa->fin; int *nxtin = csa->nxtin; /* updated parameters */ # define crash (csa->crash) int *rc = csa->rc; int *u = csa->u; int *x = csa->x; int *dfct = csa->dfct; /* output parameters */ # define nsp (csa->nsp) /* working parameters */ int *p = csa->label; int *prdcsr = csa->prdcsr; int *save = csa->save; int *fpushf = csa->tfstou; int *nxtpushf = csa->tnxtou; int *fpushb = csa->tfstin; int *nxtpushb = csa->tnxtin; int *nxtqueue = csa->nxtqueue; int *extend_arc = csa->extend_arc; int *sb_level = csa->sb_level; int *sb_arc = csa->sb_arc; char *path_id = csa->mark; /* local variables */ int arc, bstlevel, end, eps, extarc, factor, flow, i, incr, last, lastqueue, maxcost, mincost, nas, naug, new_level, node, nolist, num_passes, nxtnode, pass, pend, pr_term, prd, prevarc, prevlevel, prevnode, pstart, pterm, rdcost, red_cost, resid, root, secarc, seclevel, start, term, thresh_dfct; /* start initialization using auction */ naug = 0; pass = 0; thresh_dfct = 0; /* factor determines by how much epsilon is reduced at each * minimization */ factor = 3; /* num_passes determines how many auction scaling phases are * performed */ num_passes = 1; /* set arc flows to satisfy cs and calculate maxcost and * mincost */ maxcost = -large; mincost = large; for (arc = 1; arc <= na; arc++) { start = startn[arc]; end = endn[arc]; rdcost = rc[arc]; if (maxcost < rdcost) maxcost = rdcost; if (mincost > rdcost) mincost = rdcost; if (rdcost < 0) { dfct[start] += u[arc]; dfct[end] -= u[arc]; x[arc] = u[arc]; u[arc] = 0; } else x[arc] = 0; } /* set initial epsilon */ if ((maxcost - mincost) >= 8) eps = (maxcost - mincost) / 8; else eps = 1; /* set initial prices to zero */ for (node = 1; node <= n; node++) p[node] = 0; /* Initialization using auction/shortest paths. */ L100: /* Start of the first scaling phase. */ pass++; if ((pass == num_passes) || (eps == 1)) crash = 0; nolist = 0; /* construct list of positive surplus nodes and queue of negative * surplus nodes */ for (node = 1; node <= n; node++) { prdcsr[node] = 0; path_id[node] = false; extend_arc[node] = 0; sb_level[node] = -large; nxtqueue[node] = node + 1; if (dfct[node] > 0) { nolist++; save[nolist] = node; } } nxtqueue[n] = 1; root = 1; prevnode = lastqueue = n; /* initialization with down iterations for negative surplus * nodes */ for (i = 1; i <= nolist; i++) { node = save[i]; nsp++; /* build the list of arcs w/ room for pushing flow and find * proper price for down iteration */ bstlevel = -large; fpushf[node] = 0; for (arc = fou[node]; arc > 0; arc = nxtou[arc]) { if (u[arc] > 0) { if (fpushf[node] == 0) { fpushf[node] = arc; nxtpushf[arc] = 0; last = arc; } else { nxtpushf[last] = arc; nxtpushf[arc] = 0; last = arc; } } if (x[arc] > 0) { new_level = p[endn[arc]] + rc[arc]; if (new_level > bstlevel) { bstlevel = new_level; extarc = arc; } } } fpushb[node] = 0; for (arc = fin[node]; arc > 0; arc = nxtin[arc]) { if (x[arc] > 0) { if (fpushb[node] == 0) { fpushb[node] = arc; nxtpushb[arc] = 0; last = arc; } else { nxtpushb[last] = arc; nxtpushb[arc] = 0; last = arc; } } if (u[arc] > 0) { new_level = p[startn[arc]] - rc[arc]; if (new_level > bstlevel) { bstlevel = new_level; extarc = -arc; } } } extend_arc[node] = extarc; p[node] = bstlevel - eps; } L200: /* Start the augmentation cycles of the new scaling phase. */ if (dfct[root] >= thresh_dfct) goto L3000; term = root; path_id[root] = true; L500: /* Main forward algorithm with root as origin. */ /* start of a new forward iteration */ pterm = p[term]; extarc = extend_arc[term]; if (extarc == 0) { /* build the list of arcs w/ room for pushing flow */ fpushf[term] = 0; for (arc = fou[term]; arc > 0; arc = nxtou[arc]) { if (u[arc] > 0) { if (fpushf[term] == 0) { fpushf[term] = arc; nxtpushf[arc] = 0; last = arc; } else { nxtpushf[last] = arc; nxtpushf[arc] = 0; last = arc; } } } fpushb[term] = 0; for (arc = fin[term]; arc > 0; arc = nxtin[arc]) { if (x[arc] > 0) { if (fpushb[term] == 0) { fpushb[term] = arc; nxtpushb[arc] = 0; last = arc; } else { nxtpushb[last] = arc; nxtpushb[arc] = 0; last = arc; } } } goto L600; } /* speculative path extension attempt */ /* note: arc > 0 means that arc is oriented from the root to the * destinations * arc < 0 means that arc is oriented from the destinations to the * root * extarc = 0 or prdarc = 0, means the extension arc or the * predecessor arc, respectively, has not been established */ if (extarc > 0) { if (u[extarc] == 0) { seclevel = sb_level[term]; goto L580; } end = endn[extarc]; bstlevel = p[end] + rc[extarc]; if (pterm >= bstlevel) { if (path_id[end]) goto L1200; term = end; prdcsr[term] = extarc; path_id[term] = true; /* if negative surplus node is found, do an augmentation */ if (dfct[term] > 0) goto L2000; /* return for another iteration */ goto L500; } } else { extarc = -extarc; if (x[extarc] == 0) { seclevel = sb_level[term]; goto L580; } start = startn[extarc]; bstlevel = p[start] - rc[extarc]; if (pterm >= bstlevel) { if (path_id[start]) goto L1200; term = start; prdcsr[term] = -extarc; path_id[term] = true; /* if negative surplus node is found, do an augmentation */ if (dfct[term] > 0) goto L2000; /* return for another iteration */ goto L500; } } L550: /* second best logic test applied to save a full node scan * if old best level continues to be best go for another * contraction */ seclevel = sb_level[term]; if (bstlevel <= seclevel) goto L800; L580: /* if second best can be used do either a contraction or start * over with a speculative extension */ if (seclevel > -large) { extarc = sb_arc[term]; if (extarc > 0) { if (u[extarc] == 0) goto L600; bstlevel = p[endn[extarc]] + rc[extarc]; } else { if (x[-extarc] == 0) goto L600; bstlevel = p[startn[-extarc]] - rc[-extarc]; } if (bstlevel == seclevel) { sb_level[term] = -large; extend_arc[term] = extarc; goto L800; } } L600: /* extension/contraction attempt was unsuccessful, so scan * terminal node */ nsp++; bstlevel = seclevel = large; for (arc = fpushf[term]; arc > 0; arc = nxtpushf[arc]) { new_level = p[endn[arc]] + rc[arc]; if (new_level < seclevel) { if (new_level < bstlevel) { seclevel = bstlevel; bstlevel = new_level; secarc = extarc; extarc = arc; } else { seclevel = new_level; secarc = arc; } } } for (arc = fpushb[term]; arc > 0; arc = nxtpushb[arc]) { new_level = p[startn[arc]] - rc[arc]; if (new_level < seclevel) { if (new_level < bstlevel) { seclevel = bstlevel; bstlevel = new_level; secarc = extarc; extarc = -arc; } else { seclevel = new_level; secarc = -arc; } } } sb_level[term] = seclevel; sb_arc[term] = secarc; extend_arc[term] = extarc; L800: /* End of node scan. */ /* if the terminal node is the root, adjust its price and change * root */ if (term == root) { p[term] = bstlevel + eps; if (p[term] >= large) { /* no path to the destination */ /* problem is found to be infeasible */ return 1; } path_id[root] = false; prevnode = root; root = nxtqueue[root]; goto L200; } /* check whether extension or contraction */ prd = prdcsr[term]; if (prd > 0) { pr_term = startn[prd]; prevlevel = p[pr_term] - rc[prd]; } else { pr_term = endn[-prd]; prevlevel = p[pr_term] + rc[-prd]; } if (prevlevel > bstlevel) { /* path extension */ if (prevlevel >= bstlevel + eps) p[term] = bstlevel + eps; else p[term] = prevlevel; if (extarc > 0) { end = endn[extarc]; if (path_id[end]) goto L1200; term = end; } else { start = startn[-extarc]; if (path_id[start]) goto L1200; term = start; } prdcsr[term] = extarc; path_id[term] = true; /* if negative surplus node is found, do an augmentation */ if (dfct[term] > 0) goto L2000; /* return for another iteration */ goto L500; } else { /* path contraction */ p[term] = bstlevel + eps; path_id[term] = false; term = pr_term; if (pr_term != root) { if (bstlevel <= pterm + eps) goto L2000; } pterm = p[term]; extarc = prd; if (prd > 0) bstlevel += eps + rc[prd]; else bstlevel += eps - rc[-prd]; /* do a second best test and if that fails, do a full node * scan */ goto L550; } L1200:/* A cycle is about to form; do a retreat sequence. */ node = term; L1600:if (node != root) { path_id[node] = false; prd = prdcsr[node]; if (prd > 0) { pr_term = startn[prd]; if (p[pr_term] == p[node] + rc[prd] + eps) { node = pr_term; goto L1600; } } else { pr_term = endn[-prd]; if (p[pr_term] == p[node] - rc[-prd] + eps) { node = pr_term; goto L1600; } } /* do a full scan and price rise at pr_term */ nsp++; bstlevel = seclevel = large; for (arc = fpushf[pr_term]; arc > 0; arc = nxtpushf[arc]) { new_level = p[endn[arc]] + rc[arc]; if (new_level < seclevel) { if (new_level < bstlevel) { seclevel = bstlevel; bstlevel = new_level; secarc = extarc; extarc = arc; } else { seclevel = new_level; secarc = arc; } } } for (arc = fpushb[pr_term]; arc > 0; arc = nxtpushb[arc]) { new_level = p[startn[arc]] - rc[arc]; if (new_level < seclevel) { if (new_level < bstlevel) { seclevel = bstlevel; bstlevel = new_level; secarc = extarc; extarc = -arc; } else { seclevel = new_level; secarc = -arc; } } } sb_level[pr_term] = seclevel; sb_arc[pr_term] = secarc; extend_arc[pr_term] = extarc; p[pr_term] = bstlevel + eps; if (pr_term == root) { prevnode = root; path_id[root] = false; root = nxtqueue[root]; goto L200; } path_id[pr_term] = false; prd = prdcsr[pr_term]; if (prd > 0) term = startn[prd]; else term = endn[-prd]; if (term == root) { prevnode = root; path_id[root] = false; root = nxtqueue[root]; goto L200; } else goto L2000; } L2000:/* End of auction/shortest path routine. */ /* do augmentation from root and correct the push lists */ incr = -dfct[root]; for (node = root;;) { extarc = extend_arc[node]; path_id[node] = false; if (extarc > 0) { node = endn[extarc]; if (incr > u[extarc]) incr = u[extarc]; } else { node = startn[-extarc]; if (incr > x[-extarc]) incr = x[-extarc]; } if (node == term) break; } path_id[term] = false; if (dfct[term] > 0) { if (incr > dfct[term]) incr = dfct[term]; } for (node = root;;) { extarc = extend_arc[node]; if (extarc > 0) { end = endn[extarc]; /* add arc to the reduced graph */ if (x[extarc] == 0) { nxtpushb[extarc] = fpushb[end]; fpushb[end] = extarc; new_level = p[node] - rc[extarc]; if (sb_level[end] > new_level) { sb_level[end] = new_level; sb_arc[end] = -extarc; } } x[extarc] += incr; u[extarc] -= incr; /* remove arc from the reduced graph */ if (u[extarc] == 0) { nas++; arc = fpushf[node]; if (arc == extarc) fpushf[node] = nxtpushf[arc]; else { prevarc = arc; arc = nxtpushf[arc]; while (arc > 0) { if (arc == extarc) { nxtpushf[prevarc] = nxtpushf[arc]; break; } prevarc = arc; arc = nxtpushf[arc]; } } } node = end; } else { extarc = -extarc; start = startn[extarc]; /* add arc to the reduced graph */ if (u[extarc] == 0) { nxtpushf[extarc] = fpushf[start]; fpushf[start] = extarc; new_level = p[node] + rc[extarc]; if (sb_level[start] > new_level) { sb_level[start] = new_level; sb_arc[start] = extarc; } } u[extarc] += incr; x[extarc] -= incr; /* remove arc from the reduced graph */ if (x[extarc] == 0) { nas++; arc = fpushb[node]; if (arc == extarc) fpushb[node] = nxtpushb[arc]; else { prevarc = arc; arc = nxtpushb[arc]; while (arc > 0) { if (arc == extarc) { nxtpushb[prevarc] = nxtpushb[arc]; break; } prevarc = arc; arc = nxtpushb[arc]; } } } node = start; } if (node == term) break; } dfct[term] -= incr; dfct[root] += incr; /* insert term in the queue if it has a large enough surplus */ if (dfct[term] < thresh_dfct) { if (nxtqueue[term] == 0) { nxtnode = nxtqueue[root]; if ((p[term] >= p[nxtnode]) && (root != nxtnode)) { nxtqueue[root] = term; nxtqueue[term] = nxtnode; } else { nxtqueue[prevnode] = term; nxtqueue[term] = root; prevnode = term; } } } /* if root has a large enough surplus, keep it in the queue and * return for another iteration */ if (dfct[root] < thresh_dfct) { prevnode = root; root = nxtqueue[root]; goto L200; } L3000:/* end of augmentation cycle */ /* Check for termination of scaling phase. If scaling phase is not * finished, advance the queue and return to take another node. */ nxtnode = nxtqueue[root]; if (root != nxtnode) { nxtqueue[root] = 0; nxtqueue[prevnode] = nxtnode; root = nxtnode; goto L200; } /* End of subproblem (scaling phase). */ /* Reduce epsilon. */ eps /= factor; if (eps < 1) eps = 1; thresh_dfct /= factor; if (eps == 1) thresh_dfct = 0; /* if another auction scaling phase remains, reset the flows & * the push lists; else reset arc flows to satisfy cs and compute * reduced costs */ if (crash == 1) { for (arc = 1; arc <= na; arc++) { start = startn[arc]; end = endn[arc]; pstart = p[start]; pend = p[end]; if (pstart > pend + eps + rc[arc]) { resid = u[arc]; if (resid > 0) { dfct[start] += resid; dfct[end] -= resid; x[arc] += resid; u[arc] = 0; } } else if (pstart < pend - eps + rc[arc]) { flow = x[arc]; if (flow > 0) { dfct[start] -= flow; dfct[end] += flow; x[arc] = 0; u[arc] += flow; } } } /* return for another phase */ goto L100; } else { crash = 1; for (arc = 1; arc <= na; arc++) { start = startn[arc]; end = endn[arc]; red_cost = rc[arc] + p[end] - p[start]; if (red_cost < 0) { resid = u[arc]; if (resid > 0) { dfct[start] += resid; dfct[end] -= resid; x[arc] += resid; u[arc] = 0; } } else if (red_cost > 0) { flow = x[arc]; if (flow > 0) { dfct[start] -= flow; dfct[end] += flow; x[arc] = 0; u[arc] += flow; } } rc[arc] = red_cost; } } return 0; # undef crash # undef nsp } /* eof */ Rglpk/src/GLPK/glpapi07.c0000644000176000001440000003517712245352174014516 0ustar ripleyusers/* glpapi07.c (exact simplex solver) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpapi.h" #include "glplib.h" #include "glpssx.h" /*********************************************************************** * NAME * * glp_exact - solve LP problem in exact arithmetic * * SYNOPSIS * * int glp_exact(glp_prob *lp, const glp_smcp *parm); * * DESCRIPTION * * The routine glp_exact is a tentative implementation of the primal * two-phase simplex method based on exact (rational) arithmetic. It is * similar to the routine glp_simplex, however, for all internal * computations it uses arithmetic of rational numbers, which is exact * in mathematical sense, i.e. free of round-off errors unlike floating * point arithmetic. * * Note that the routine glp_exact uses inly two control parameters * passed in the structure glp_smcp, namely, it_lim and tm_lim. * * RETURNS * * 0 The LP problem instance has been successfully solved. This code * does not necessarily mean that the solver has found optimal * solution. It only means that the solution process was successful. * * GLP_EBADB * Unable to start the search, because the initial basis specified * in the problem object is invalid--the number of basic (auxiliary * and structural) variables is not the same as the number of rows in * the problem object. * * GLP_ESING * Unable to start the search, because the basis matrix correspodning * to the initial basis is exactly singular. * * GLP_EBOUND * Unable to start the search, because some double-bounded variables * have incorrect bounds. * * GLP_EFAIL * The problem has no rows/columns. * * GLP_EITLIM * The search was prematurely terminated, because the simplex * iteration limit has been exceeded. * * GLP_ETMLIM * The search was prematurely terminated, because the time limit has * been exceeded. */ static void set_d_eps(mpq_t x, double val) { /* convert double val to rational x obtaining a more adequate fraction than provided by mpq_set_d due to allowing a small approximation error specified by a given relative tolerance; for example, mpq_set_d would give the following 1/3 ~= 0.333333333333333314829616256247391... -> -> 6004799503160661/18014398509481984 while this routine gives exactly 1/3 */ int s, n, j; double f, p, q, eps = 1e-9; mpq_t temp; xassert(-DBL_MAX <= val && val <= +DBL_MAX); #if 1 /* 30/VII-2008 */ if (val == floor(val)) { /* if val is integral, do not approximate */ mpq_set_d(x, val); goto done; } #endif if (val > 0.0) s = +1; else if (val < 0.0) s = -1; else { mpq_set_si(x, 0, 1); goto done; } f = frexp(fabs(val), &n); /* |val| = f * 2^n, where 0.5 <= f < 1.0 */ fp2rat(f, 0.1 * eps, &p, &q); /* f ~= p / q, where p and q are integers */ mpq_init(temp); mpq_set_d(x, p); mpq_set_d(temp, q); mpq_div(x, x, temp); mpq_set_si(temp, 1, 1); for (j = 1; j <= abs(n); j++) mpq_add(temp, temp, temp); if (n > 0) mpq_mul(x, x, temp); else if (n < 0) mpq_div(x, x, temp); mpq_clear(temp); if (s < 0) mpq_neg(x, x); /* check that the desired tolerance has been attained */ xassert(fabs(val - mpq_get_d(x)) <= eps * (1.0 + fabs(val))); done: return; } static void load_data(SSX *ssx, LPX *lp) { /* load LP problem data into simplex solver workspace */ int m = ssx->m; int n = ssx->n; int nnz = ssx->A_ptr[n+1]-1; int j, k, type, loc, len, *ind; double lb, ub, coef, *val; xassert(lpx_get_num_rows(lp) == m); xassert(lpx_get_num_cols(lp) == n); xassert(lpx_get_num_nz(lp) == nnz); /* types and bounds of rows and columns */ for (k = 1; k <= m+n; k++) { if (k <= m) { type = lpx_get_row_type(lp, k); lb = lpx_get_row_lb(lp, k); ub = lpx_get_row_ub(lp, k); } else { type = lpx_get_col_type(lp, k-m); lb = lpx_get_col_lb(lp, k-m); ub = lpx_get_col_ub(lp, k-m); } switch (type) { case LPX_FR: type = SSX_FR; break; case LPX_LO: type = SSX_LO; break; case LPX_UP: type = SSX_UP; break; case LPX_DB: type = SSX_DB; break; case LPX_FX: type = SSX_FX; break; default: xassert(type != type); } ssx->type[k] = type; set_d_eps(ssx->lb[k], lb); set_d_eps(ssx->ub[k], ub); } /* optimization direction */ switch (lpx_get_obj_dir(lp)) { case LPX_MIN: ssx->dir = SSX_MIN; break; case LPX_MAX: ssx->dir = SSX_MAX; break; default: xassert(lp != lp); } /* objective coefficients */ for (k = 0; k <= m+n; k++) { if (k == 0) coef = lpx_get_obj_coef(lp, 0); else if (k <= m) coef = 0.0; else coef = lpx_get_obj_coef(lp, k-m); set_d_eps(ssx->coef[k], coef); } /* constraint coefficients */ ind = xcalloc(1+m, sizeof(int)); val = xcalloc(1+m, sizeof(double)); loc = 0; for (j = 1; j <= n; j++) { ssx->A_ptr[j] = loc+1; len = lpx_get_mat_col(lp, j, ind, val); for (k = 1; k <= len; k++) { loc++; ssx->A_ind[loc] = ind[k]; set_d_eps(ssx->A_val[loc], val[k]); } } xassert(loc == nnz); xfree(ind); xfree(val); return; } static int load_basis(SSX *ssx, LPX *lp) { /* load current LP basis into simplex solver workspace */ int m = ssx->m; int n = ssx->n; int *type = ssx->type; int *stat = ssx->stat; int *Q_row = ssx->Q_row; int *Q_col = ssx->Q_col; int i, j, k; xassert(lpx_get_num_rows(lp) == m); xassert(lpx_get_num_cols(lp) == n); /* statuses of rows and columns */ for (k = 1; k <= m+n; k++) { if (k <= m) stat[k] = lpx_get_row_stat(lp, k); else stat[k] = lpx_get_col_stat(lp, k-m); switch (stat[k]) { case LPX_BS: stat[k] = SSX_BS; break; case LPX_NL: stat[k] = SSX_NL; xassert(type[k] == SSX_LO || type[k] == SSX_DB); break; case LPX_NU: stat[k] = SSX_NU; xassert(type[k] == SSX_UP || type[k] == SSX_DB); break; case LPX_NF: stat[k] = SSX_NF; xassert(type[k] == SSX_FR); break; case LPX_NS: stat[k] = SSX_NS; xassert(type[k] == SSX_FX); break; default: xassert(stat != stat); } } /* build permutation matix Q */ i = j = 0; for (k = 1; k <= m+n; k++) { if (stat[k] == SSX_BS) { i++; if (i > m) return 1; Q_row[k] = i, Q_col[i] = k; } else { j++; if (j > n) return 1; Q_row[k] = m+j, Q_col[m+j] = k; } } xassert(i == m && j == n); return 0; } int glp_exact(glp_prob *lp, const glp_smcp *parm) { glp_smcp _parm; SSX *ssx; int m = lpx_get_num_rows(lp); int n = lpx_get_num_cols(lp); int nnz = lpx_get_num_nz(lp); int i, j, k, type, pst, dst, ret, *stat; double lb, ub, *prim, *dual, sum; if (parm == NULL) parm = &_parm, glp_init_smcp((glp_smcp *)parm); /* check control parameters */ if (parm->it_lim < 0) xerror("glp_exact: it_lim = %d; invalid parameter\n", parm->it_lim); if (parm->tm_lim < 0) xerror("glp_exact: tm_lim = %d; invalid parameter\n", parm->tm_lim); /* the problem must have at least one row and one column */ if (!(m > 0 && n > 0)) { xprintf("glp_exact: problem has no rows/columns\n"); return GLP_EFAIL; } #if 1 /* basic solution is currently undefined */ lp->pbs_stat = lp->dbs_stat = GLP_UNDEF; lp->obj_val = 0.0; lp->some = 0; #endif /* check that all double-bounded variables have correct bounds */ for (k = 1; k <= m+n; k++) { if (k <= m) { type = lpx_get_row_type(lp, k); lb = lpx_get_row_lb(lp, k); ub = lpx_get_row_ub(lp, k); } else { type = lpx_get_col_type(lp, k-m); lb = lpx_get_col_lb(lp, k-m); ub = lpx_get_col_ub(lp, k-m); } if (type == LPX_DB && lb >= ub) { xprintf("glp_exact: %s %d has invalid bounds\n", k <= m ? "row" : "column", k <= m ? k : k-m); return GLP_EBOUND; } } /* create the simplex solver workspace */ xprintf("glp_exact: %d rows, %d columns, %d non-zeros\n", m, n, nnz); #ifdef HAVE_GMP xprintf("GNU MP bignum library is being used\n"); #else xprintf("GLPK bignum module is being used\n"); xprintf("(Consider installing GNU MP to attain a much better perf" "ormance.)\n"); #endif ssx = ssx_create(m, n, nnz); /* load LP problem data into the workspace */ load_data(ssx, lp); /* load current LP basis into the workspace */ if (load_basis(ssx, lp)) { xprintf("glp_exact: initial LP basis is invalid\n"); ret = GLP_EBADB; goto done; } /* inherit some control parameters from the LP object */ #if 0 ssx->it_lim = lpx_get_int_parm(lp, LPX_K_ITLIM); ssx->it_cnt = lpx_get_int_parm(lp, LPX_K_ITCNT); ssx->tm_lim = lpx_get_real_parm(lp, LPX_K_TMLIM); #else ssx->it_lim = parm->it_lim; ssx->it_cnt = lp->it_cnt; ssx->tm_lim = (double)parm->tm_lim / 1000.0; #endif ssx->out_frq = 5.0; ssx->tm_beg = xtime(); #if 0 /* 10/VI-2013 */ ssx->tm_lag = xlset(0); #else ssx->tm_lag = 0.0; #endif /* solve LP */ ret = ssx_driver(ssx); /* copy back some statistics to the LP object */ #if 0 lpx_set_int_parm(lp, LPX_K_ITLIM, ssx->it_lim); lpx_set_int_parm(lp, LPX_K_ITCNT, ssx->it_cnt); lpx_set_real_parm(lp, LPX_K_TMLIM, ssx->tm_lim); #else lp->it_cnt = ssx->it_cnt; #endif /* analyze the return code */ switch (ret) { case 0: /* optimal solution found */ ret = 0; pst = LPX_P_FEAS, dst = LPX_D_FEAS; break; case 1: /* problem has no feasible solution */ ret = 0; pst = LPX_P_NOFEAS, dst = LPX_D_INFEAS; break; case 2: /* problem has unbounded solution */ ret = 0; pst = LPX_P_FEAS, dst = LPX_D_NOFEAS; #if 1 xassert(1 <= ssx->q && ssx->q <= n); lp->some = ssx->Q_col[m + ssx->q]; xassert(1 <= lp->some && lp->some <= m+n); #endif break; case 3: /* iteration limit exceeded (phase I) */ ret = GLP_EITLIM; pst = LPX_P_INFEAS, dst = LPX_D_INFEAS; break; case 4: /* iteration limit exceeded (phase II) */ ret = GLP_EITLIM; pst = LPX_P_FEAS, dst = LPX_D_INFEAS; break; case 5: /* time limit exceeded (phase I) */ ret = GLP_ETMLIM; pst = LPX_P_INFEAS, dst = LPX_D_INFEAS; break; case 6: /* time limit exceeded (phase II) */ ret = GLP_ETMLIM; pst = LPX_P_FEAS, dst = LPX_D_INFEAS; break; case 7: /* initial basis matrix is singular */ ret = GLP_ESING; goto done; default: xassert(ret != ret); } /* obtain final basic solution components */ stat = xcalloc(1+m+n, sizeof(int)); prim = xcalloc(1+m+n, sizeof(double)); dual = xcalloc(1+m+n, sizeof(double)); for (k = 1; k <= m+n; k++) { if (ssx->stat[k] == SSX_BS) { i = ssx->Q_row[k]; /* x[k] = xB[i] */ xassert(1 <= i && i <= m); stat[k] = LPX_BS; prim[k] = mpq_get_d(ssx->bbar[i]); dual[k] = 0.0; } else { j = ssx->Q_row[k] - m; /* x[k] = xN[j] */ xassert(1 <= j && j <= n); switch (ssx->stat[k]) { case SSX_NF: stat[k] = LPX_NF; prim[k] = 0.0; break; case SSX_NL: stat[k] = LPX_NL; prim[k] = mpq_get_d(ssx->lb[k]); break; case SSX_NU: stat[k] = LPX_NU; prim[k] = mpq_get_d(ssx->ub[k]); break; case SSX_NS: stat[k] = LPX_NS; prim[k] = mpq_get_d(ssx->lb[k]); break; default: xassert(ssx != ssx); } dual[k] = mpq_get_d(ssx->cbar[j]); } } /* and store them into the LP object */ pst = pst - LPX_P_UNDEF + GLP_UNDEF; dst = dst - LPX_D_UNDEF + GLP_UNDEF; for (k = 1; k <= m+n; k++) stat[k] = stat[k] - LPX_BS + GLP_BS; sum = lpx_get_obj_coef(lp, 0); for (j = 1; j <= n; j++) sum += lpx_get_obj_coef(lp, j) * prim[m+j]; lpx_put_solution(lp, 1, &pst, &dst, &sum, &stat[0], &prim[0], &dual[0], &stat[m], &prim[m], &dual[m]); xfree(stat); xfree(prim); xfree(dual); done: /* delete the simplex solver workspace */ ssx_delete(ssx); /* return to the application program */ return ret; } /* eof */ Rglpk/src/GLPK/Makefile.win0000644000176000001440000000437112245337107015152 0ustar ripleyusers#-*- Makefile -*- # include $(R_HOME)/etc$(R_ARCH)/Makeconf SOURCES= \ ./minisat/minisat.c \ ./glptsp.c \ ./sgf.c \ ./glprgr.c \ ./lufint.c \ ./triang.c \ ./glpnpp01.c \ ./glpapi09.c \ ./glpios08.c \ ./glpscl.c \ ./glpavl.c \ ./glpapi15.c \ ./glpios05.c \ ./glpios12.c \ ./glpios09.c \ ./glpapi12.c \ ./glpssx01.c \ ./glpcpx.c \ ./glpapi17.c \ ./glpmpl06.c \ ./glpmpl03.c \ ./glpnpp03.c \ ./glpgmp.c \ ./glpios02.c \ ./glpapi10.c \ ./glpnpp02.c \ ./glpsdf.c \ ./glpapi16.c \ ./glpipm.c \ ./glpspx01.c \ ./colamd/colamd.c \ ./zlib/gzclose.c \ ./zlib/gzread.c \ ./zlib/inftrees.c \ ./zlib/zutil.c \ ./zlib/uncompr.c \ ./zlib/deflate.c \ ./zlib/gzwrite.c \ ./zlib/adler32.c \ ./zlib/inflate.c \ ./zlib/trees.c \ ./zlib/zio.c \ ./zlib/inffast.c \ ./zlib/compress.c \ ./zlib/gzlib.c \ ./zlib/crc32.c \ ./qmd.c \ ./glpapi13.c \ ./dmp.c \ ./glpapi03.c \ ./glpnpp06.c \ ./glpapi06.c \ ./glphbm.c \ ./tls.c \ ./time.c \ ./glpios01.c \ ./glpmpl02.c \ ./glpios04.c \ ./glpenv08.c \ ./proxy/main.c \ ./proxy/proxy.c \ ./proxy/proxy1.c \ ./glpapi11.c \ ./glpspm.c \ ./glpssx02.c \ ./glpnpp04.c \ ./fhvint.c \ ./glplpx02.c \ ./glplux.c \ ./glpmpl04.c \ ./bignum.c \ ./glpnet05.c \ ./okalg.c \ ./glpmpl01.c \ ./glpios03.c \ ./glplpf.c \ ./glpnpp05.c \ ./glpapi20.c \ ./rng1.c \ ./error.c \ ./glpios11.c \ ./glpmps.c \ ./amd/amd_order.c \ ./amd/amd_defaults.c \ ./amd/amd_postorder.c \ ./amd/amd_info.c \ ./amd/amd_dump.c \ ./amd/amd_control.c \ ./amd/amd_valid.c \ ./amd/amd_1.c \ ./amd/amd_post_tree.c \ ./amd/amd_aat.c \ ./amd/amd_2.c \ ./amd/amd_preprocess.c \ ./cfg1.c \ ./glplpx01.c \ ./glpapi19.c \ ./glpapi01.c \ ./glpapi18.c \ ./glpdmx.c \ ./glplib03.c \ ./glpmat.c \ ./glpspx02.c \ ./glpapi07.c \ ./glpbfd.c \ ./glpnet03.c \ ./glpenv07.c \ ./glpapi05.c \ ./keller.c \ ./glpapi04.c \ ./luf.c \ ./env.c \ ./glplpx03.c \ ./mc13d.c \ ./glpapi08.c \ ./sva.c \ ./stdout.c \ ./ffalg.c \ ./rng.c \ ./alloc.c \ ./glpnet04.c \ ./glpbfx.c \ ./glpapi14.c \ ./glpapi21.c \ ./wclique.c \ ./fhv.c \ ./glpini01.c \ ./mc21a.c \ ./glpapi02.c \ ./cfg.c \ ./glpios10.c \ ./glpmpl05.c \ ./wclique1.c \ ./jd.c \ ./glpios07.c \ ./glpsql.c \ ./glpios06.c \ ./glpini02.c \ ./glpscf.c \ ./relax4.c \ OBJS = $(SOURCES:.c=.o) PKG_CPPFLAGS = -D__WOE__ -D__MINGW32__ -I. all: libglpk.a libglpk.a: $(OBJS) $(AR) crs $@ $(OBJS) Rglpk/src/GLPK/glpbfd.h0000644000176000001440000000502112245352174014317 0ustar ripleyusers/* glpbfd.h (LP basis factorization driver) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPBFD_H #define GLPBFD_H typedef struct BFD BFD; /* return codes: */ #define BFD_ESING 1 /* singular matrix */ #define BFD_ECOND 2 /* ill-conditioned matrix */ #define BFD_ECHECK 3 /* insufficient accuracy */ #define BFD_ELIMIT 4 /* update limit reached */ #define BFD_EROOM 5 /* SVA overflow */ #define bfd_create_it _glp_bfd_create_it BFD *bfd_create_it(void); /* create LP basis factorization */ #define bfd_set_parm _glp_bfd_set_parm void bfd_set_parm(BFD *bfd, const void *parm); /* change LP basis factorization control parameters */ #define bfd_factorize _glp_bfd_factorize int bfd_factorize(BFD *bfd, int m, const int bh[], int (*col) (void *info, int j, int ind[], double val[]), void *info); /* compute LP basis factorization */ #define bfd_ftran _glp_bfd_ftran void bfd_ftran(BFD *bfd, double x[]); /* perform forward transformation (solve system B*x = b) */ #define bfd_btran _glp_bfd_btran void bfd_btran(BFD *bfd, double x[]); /* perform backward transformation (solve system B'*x = b) */ #define bfd_update_it _glp_bfd_update_it int bfd_update_it(BFD *bfd, int j, int bh, int len, const int ind[], const double val[]); /* update LP basis factorization */ #define bfd_get_count _glp_bfd_get_count int bfd_get_count(BFD *bfd); /* determine factorization update count */ #define bfd_delete_it _glp_bfd_delete_it void bfd_delete_it(BFD *bfd); /* delete LP basis factorization */ #endif /* eof */ Rglpk/src/GLPK/lufint.c0000644000176000001440000001555412245352174014371 0ustar ripleyusers/* lufint.c (interface to LU-factorization) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #include "lufint.h" LUFINT *lufint_create(void) { /* create interface to LU-factorization */ LUFINT *fi; fi = talloc(1, LUFINT); fi->n_max = 0; fi->valid = 0; fi->sva = NULL; fi->luf = NULL; fi->sgf = NULL; fi->sva_n_max = fi->sva_size = 0; fi->delta_n0 = fi->delta_n = 0; fi->sgf_updat = 0; fi->sgf_piv_tol = 0.10; fi->sgf_piv_lim = 4; fi->sgf_suhl = 1; fi->sgf_eps_tol = DBL_EPSILON; return fi; } static int setup_v_cols(LUF *luf, int (*col)(void *info, int j, int ind[], double val[]), void *info, int ind[], double val[]) { /* setup matrix V = A in column-wise format */ int n = luf->n; SVA *sva = luf->sva; int *sv_ind = sva->ind; double *sv_val = sva->val; int vc_ref = luf->vc_ref; int *vc_ptr = &sva->ptr[vc_ref-1]; int *vc_len = &sva->len[vc_ref-1]; int *vc_cap = &sva->cap[vc_ref-1]; int j, len, ptr, nnz; nnz = 0; for (j = 1; j <= n; j++) { /* get j-th column */ len = col(info, j, ind, val); xassert(0 <= len && len <= n); /* enlarge j-th column capacity */ if (vc_cap[j] < len) { if (sva->r_ptr - sva->m_ptr < len) { sva_more_space(sva, len); sv_ind = sva->ind; sv_val = sva->val; } sva_enlarge_cap(sva, vc_ref-1+j, len, 0); } /* store j-th column */ ptr = vc_ptr[j]; memcpy(&sv_ind[ptr], &ind[1], len * sizeof(int)); memcpy(&sv_val[ptr], &val[1], len * sizeof(double)); vc_len[j] = len; nnz += len; } return nnz; } int lufint_factorize(LUFINT *fi, int n, int (*col)(void *info, int j, int ind[], double val[]), void *info) { /* compute LU-factorization of specified matrix A */ SVA *sva; LUF *luf; SGF *sgf; int k; xassert(n > 0); fi->valid = 0; /* create sparse vector area (SVA), if necessary */ sva = fi->sva; if (sva == NULL) { int sva_n_max = fi->sva_n_max; int sva_size = fi->sva_size; if (sva_n_max == 0) sva_n_max = 4 * n; if (sva_size == 0) sva_size = 10 * n; sva = fi->sva = sva_create_area(sva_n_max, sva_size); } /* allocate/reallocate underlying objects, if necessary */ if (fi->n_max < n) { int n_max = fi->n_max; if (n_max == 0) n_max = fi->n_max = n + fi->delta_n0; else n_max = fi->n_max = n + fi->delta_n; xassert(n_max >= n); /* allocate/reallocate LU-factorization (LUF) */ luf = fi->luf; if (luf == NULL) { luf = fi->luf = talloc(1, LUF); memset(luf, 0, sizeof(LUF)); luf->sva = sva; } else { tfree(luf->vr_piv); tfree(luf->pp_ind); tfree(luf->pp_inv); tfree(luf->qq_ind); tfree(luf->qq_inv); } luf->vr_piv = talloc(1+n_max, double); luf->pp_ind = talloc(1+n_max, int); luf->pp_inv = talloc(1+n_max, int); luf->qq_ind = talloc(1+n_max, int); luf->qq_inv = talloc(1+n_max, int); /* allocate/reallocate factorizer workspace (SGF) */ sgf = fi->sgf; if (sgf == NULL) { sgf = fi->sgf = talloc(1, SGF); memset(sgf, 0, sizeof(SGF)); sgf->luf = luf; } else { tfree(sgf->rs_head); tfree(sgf->rs_prev); tfree(sgf->rs_next); tfree(sgf->cs_head); tfree(sgf->cs_prev); tfree(sgf->cs_next); tfree(sgf->vr_max); tfree(sgf->flag); tfree(sgf->work); } sgf->rs_head = talloc(1+n_max, int); sgf->rs_prev = talloc(1+n_max, int); sgf->rs_next = talloc(1+n_max, int); sgf->cs_head = talloc(1+n_max, int); sgf->cs_prev = talloc(1+n_max, int); sgf->cs_next = talloc(1+n_max, int); sgf->vr_max = talloc(1+n_max, double); sgf->flag = talloc(1+n_max, char); sgf->work = talloc(1+n_max, double); } luf = fi->luf; sgf = fi->sgf; #if 1 /* FIXME */ /* initialize SVA */ sva->n = 0; sva->m_ptr = 1; sva->r_ptr = sva->size + 1; sva->head = sva->tail = 0; #endif /* allocate sparse vectors in SVA */ luf->n = n; luf->fr_ref = sva_alloc_vecs(sva, n); luf->fc_ref = sva_alloc_vecs(sva, n); luf->vr_ref = sva_alloc_vecs(sva, n); luf->vc_ref = sva_alloc_vecs(sva, n); /* setup matrix V = A in column-wise format */ setup_v_cols(luf, col, info, sgf->rs_prev, sgf->work); /* setup factorizer control parameters */ sgf->updat = fi->sgf_updat; sgf->piv_tol = fi->sgf_piv_tol; sgf->piv_lim = fi->sgf_piv_lim; sgf->suhl = fi->sgf_suhl; sgf->eps_tol = fi->sgf_eps_tol; /* compute LU-factorization of specified matrix A */ k = sgf_factorize(sgf, 1); if (k == 0) fi->valid = 1; return k; } void lufint_delete(LUFINT *fi) { /* delete interface to LU-factorization */ SVA *sva = fi->sva; LUF *luf = fi->luf; SGF *sgf = fi->sgf; if (sva != NULL) sva_delete_area(sva); if (luf != NULL) { tfree(luf->vr_piv); tfree(luf->pp_ind); tfree(luf->pp_inv); tfree(luf->qq_ind); tfree(luf->qq_inv); tfree(luf); } if (sgf != NULL) { tfree(sgf->rs_head); tfree(sgf->rs_prev); tfree(sgf->rs_next); tfree(sgf->cs_head); tfree(sgf->cs_prev); tfree(sgf->cs_next); tfree(sgf->vr_max); tfree(sgf->flag); tfree(sgf->work); tfree(sgf); } tfree(fi); return; } /* eof */ Rglpk/src/GLPK/mc13d.c0000644000176000001440000002444012245352174013771 0ustar ripleyusers/* mc13d.c (permutations to block triangular form) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * This code is the result of translation of the Fortran subroutines * MC13D and MC13E associated with the following paper: * * I.S.Duff, J.K.Reid, Algorithm 529: Permutations to block triangular * form, ACM Trans. on Math. Softw. 4 (1978), 189-192. * * Use of ACM Algorithms is subject to the ACM Software Copyright and * License Agreement. See . * * The translation was made by Andrew Makhorin . * * 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 . ***********************************************************************/ #include "mc13d.h" /*********************************************************************** * NAME * * mc13d - permutations to block triangular form * * SYNOPSIS * * #include "mc13d.h" * int mc13d(int n, const int icn[], const int ip[], const int lenr[], * int ior[], int ib[], int lowl[], int numb[], int prev[]); * * DESCRIPTION * * Given the column numbers of the nonzeros in each row of the sparse * matrix, the routine mc13d finds a symmetric permutation that makes * the matrix block lower triangular. * * INPUT PARAMETERS * * n order of the matrix. * * icn array containing the column indices of the non-zeros. Those * belonging to a single row must be contiguous but the ordering * of column indices within each row is unimportant and wasted * space between rows is permitted. * * ip ip[i], i = 1,2,...,n, is the position in array icn of the * first column index of a non-zero in row i. * * lenr lenr[i], i = 1,2,...,n, is the number of non-zeros in row i. * * OUTPUT PARAMETERS * * ior ior[i], i = 1,2,...,n, gives the position on the original * ordering of the row or column which is in position i in the * permuted form. * * ib ib[i], i = 1,2,...,num, is the row number in the permuted * matrix of the beginning of block i, 1 <= num <= n. * * WORKING ARRAYS * * arp working array of length [1+n], where arp[0] is not used. * arp[i] is one less than the number of unsearched edges leaving * node i. At the end of the algorithm it is set to a permutation * which puts the matrix in block lower triangular form. * * ib working array of length [1+n], where ib[0] is not used. * ib[i] is the position in the ordering of the start of the ith * block. ib[n+1-i] holds the node number of the ith node on the * stack. * * lowl working array of length [1+n], where lowl[0] is not used. * lowl[i] is the smallest stack position of any node to which a * path from node i has been found. It is set to n+1 when node i * is removed from the stack. * * numb working array of length [1+n], where numb[0] is not used. * numb[i] is the position of node i in the stack if it is on it, * is the permuted order of node i for those nodes whose final * position has been found and is otherwise zero. * * prev working array of length [1+n], where prev[0] is not used. * prev[i] is the node at the end of the path when node i was * placed on the stack. * * RETURNS * * The routine mc13d returns num, the number of blocks found. */ int mc13d(int n, const int icn[], const int ip[], const int lenr[], int ior[], int ib[], int lowl[], int numb[], int prev[]) { int *arp = ior; int dummy, i, i1, i2, icnt, ii, isn, ist, ist1, iv, iw, j, lcnt, nnm1, num, stp; /* icnt is the number of nodes whose positions in final ordering * have been found. */ icnt = 0; /* num is the number of blocks that have been found. */ num = 0; nnm1 = n + n - 1; /* Initialization of arrays. */ for (j = 1; j <= n; j++) { numb[j] = 0; arp[j] = lenr[j] - 1; } for (isn = 1; isn <= n; isn++) { /* Look for a starting node. */ if (numb[isn] != 0) continue; iv = isn; /* ist is the number of nodes on the stack ... it is the stack * pointer. */ ist = 1; /* Put node iv at beginning of stack. */ lowl[iv] = numb[iv] = 1; ib[n] = iv; /* The body of this loop puts a new node on the stack or * backtracks. */ for (dummy = 1; dummy <= nnm1; dummy++) { i1 = arp[iv]; /* Have all edges leaving node iv been searched? */ if (i1 >= 0) { i2 = ip[iv] + lenr[iv] - 1; i1 = i2 - i1; /* Look at edges leaving node iv until one enters a new * node or all edges are exhausted. */ for (ii = i1; ii <= i2; ii++) { iw = icn[ii]; /* Has node iw been on stack already? */ if (numb[iw] == 0) goto L70; /* Update value of lowl[iv] if necessary. */ if (lowl[iw] < lowl[iv]) lowl[iv] = lowl[iw]; } /* There are no more edges leaving node iv. */ arp[iv] = -1; } /* Is node iv the root of a block? */ if (lowl[iv] < numb[iv]) goto L60; /* Order nodes in a block. */ num++; ist1 = n + 1 - ist; lcnt = icnt + 1; /* Peel block off the top of the stack starting at the top * and working down to the root of the block. */ for (stp = ist1; stp <= n; stp++) { iw = ib[stp]; lowl[iw] = n + 1; numb[iw] = ++icnt; if (iw == iv) break; } ist = n - stp; ib[num] = lcnt; /* Are there any nodes left on the stack? */ if (ist != 0) goto L60; /* Have all the nodes been ordered? */ if (icnt < n) break; goto L100; L60: /* Backtrack to previous node on path. */ iw = iv; iv = prev[iv]; /* Update value of lowl[iv] if necessary. */ if (lowl[iw] < lowl[iv]) lowl[iv] = lowl[iw]; continue; L70: /* Put new node on the stack. */ arp[iv] = i2 - ii - 1; prev[iw] = iv; iv = iw; lowl[iv] = numb[iv] = ++ist; ib[n+1-ist] = iv; } } L100: /* Put permutation in the required form. */ for (i = 1; i <= n; i++) arp[numb[i]] = i; return num; } /**********************************************************************/ #ifdef GLP_TEST #include "env.h" void test(int n, int ipp); int main(void) { /* test program for routine mc13d */ test( 1, 0); test( 2, 1); test( 2, 2); test( 3, 3); test( 4, 4); test( 5, 10); test(10, 10); test(10, 20); test(20, 20); test(20, 50); test(50, 50); test(50, 200); return 0; } void fa01bs(int max, int *nrand); void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[]); void test(int n, int ipp) { int ip[1+50], icn[1+1000], ior[1+50], ib[1+51], iw[1+150], lenr[1+50]; char a[1+50][1+50], hold[1+100]; int i, ii, iblock, ij, index, j, jblock, jj, k9, num; xprintf("\n\n\nMatrix is of order %d and has %d off-diagonal non-" "zeros\n", n, ipp); for (j = 1; j <= n; j++) { for (i = 1; i <= n; i++) a[i][j] = 0; a[j][j] = 1; } for (k9 = 1; k9 <= ipp; k9++) { /* these statements should be replaced by calls to your * favorite random number generator to place two pseudo-random * numbers between 1 and n in the variables i and j */ for (;;) { fa01bs(n, &i); fa01bs(n, &j); if (!a[i][j]) break; } a[i][j] = 1; } /* setup converts matrix a[i,j] to required sparsity-oriented * storage format */ setup(n, a, ip, icn, lenr); num = mc13d(n, icn, ip, lenr, ior, ib, &iw[0], &iw[n], &iw[n+n]); /* output reordered matrix with blocking to improve clarity */ xprintf("\nThe reordered matrix which has %d block%s is of the fo" "rm\n", num, num == 1 ? "" : "s"); ib[num+1] = n + 1; index = 100; iblock = 1; for (i = 1; i <= n; i++) { for (ij = 1; ij <= index; ij++) hold[ij] = ' '; if (i == ib[iblock]) { xprintf("\n"); iblock++; } jblock = 1; index = 0; for (j = 1; j <= n; j++) { if (j == ib[jblock]) { hold[++index] = ' '; jblock++; } ii = ior[i]; jj = ior[j]; hold[++index] = (char)(a[ii][jj] ? 'X' : '0'); } xprintf("%.*s\n", index, &hold[1]); } xprintf("\nThe starting point for each block is given by\n"); for (i = 1; i <= num; i++) { if ((i - 1) % 12 == 0) xprintf("\n"); xprintf(" %4d", ib[i]); } xprintf("\n"); return; } void setup(int n, char a[1+50][1+50], int ip[], int icn[], int lenr[]) { int i, j, ind; for (i = 1; i <= n; i++) lenr[i] = 0; ind = 1; for (i = 1; i <= n; i++) { ip[i] = ind; for (j = 1; j <= n; j++) { if (a[i][j]) { lenr[i]++; icn[ind++] = j; } } } return; } double g = 1431655765.0; double fa01as(int i) { /* random number generator */ g = fmod(g * 9228907.0, 4294967296.0); if (i >= 0) return g / 4294967296.0; else return 2.0 * g / 4294967296.0 - 1.0; } void fa01bs(int max, int *nrand) { *nrand = (int)(fa01as(1) * (double)max) + 1; return; } #endif /* eof */ Rglpk/src/GLPK/glpspx.h0000644000176000001440000000267012245352174014405 0ustar ripleyusers/* glpspx.h (core simplex solvers) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPSPX_H #define GLPSPX_H #include "glpapi.h" #define spx_primal _glp_spx_primal int spx_primal(glp_prob *lp, const glp_smcp *parm); /* core LP solver based on the primal simplex method */ #define spx_dual _glp_spx_dual int spx_dual(glp_prob *lp, const glp_smcp *parm); /* core LP solver based on the dual simplex method */ #endif /* eof */ Rglpk/src/GLPK/glprgr.c0000644000176000001440000001416512245352174014362 0ustar ripleyusers/* glprgr.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #define _GLPSTD_ERRNO #define _GLPSTD_STDIO #include "env.h" #include "glprgr.h" #define xfault xerror /*********************************************************************** * NAME * * rgr_write_bmp16 - write 16-color raster image in BMP file format * * SYNOPSIS * * #include "glprgr.h" * int rgr_write_bmp16(const char *fname, int m, int n, const char * map[]); * * DESCRIPTION * * The routine rgr_write_bmp16 writes 16-color raster image in * uncompressed BMP file format (Windows bitmap) to a binary file whose * name is specified by the character string fname. * * The parameters m and n specify, respectively, the number of rows and * the numbers of columns (i.e. height and width) of the raster image. * * The character array map has m*n elements. Elements map[0, ..., n-1] * correspond to the first (top) scanline, elements map[n, ..., 2*n-1] * correspond to the second scanline, etc. * * Each element of the array map specifies a color of the corresponding * pixel as 8-bit binary number XXXXIRGB, where four high-order bits (X) * are ignored, I is high intensity bit, R is red color bit, G is green * color bit, and B is blue color bit. Thus, all 16 possible colors are * coded as following hexadecimal numbers: * * 0x00 = black 0x08 = dark gray * 0x01 = blue 0x09 = bright blue * 0x02 = green 0x0A = bright green * 0x03 = cyan 0x0B = bright cyan * 0x04 = red 0x0C = bright red * 0x05 = magenta 0x0D = bright magenta * 0x06 = brown 0x0E = yellow * 0x07 = light gray 0x0F = white * * RETURNS * * If no error occured, the routine returns zero; otherwise, it prints * an appropriate error message and returns non-zero. */ static void put_byte(FILE *fp, int c) { fputc(c, fp); return; } static void put_word(FILE *fp, int w) { /* big endian */ put_byte(fp, w); put_byte(fp, w >> 8); return; } static void put_dword(FILE *fp, int d) { /* big endian */ put_word(fp, d); put_word(fp, d >> 16); return; } int rgr_write_bmp16(const char *fname, int m, int n, const char map[]) { FILE *fp; int offset, bmsize, i, j, b, ret = 0; if (!(1 <= m && m <= 32767)) xfault("rgr_write_bmp16: m = %d; invalid height\n", m); if (!(1 <= n && n <= 32767)) xfault("rgr_write_bmp16: n = %d; invalid width\n", n); fp = fopen(fname, "wb"); if (fp == NULL) { xprintf("rgr_write_bmp16: unable to create `%s' - %s\n", fname, strerror(errno)); ret = 1; goto fini; } offset = 14 + 40 + 16 * 4; bmsize = (4 * n + 31) / 32; /* struct BMPFILEHEADER (14 bytes) */ /* UINT bfType */ put_byte(fp, 'B'), put_byte(fp, 'M'); /* DWORD bfSize */ put_dword(fp, offset + bmsize * 4); /* UINT bfReserved1 */ put_word(fp, 0); /* UNIT bfReserved2 */ put_word(fp, 0); /* DWORD bfOffBits */ put_dword(fp, offset); /* struct BMPINFOHEADER (40 bytes) */ /* DWORD biSize */ put_dword(fp, 40); /* LONG biWidth */ put_dword(fp, n); /* LONG biHeight */ put_dword(fp, m); /* WORD biPlanes */ put_word(fp, 1); /* WORD biBitCount */ put_word(fp, 4); /* DWORD biCompression */ put_dword(fp, 0 /* BI_RGB */); /* DWORD biSizeImage */ put_dword(fp, 0); /* LONG biXPelsPerMeter */ put_dword(fp, 2953 /* 75 dpi */); /* LONG biYPelsPerMeter */ put_dword(fp, 2953 /* 75 dpi */); /* DWORD biClrUsed */ put_dword(fp, 0); /* DWORD biClrImportant */ put_dword(fp, 0); /* struct RGBQUAD (16 * 4 = 64 bytes) */ /* CGA-compatible colors: */ /* 0x00 = black */ put_dword(fp, 0x000000); /* 0x01 = blue */ put_dword(fp, 0x000080); /* 0x02 = green */ put_dword(fp, 0x008000); /* 0x03 = cyan */ put_dword(fp, 0x008080); /* 0x04 = red */ put_dword(fp, 0x800000); /* 0x05 = magenta */ put_dword(fp, 0x800080); /* 0x06 = brown */ put_dword(fp, 0x808000); /* 0x07 = light gray */ put_dword(fp, 0xC0C0C0); /* 0x08 = dark gray */ put_dword(fp, 0x808080); /* 0x09 = bright blue */ put_dword(fp, 0x0000FF); /* 0x0A = bright green */ put_dword(fp, 0x00FF00); /* 0x0B = bright cyan */ put_dword(fp, 0x00FFFF); /* 0x0C = bright red */ put_dword(fp, 0xFF0000); /* 0x0D = bright magenta */ put_dword(fp, 0xFF00FF); /* 0x0E = yellow */ put_dword(fp, 0xFFFF00); /* 0x0F = white */ put_dword(fp, 0xFFFFFF); /* pixel data bits */ b = 0; for (i = m - 1; i >= 0; i--) { for (j = 0; j < ((n + 7) / 8) * 8; j++) { b <<= 4; b |= (j < n ? map[i * n + j] & 15 : 0); if (j & 1) put_byte(fp, b); } } fflush(fp); if (ferror(fp)) { xprintf("rgr_write_bmp16: write error on `%s' - %s\n", fname, strerror(errno)); ret = 1; } fini: if (fp != NULL) fclose(fp); return ret; } /* eof */ Rglpk/src/GLPK/glpsql.c0000644000176000001440000013200512245352174014361 0ustar ripleyusers/* glpsql.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Author: Heinrich Schuchardt . * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include "glpmpl.h" #include "glpsql.h" #ifdef ODBC_DLNAME #define HAVE_ODBC #define libodbc ODBC_DLNAME #define h_odbc (get_env_ptr()->h_odbc) #endif #ifdef MYSQL_DLNAME #define HAVE_MYSQL #define libmysql MYSQL_DLNAME #define h_mysql (get_env_ptr()->h_mysql) #endif static void *db_iodbc_open_int(TABDCA *dca, int mode, const char **sqllines); static void *db_mysql_open_int(TABDCA *dca, int mode, const char **sqllines); /**********************************************************************/ #if defined(HAVE_ODBC) || defined(HAVE_MYSQL) #define SQL_FIELD_MAX 100 /* maximal field count */ #define SQL_FDLEN_MAX 255 /* maximal field length */ /*********************************************************************** * NAME * * args_concat - concatenate arguments * * SYNOPSIS * * static char **args_concat(TABDCA *dca); * * DESCRIPTION * * The arguments passed in dca are SQL statements. A SQL statement may * be split over multiple arguments. The last argument of a SQL * statement will be terminated with a semilocon. Each SQL statement is * merged into a single zero terminated string. Boundaries between * arguments are replaced by space. * * RETURNS * * Buffer with SQL statements */ static char **args_concat(TABDCA *dca) { const char *arg; int i; int j; int j0; int j1; int len; int lentot; int narg; int nline = 0; void *ret; char **sqllines = NULL; narg = mpl_tab_num_args(dca); /* The SQL statements start with argument 3. */ if (narg < 3) return NULL; /* Count the SQL statements */ for (j = 3; j <= narg; j++) { arg = mpl_tab_get_arg(dca, j); len = strlen(arg); if (arg[len-1] == ';' || j == narg) nline ++; } /* Allocate string buffer. */ sqllines = (char **) xmalloc((nline+1) * sizeof(char **)); /* Join arguments */ sqllines[0] = NULL; j0 = 3; i = 0; lentot = 0; for (j = 3; j <= narg; j++) { arg = mpl_tab_get_arg(dca, j); len = strlen(arg); /* add length of part */ lentot += len; /* add length of space separating parts or 0x00 at end of SQL statement */ lentot++; if (arg[len-1] == ';' || j == narg) { /* Join arguments for a single SQL statement */ sqllines[i] = xmalloc(lentot); sqllines[i+1] = NULL; sqllines[i][0] = 0x00; for (j1 = j0; j1 <= j; j1++) { if(j1>j0) strcat(sqllines[i], " "); strcat(sqllines[i], mpl_tab_get_arg(dca, j1)); } len = strlen(sqllines[i]); if (sqllines[i][len-1] == ';') sqllines[i][len-1] = 0x00; j0 = j+1; i++; lentot = 0; } } return sqllines; } /*********************************************************************** * NAME * * free_buffer - free multiline string buffer * * SYNOPSIS * * static void free_buffer(char **buf); * * DESCRIPTION * * buf is a list of strings terminated by NULL. * The memory for the strings and for the list is released. */ static void free_buffer(char **buf) { int i; for(i = 0; buf[i] != NULL; i++) xfree(buf[i]); xfree(buf); } static int db_escaped_string_length(const char* from) /* length of escaped string */ { int count; const char *pointer; for (pointer = from, count = 0; *pointer != (char) '\0'; pointer++, count++) { switch (*pointer) { case '\'': count++; break; } } return count; } static int db_escape_string (char *to, const char *from) /* escape string*/ { const char *source = from; char *target = to; unsigned int remaining; remaining = strlen(from); if (to == NULL) to = (char *) (from + remaining); while (remaining > 0) { switch (*source) { case '\'': *target = '\''; target++; *target = '\''; break; default: *target = *source; } source++; target++; remaining--; } /* Write the terminating NUL character. */ *target = '\0'; return target - to; } static char *db_generate_select_stmt(TABDCA *dca) /* generate select statement */ { char *arg; char const *field; char *query; int j; int narg; int nf; int total; total = 50; nf = mpl_tab_num_flds(dca); narg = mpl_tab_num_args(dca); for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++) { field = mpl_tab_get_name(dca, j); total += strlen(field); total += 2; } arg = (char *) mpl_tab_get_arg(dca, narg); total += strlen(arg); query = xmalloc( total * sizeof(char)); strcpy (query, "SELECT "); for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++) { field = mpl_tab_get_name(dca, j); strcat(query, field); if ( j < nf ) strcat(query, ", "); } strcat(query, " FROM "); strcat(query, arg); return query; } static char *db_generate_insert_stmt(TABDCA *dca) /* generate insert statement */ { char *arg; char const *field; char *query; int j; int narg; int nf; int total; total = 50; nf = mpl_tab_num_flds(dca); narg = mpl_tab_num_args(dca); for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++) { field = mpl_tab_get_name(dca, j); total += strlen(field); total += 5; } arg = (char *) mpl_tab_get_arg(dca, narg); total += strlen(arg); query = xmalloc( (total+1) * sizeof(char)); strcpy (query, "INSERT INTO "); strcat(query, arg); strcat(query, " ( "); for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++) { field = mpl_tab_get_name(dca, j); strcat(query, field); if ( j < nf ) strcat(query, ", "); } strcat(query, " ) VALUES ( "); for (j=1; j <= nf && j <= SQL_FIELD_MAX; j++) { strcat(query, "?"); if ( j < nf ) strcat(query, ", "); } strcat(query, " )"); return query; } #endif /**********************************************************************/ #ifndef HAVE_ODBC void *db_iodbc_open(TABDCA *dca, int mode) { xassert(dca == dca); xassert(mode == mode); xprintf("iODBC table driver not supported\n"); return NULL; } int db_iodbc_read(TABDCA *dca, void *link) { xassert(dca != dca); xassert(link != link); return 0; } int db_iodbc_write(TABDCA *dca, void *link) { xassert(dca != dca); xassert(link != link); return 0; } int db_iodbc_close(TABDCA *dca, void *link) { xassert(dca != dca); xassert(link != link); return 0; } #else #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WOE__) #include #endif #include #include struct db_odbc { int mode; /*'R' = Read, 'W' = Write*/ SQLHDBC hdbc; /*connection handle*/ SQLHENV henv; /*environment handle*/ SQLHSTMT hstmt; /*statement handle*/ SQLSMALLINT nresultcols; /* columns in result*/ SQLULEN collen[SQL_FIELD_MAX+1]; SQLLEN outlen[SQL_FIELD_MAX+1]; SQLSMALLINT coltype[SQL_FIELD_MAX+1]; SQLCHAR data[SQL_FIELD_MAX+1][SQL_FDLEN_MAX+1]; SQLCHAR colname[SQL_FIELD_MAX+1][SQL_FDLEN_MAX+1]; int isnumeric[SQL_FIELD_MAX+1]; int nf; /* number of fields in the csv file */ int ref[1+SQL_FIELD_MAX]; /* ref[k] = k', if k-th field of the csv file corresponds to k'-th field in the table statement; if ref[k] = 0, k-th field of the csv file is ignored */ SQLCHAR *query; /* query generated by db_iodbc_open */ }; SQLRETURN SQL_API dl_SQLAllocHandle ( SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE *OutputHandle) { typedef SQLRETURN SQL_API ep_SQLAllocHandle( SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE *OutputHandle); ep_SQLAllocHandle *fn; fn = (ep_SQLAllocHandle *) xdlsym(h_odbc, "SQLAllocHandle"); xassert(fn != NULL); return (*fn)(HandleType, InputHandle, OutputHandle); } SQLRETURN SQL_API dl_SQLBindCol ( SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLPOINTER TargetValue, SQLLEN BufferLength, SQLLEN *StrLen_or_Ind) { typedef SQLRETURN SQL_API ep_SQLBindCol( SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLPOINTER TargetValue, SQLLEN BufferLength, SQLLEN *StrLen_or_Ind); ep_SQLBindCol *fn; fn = (ep_SQLBindCol *) xdlsym(h_odbc, "SQLBindCol"); xassert(fn != NULL); return (*fn)(StatementHandle, ColumnNumber, TargetType, TargetValue, BufferLength, StrLen_or_Ind); } SQLRETURN SQL_API dl_SQLCloseCursor ( SQLHSTMT StatementHandle) { typedef SQLRETURN SQL_API ep_SQLCloseCursor ( SQLHSTMT StatementHandle); ep_SQLCloseCursor *fn; fn = (ep_SQLCloseCursor *) xdlsym(h_odbc, "SQLCloseCursor"); xassert(fn != NULL); return (*fn)(StatementHandle); } SQLRETURN SQL_API dl_SQLDisconnect ( SQLHDBC ConnectionHandle) { typedef SQLRETURN SQL_API ep_SQLDisconnect( SQLHDBC ConnectionHandle); ep_SQLDisconnect *fn; fn = (ep_SQLDisconnect *) xdlsym(h_odbc, "SQLDisconnect"); xassert(fn != NULL); return (*fn)(ConnectionHandle); } SQLRETURN SQL_API dl_SQLDriverConnect ( SQLHDBC hdbc, SQLHWND hwnd, SQLCHAR *szConnStrIn, SQLSMALLINT cbConnStrIn, SQLCHAR *szConnStrOut, SQLSMALLINT cbConnStrOutMax, SQLSMALLINT *pcbConnStrOut, SQLUSMALLINT fDriverCompletion) { typedef SQLRETURN SQL_API ep_SQLDriverConnect( SQLHDBC hdbc, SQLHWND hwnd, SQLCHAR * szConnStrIn, SQLSMALLINT cbConnStrIn, SQLCHAR * szConnStrOut, SQLSMALLINT cbConnStrOutMax, SQLSMALLINT * pcbConnStrOut, SQLUSMALLINT fDriverCompletion); ep_SQLDriverConnect *fn; fn = (ep_SQLDriverConnect *) xdlsym(h_odbc, "SQLDriverConnect"); xassert(fn != NULL); return (*fn)(hdbc, hwnd, szConnStrIn, cbConnStrIn, szConnStrOut, cbConnStrOutMax, pcbConnStrOut, fDriverCompletion); } SQLRETURN SQL_API dl_SQLEndTran ( SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMALLINT CompletionType) { typedef SQLRETURN SQL_API ep_SQLEndTran ( SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMALLINT CompletionType); ep_SQLEndTran *fn; fn = (ep_SQLEndTran *) xdlsym(h_odbc, "SQLEndTran"); xassert(fn != NULL); return (*fn)(HandleType, Handle, CompletionType); } SQLRETURN SQL_API dl_SQLExecDirect ( SQLHSTMT StatementHandle, SQLCHAR * StatementText, SQLINTEGER TextLength) { typedef SQLRETURN SQL_API ep_SQLExecDirect ( SQLHSTMT StatementHandle, SQLCHAR * StatementText, SQLINTEGER TextLength); ep_SQLExecDirect *fn; fn = (ep_SQLExecDirect *) xdlsym(h_odbc, "SQLExecDirect"); xassert(fn != NULL); return (*fn)(StatementHandle, StatementText, TextLength); } SQLRETURN SQL_API dl_SQLFetch ( SQLHSTMT StatementHandle) { typedef SQLRETURN SQL_API ep_SQLFetch ( SQLHSTMT StatementHandle); ep_SQLFetch *fn; fn = (ep_SQLFetch*) xdlsym(h_odbc, "SQLFetch"); xassert(fn != NULL); return (*fn)(StatementHandle); } SQLRETURN SQL_API dl_SQLFreeHandle ( SQLSMALLINT HandleType, SQLHANDLE Handle) { typedef SQLRETURN SQL_API ep_SQLFreeHandle ( SQLSMALLINT HandleType, SQLHANDLE Handle); ep_SQLFreeHandle *fn; fn = (ep_SQLFreeHandle *) xdlsym(h_odbc, "SQLFreeHandle"); xassert(fn != NULL); return (*fn)(HandleType, Handle); } SQLRETURN SQL_API dl_SQLDescribeCol ( SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLCHAR * ColumnName, SQLSMALLINT BufferLength, SQLSMALLINT * NameLength, SQLSMALLINT * DataType, SQLULEN * ColumnSize, SQLSMALLINT * DecimalDigits, SQLSMALLINT * Nullable) { typedef SQLRETURN SQL_API ep_SQLDescribeCol ( SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLCHAR *ColumnName, SQLSMALLINT BufferLength, SQLSMALLINT *NameLength, SQLSMALLINT *DataType, SQLULEN *ColumnSize, SQLSMALLINT *DecimalDigits, SQLSMALLINT *Nullable); ep_SQLDescribeCol *fn; fn = (ep_SQLDescribeCol *) xdlsym(h_odbc, "SQLDescribeCol"); xassert(fn != NULL); return (*fn)(StatementHandle, ColumnNumber, ColumnName, BufferLength, NameLength, DataType, ColumnSize, DecimalDigits, Nullable); } SQLRETURN SQL_API dl_SQLGetDiagRec ( SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMALLINT RecNumber, SQLCHAR *Sqlstate, SQLINTEGER *NativeError, SQLCHAR *MessageText, SQLSMALLINT BufferLength, SQLSMALLINT *TextLength) { typedef SQLRETURN SQL_API ep_SQLGetDiagRec ( SQLSMALLINT HandleType, SQLHANDLE Handle, SQLSMALLINT RecNumber, SQLCHAR *Sqlstate, SQLINTEGER *NativeError, SQLCHAR *MessageText, SQLSMALLINT BufferLength, SQLSMALLINT *TextLength); ep_SQLGetDiagRec *fn; fn = (ep_SQLGetDiagRec *) xdlsym(h_odbc, "SQLGetDiagRec"); xassert(fn != NULL); return (*fn)(HandleType, Handle, RecNumber, Sqlstate, NativeError, MessageText, BufferLength, TextLength); } SQLRETURN SQL_API dl_SQLGetInfo ( SQLHDBC ConnectionHandle, SQLUSMALLINT InfoType, SQLPOINTER InfoValue, SQLSMALLINT BufferLength, SQLSMALLINT *StringLength) { typedef SQLRETURN SQL_API ep_SQLGetInfo ( SQLHDBC ConnectionHandle, SQLUSMALLINT InfoType, SQLPOINTER InfoValue, SQLSMALLINT BufferLength, SQLSMALLINT *StringLength); ep_SQLGetInfo *fn; fn = (ep_SQLGetInfo *) xdlsym(h_odbc, "SQLGetInfo"); xassert(fn != NULL); return (*fn)(ConnectionHandle, InfoType, InfoValue, BufferLength, StringLength); } SQLRETURN SQL_API dl_SQLNumResultCols ( SQLHSTMT StatementHandle, SQLSMALLINT *ColumnCount) { typedef SQLRETURN SQL_API ep_SQLNumResultCols ( SQLHSTMT StatementHandle, SQLSMALLINT *ColumnCount); ep_SQLNumResultCols *fn; fn = (ep_SQLNumResultCols *) xdlsym(h_odbc, "SQLNumResultCols"); xassert(fn != NULL); return (*fn)(StatementHandle, ColumnCount); } SQLRETURN SQL_API dl_SQLSetConnectAttr ( SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER StringLength) { typedef SQLRETURN SQL_API ep_SQLSetConnectAttr ( SQLHDBC ConnectionHandle, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER StringLength); ep_SQLSetConnectAttr *fn; fn = (ep_SQLSetConnectAttr *) xdlsym(h_odbc, "SQLSetConnectAttr"); xassert(fn != NULL); return (*fn)(ConnectionHandle, Attribute, Value, StringLength); } SQLRETURN SQL_API dl_SQLSetEnvAttr ( SQLHENV EnvironmentHandle, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER StringLength) { typedef SQLRETURN SQL_API ep_SQLSetEnvAttr ( SQLHENV EnvironmentHandle, SQLINTEGER Attribute, SQLPOINTER Value, SQLINTEGER StringLength); ep_SQLSetEnvAttr *fn; fn = (ep_SQLSetEnvAttr *) xdlsym(h_odbc, "SQLSetEnvAttr"); xassert(fn != NULL); return (*fn)(EnvironmentHandle, Attribute, Value, StringLength); } static void extract_error( char *fn, SQLHANDLE handle, SQLSMALLINT type); static int is_numeric( SQLSMALLINT coltype); /*********************************************************************** * NAME * * db_iodbc_open - open connection to ODBC data base * * SYNOPSIS * * #include "glpsql.h" * void *db_iodbc_open(TABDCA *dca, int mode); * * DESCRIPTION * * The routine db_iodbc_open opens a connection to an ODBC data base. * It then executes the sql statements passed. * * In the case of table read the SELECT statement is executed. * * In the case of table write the INSERT statement is prepared. * RETURNS * * The routine returns a pointer to data storage area created. */ void *db_iodbc_open(TABDCA *dca, int mode) { void *ret; char **sqllines; sqllines = args_concat(dca); if (sqllines == NULL) { xprintf("Missing arguments in table statement.\n" "Please, supply table driver, dsn, and query.\n"); return NULL; } ret = db_iodbc_open_int(dca, mode, (const char **) sqllines); free_buffer(sqllines); return ret; } static void *db_iodbc_open_int(TABDCA *dca, int mode, const char **sqllines) { struct db_odbc *sql; SQLRETURN ret; SQLCHAR FAR *dsn; SQLCHAR info[256]; SQLSMALLINT colnamelen; SQLSMALLINT nullable; SQLSMALLINT scale; const char *arg; int narg; int i, j; int total; if (libodbc == NULL) { xprintf("No loader for shared ODBC library available\n"); return NULL; } if (h_odbc == NULL) { h_odbc = xdlopen(libodbc); if (h_odbc == NULL) { xprintf("unable to open library %s\n", libodbc); xprintf("%s\n", xerrmsg()); return NULL; } } sql = (struct db_odbc *) xmalloc(sizeof(struct db_odbc)); if (sql == NULL) return NULL; sql->mode = mode; sql->hdbc = NULL; sql->henv = NULL; sql->hstmt = NULL; sql->query = NULL; narg = mpl_tab_num_args(dca); dsn = (SQLCHAR FAR *) mpl_tab_get_arg(dca, 2); /* allocate an environment handle */ ret = dl_SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(sql->henv)); /* set attribute to enable application to run as ODBC 3.0 application */ ret = dl_SQLSetEnvAttr(sql->henv, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); /* allocate a connection handle */ ret = dl_SQLAllocHandle(SQL_HANDLE_DBC, sql->henv, &(sql->hdbc)); /* connect */ ret = dl_SQLDriverConnect(sql->hdbc, NULL, dsn, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE); if (SQL_SUCCEEDED(ret)) { /* output information about data base connection */ xprintf("Connected to "); dl_SQLGetInfo(sql->hdbc, SQL_DBMS_NAME, (SQLPOINTER)info, sizeof(info), NULL); xprintf("%s ", info); dl_SQLGetInfo(sql->hdbc, SQL_DBMS_VER, (SQLPOINTER)info, sizeof(info), NULL); xprintf("%s - ", info); dl_SQLGetInfo(sql->hdbc, SQL_DATABASE_NAME, (SQLPOINTER)info, sizeof(info), NULL); xprintf("%s\n", info); } else { /* describe error */ xprintf("Failed to connect\n"); extract_error("SQLDriverConnect", sql->hdbc, SQL_HANDLE_DBC); dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc); dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv); xfree(sql); return NULL; } /* set AUTOCOMMIT on*/ ret = dl_SQLSetConnectAttr(sql->hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, 0); /* allocate a statement handle */ ret = dl_SQLAllocHandle(SQL_HANDLE_STMT, sql->hdbc, &(sql->hstmt)); /* initialization queries */ for(j = 0; sqllines[j+1] != NULL; j++) { sql->query = (SQLCHAR *) sqllines[j]; xprintf("%s\n", sql->query); ret = dl_SQLExecDirect(sql->hstmt, sql->query, SQL_NTS); switch (ret) { case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO: case SQL_NO_DATA_FOUND: break; default: xprintf("db_iodbc_open: Query\n\"%s\"\nfailed.\n", sql->query); extract_error("SQLExecDirect", sql->hstmt, SQL_HANDLE_STMT); dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt); dl_SQLDisconnect(sql->hdbc); dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc); dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv); xfree(sql); return NULL; } /* commit statement */ dl_SQLEndTran(SQL_HANDLE_ENV, sql->henv, SQL_COMMIT); } if ( sql->mode == 'R' ) { sql->nf = mpl_tab_num_flds(dca); for(j = 0; sqllines[j] != NULL; j++) arg = sqllines[j]; total = strlen(arg); if (total > 7 && 0 == strncmp(arg, "SELECT ", 7)) { total = strlen(arg); sql->query = xmalloc( (total+1) * sizeof(char)); strcpy (sql->query, arg); } else { sql->query = db_generate_select_stmt(dca); } xprintf("%s\n", sql->query); if (dl_SQLExecDirect(sql->hstmt, sql->query, SQL_NTS) != SQL_SUCCESS) { xprintf("db_iodbc_open: Query\n\"%s\"\nfailed.\n", sql->query); extract_error("SQLExecDirect", sql->hstmt, SQL_HANDLE_STMT); dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt); dl_SQLDisconnect(sql->hdbc); dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc); dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv); xfree(sql->query); xfree(sql); return NULL; } xfree(sql->query); /* determine number of result columns */ ret = dl_SQLNumResultCols(sql->hstmt, &sql->nresultcols); total = sql->nresultcols; if (total > SQL_FIELD_MAX) { xprintf("db_iodbc_open: Too many fields (> %d) in query.\n" "\"%s\"\n", SQL_FIELD_MAX, sql->query); dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt); dl_SQLDisconnect(sql->hdbc); dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc); dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv); xfree(sql->query); return NULL; } for (i = 1; i <= total; i++) { /* return a set of attributes for a column */ ret = dl_SQLDescribeCol(sql->hstmt, (SQLSMALLINT) i, sql->colname[i], SQL_FDLEN_MAX, &colnamelen, &(sql->coltype[i]), &(sql->collen[i]), &scale, &nullable); sql->isnumeric[i] = is_numeric(sql->coltype[i]); /* bind columns to program vars, converting all types to CHAR*/ if (sql->isnumeric[i]) { dl_SQLBindCol(sql->hstmt, i, SQL_DOUBLE, sql->data[i], SQL_FDLEN_MAX, &(sql->outlen[i])); } else { dl_SQLBindCol(sql->hstmt, i, SQL_CHAR, sql->data[i], SQL_FDLEN_MAX, &(sql->outlen[i])); } for (j = sql->nf; j >= 1; j--) { if (strcmp(mpl_tab_get_name(dca, j), sql->colname[i]) == 0) break; } sql->ref[i] = j; } } else if ( sql->mode == 'W' ) { for(j = 0; sqllines[j] != NULL; j++) arg = sqllines[j]; if ( NULL != strchr(arg, '?') ) { total = strlen(arg); sql->query = xmalloc( (total+1) * sizeof(char)); strcpy (sql->query, arg); } else { sql->query = db_generate_insert_stmt(dca); } xprintf("%s\n", sql->query); } return sql; } int db_iodbc_read(TABDCA *dca, void *link) { struct db_odbc *sql; SQLRETURN ret; char buf[SQL_FDLEN_MAX+1]; int i; int len; double num; sql = (struct db_odbc *) link; xassert(sql != NULL); xassert(sql->mode == 'R'); ret=dl_SQLFetch(sql->hstmt); if (ret== SQL_ERROR) return -1; if (ret== SQL_NO_DATA_FOUND) return -1; /*EOF*/ for (i=1; i <= sql->nresultcols; i++) { if (sql->ref[i] > 0) { len = sql->outlen[i]; if (len != SQL_NULL_DATA) { if (sql->isnumeric[i]) { mpl_tab_set_num(dca, sql->ref[i], *((const double *) sql->data[i])); } else { if (len > SQL_FDLEN_MAX) len = SQL_FDLEN_MAX; else if (len < 0) len = 0; strncpy(buf, (const char *) sql->data[i], len); buf[len] = 0x00; mpl_tab_set_str(dca, sql->ref[i], strtrim(buf)); } } } } return 0; } int db_iodbc_write(TABDCA *dca, void *link) { struct db_odbc *sql; char *part; char *query; char *template; char num[50]; int k; int len; int nf; sql = (struct db_odbc *) link; xassert(sql != NULL); xassert(sql->mode == 'W'); len = strlen(sql->query); template = (char *) xmalloc( (len + 1) * sizeof(char) ); strcpy(template, sql->query); nf = mpl_tab_num_flds(dca); for (k = 1; k <= nf; k++) { switch (mpl_tab_get_type(dca, k)) { case 'N': len += 20; break; case 'S': len += db_escaped_string_length(mpl_tab_get_str(dca, k)); len += 2; break; default: xassert(dca != dca); } } query = xmalloc( (len + 1 ) * sizeof(char) ); query[0] = 0x00; for (k = 1, part = strtok (template, "?"); (part != NULL); part = strtok (NULL, "?"), k++) { if (k > nf) break; strcat( query, part ); switch (mpl_tab_get_type(dca, k)) { case 'N': #if 0 /* 02/XI-2010 by xypron */ sprintf(num, "%-18g",mpl_tab_get_num(dca, k)); #else sprintf(num, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k)); #endif strcat( query, num ); break; case 'S': strcat( query, "'"); db_escape_string( query + strlen(query), mpl_tab_get_str(dca, k) ); strcat( query, "'"); break; default: xassert(dca != dca); } } if (part != NULL) strcat(query, part); if (dl_SQLExecDirect(sql->hstmt, (SQLCHAR *) query, SQL_NTS) != SQL_SUCCESS) { xprintf("db_iodbc_write: Query\n\"%s\"\nfailed.\n", query); extract_error("SQLExecDirect", sql->hdbc, SQL_HANDLE_DBC); xfree(query); xfree(template); return 1; } xfree(query); xfree(template); return 0; } int db_iodbc_close(TABDCA *dca, void *link) { struct db_odbc *sql; sql = (struct db_odbc *) link; xassert(sql != NULL); /* Commit */ if ( sql->mode == 'W' ) dl_SQLEndTran(SQL_HANDLE_ENV, sql->henv, SQL_COMMIT); if ( sql->mode == 'R' ) dl_SQLCloseCursor(sql->hstmt); dl_SQLFreeHandle(SQL_HANDLE_STMT, sql->hstmt); dl_SQLDisconnect(sql->hdbc); dl_SQLFreeHandle(SQL_HANDLE_DBC, sql->hdbc); dl_SQLFreeHandle(SQL_HANDLE_ENV, sql->henv); if ( sql->mode == 'W' ) xfree(sql->query); xfree(sql); dca->link = NULL; return 0; } static void extract_error( char *fn, SQLHANDLE handle, SQLSMALLINT type) { SQLINTEGER i = 0; SQLINTEGER native; SQLCHAR state[ 7 ]; SQLCHAR text[256]; SQLSMALLINT len; SQLRETURN ret; xprintf("\nThe driver reported the following diagnostics whilst " "running %s\n", fn); do { ret = dl_SQLGetDiagRec(type, handle, ++i, state, &native, text, sizeof(text), &len ); if (SQL_SUCCEEDED(ret)) xprintf("%s:%ld:%ld:%s\n", state, i, native, text); } while( ret == SQL_SUCCESS ); } static int is_numeric(SQLSMALLINT coltype) { int ret = 0; switch (coltype) { case SQL_DECIMAL: case SQL_NUMERIC: case SQL_SMALLINT: case SQL_INTEGER: case SQL_REAL: case SQL_FLOAT: case SQL_DOUBLE: case SQL_TINYINT: case SQL_BIGINT: ret = 1; break; } return ret; } #endif /**********************************************************************/ #ifndef HAVE_MYSQL void *db_mysql_open(TABDCA *dca, int mode) { xassert(dca == dca); xassert(mode == mode); xprintf("MySQL table driver not supported\n"); return NULL; } int db_mysql_read(TABDCA *dca, void *link) { xassert(dca != dca); xassert(link != link); return 0; } int db_mysql_write(TABDCA *dca, void *link) { xassert(dca != dca); xassert(link != link); return 0; } int db_mysql_close(TABDCA *dca, void *link) { xassert(dca != dca); xassert(link != link); return 0; } #else #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__WOE__) #include #endif #ifdef __CYGWIN__ #define byte_defined 1 #endif #include #include #include struct db_mysql { int mode; /*'R' = Read, 'W' = Write*/ MYSQL *con; /*connection*/ MYSQL_RES *res; /*result*/ int nf; /* number of fields in the csv file */ int ref[1+SQL_FIELD_MAX]; /* ref[k] = k', if k-th field of the csv file corresponds to k'-th field in the table statement; if ref[k] = 0, k-th field of the csv file is ignored */ char *query; /* query generated by db_mysql_open */ }; void STDCALL dl_mysql_close(MYSQL *sock) { typedef void STDCALL ep_mysql_close(MYSQL *sock); ep_mysql_close *fn; fn = (ep_mysql_close *) xdlsym(h_mysql, "mysql_close"); xassert(fn != NULL); return (*fn)(sock); } const char * STDCALL dl_mysql_error(MYSQL *mysql) { typedef const char * STDCALL ep_mysql_error(MYSQL *mysql); ep_mysql_error *fn; fn = (ep_mysql_error *) xdlsym(h_mysql, "mysql_error"); xassert(fn != NULL); return (*fn)(mysql); } MYSQL_FIELD * STDCALL dl_mysql_fetch_fields(MYSQL_RES *res) { typedef MYSQL_FIELD * STDCALL ep_mysql_fetch_fields(MYSQL_RES *res); ep_mysql_fetch_fields *fn; fn = (ep_mysql_fetch_fields *) xdlsym(h_mysql, "mysql_fetch_fields"); xassert(fn != NULL); return (*fn)(res); } unsigned long * STDCALL dl_mysql_fetch_lengths(MYSQL_RES *result) { typedef unsigned long * STDCALL ep_mysql_fetch_lengths(MYSQL_RES *result); ep_mysql_fetch_lengths *fn; fn = (ep_mysql_fetch_lengths *) xdlsym(h_mysql, "mysql_fetch_lengths"); xassert(fn != NULL); return (*fn)(result); } MYSQL_ROW STDCALL dl_mysql_fetch_row(MYSQL_RES *result) { typedef MYSQL_ROW STDCALL ep_mysql_fetch_row(MYSQL_RES *result); ep_mysql_fetch_row *fn; fn = (ep_mysql_fetch_row *) xdlsym(h_mysql, "mysql_fetch_row"); xassert(fn != NULL); return (*fn)(result); } unsigned int STDCALL dl_mysql_field_count(MYSQL *mysql) { typedef unsigned int STDCALL ep_mysql_field_count(MYSQL *mysql); ep_mysql_field_count *fn; fn = (ep_mysql_field_count *) xdlsym(h_mysql, "mysql_field_count"); xassert(fn != NULL); return (*fn)(mysql); } MYSQL * STDCALL dl_mysql_init(MYSQL *mysql) { typedef MYSQL * STDCALL ep_mysql_init(MYSQL *mysql); ep_mysql_init *fn; fn = (ep_mysql_init *) xdlsym(h_mysql, "mysql_init"); xassert(fn != NULL); return (*fn)(mysql); } unsigned int STDCALL dl_mysql_num_fields(MYSQL_RES *res) { typedef unsigned int STDCALL ep_mysql_num_fields(MYSQL_RES *res); ep_mysql_num_fields *fn; fn = (ep_mysql_num_fields *) xdlsym(h_mysql, "mysql_num_fields"); xassert(fn != NULL); return (*fn)(res); } int STDCALL dl_mysql_query(MYSQL *mysql, const char *q) { typedef int STDCALL ep_mysql_query(MYSQL *mysql, const char *q); ep_mysql_query *fn; fn = (ep_mysql_query *) xdlsym(h_mysql, "mysql_query"); xassert(fn != NULL); return (*fn)(mysql, q); } MYSQL * STDCALL dl_mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag) { typedef MYSQL * STDCALL ep_mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag); ep_mysql_real_connect *fn; fn = (ep_mysql_real_connect *) xdlsym(h_mysql, "mysql_real_connect"); xassert(fn != NULL); return (*fn)(mysql, host, user, passwd, db, port, unix_socket, clientflag); } MYSQL_RES * STDCALL dl_mysql_use_result(MYSQL *mysql) { typedef MYSQL_RES * STDCALL ep_mysql_use_result(MYSQL *mysql); ep_mysql_use_result *fn; fn = (ep_mysql_use_result *) xdlsym(h_mysql, "mysql_use_result"); xassert(fn != NULL); return (*fn)(mysql); } /*********************************************************************** * NAME * * db_mysql_open - open connection to ODBC data base * * SYNOPSIS * * #include "glpsql.h" * void *db_mysql_open(TABDCA *dca, int mode); * * DESCRIPTION * * The routine db_mysql_open opens a connection to a MySQL data base. * It then executes the sql statements passed. * * In the case of table read the SELECT statement is executed. * * In the case of table write the INSERT statement is prepared. * RETURNS * * The routine returns a pointer to data storage area created. */ void *db_mysql_open(TABDCA *dca, int mode) { void *ret; char **sqllines; sqllines = args_concat(dca); if (sqllines == NULL) { xprintf("Missing arguments in table statement.\n" "Please, supply table driver, dsn, and query.\n"); return NULL; } ret = db_mysql_open_int(dca, mode, (const char **) sqllines); free_buffer(sqllines); return ret; } static void *db_mysql_open_int(TABDCA *dca, int mode, const char **sqllines) { struct db_mysql *sql = NULL; char *arg = NULL; const char *field; MYSQL_FIELD *fields; char *keyword; char *value; char *query; char *dsn; /* "Server=[server_name];Database=[database_name];UID=[username];*/ /* PWD=[password];Port=[port]"*/ char *server = NULL; /* Server */ char *user = NULL; /* UID */ char *password = NULL; /* PWD */ char *database = NULL; /* Database */ unsigned int port = 0; /* Port */ int narg; int i, j, total; if (libmysql == NULL) { xprintf("No loader for shared MySQL library available\n"); return NULL; } if (h_mysql == NULL) { h_mysql = xdlopen(libmysql); if (h_mysql == NULL) { xprintf("unable to open library %s\n", libmysql); xprintf("%s\n", xerrmsg()); return NULL; } } sql = (struct db_mysql *) xmalloc(sizeof(struct db_mysql)); if (sql == NULL) return NULL; sql->mode = mode; sql->res = NULL; sql->query = NULL; sql->nf = mpl_tab_num_flds(dca); narg = mpl_tab_num_args(dca); if (narg < 3 ) xprintf("MySQL driver: string list too short \n"); /* get connection string*/ dsn = (char *) mpl_tab_get_arg(dca, 2); /* copy connection string*/ i = strlen(dsn); i++; arg = xmalloc(i * sizeof(char)); strcpy(arg, dsn); /*tokenize connection string*/ for (i = 1, keyword = strtok (arg, "="); (keyword != NULL); keyword = strtok (NULL, "="), i++) { value = strtok (NULL, ";"); if (value==NULL) { xprintf("db_mysql_open: Missing value for keyword %s\n", keyword); xfree(arg); xfree(sql); return NULL; } if (0 == strcmp(keyword, "Server")) server = value; else if (0 == strcmp(keyword, "Database")) database = value; else if (0 == strcmp(keyword, "UID")) user = value; else if (0 == strcmp(keyword, "PWD")) password = value; else if (0 == strcmp(keyword, "Port")) port = (unsigned int) atol(value); } /* Connect to database */ sql->con = dl_mysql_init(NULL); if (!dl_mysql_real_connect(sql->con, server, user, password, database, port, NULL, 0)) { xprintf("db_mysql_open: Connect failed\n"); xprintf("%s\n", dl_mysql_error(sql->con)); xfree(arg); xfree(sql); return NULL; } xfree(arg); for(j = 0; sqllines[j+1] != NULL; j++) { query = (char *) sqllines[j]; xprintf("%s\n", query); if (dl_mysql_query(sql->con, query)) { xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query); xprintf("%s\n",dl_mysql_error(sql->con)); dl_mysql_close(sql->con); xfree(sql); return NULL; } } if ( sql->mode == 'R' ) { sql->nf = mpl_tab_num_flds(dca); for(j = 0; sqllines[j] != NULL; j++) arg = (char *) sqllines[j]; total = strlen(arg); if (total > 7 && 0 == strncmp(arg, "SELECT ", 7)) { total = strlen(arg); query = xmalloc( (total+1) * sizeof(char)); strcpy (query, arg); } else { query = db_generate_select_stmt(dca); } xprintf("%s\n", query); if (dl_mysql_query(sql->con, query)) { xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query); xprintf("%s\n",dl_mysql_error(sql->con)); dl_mysql_close(sql->con); xfree(query); xfree(sql); return NULL; } xfree(query); sql->res = dl_mysql_use_result(sql->con); if (sql->res) { /* create references between query results and table fields*/ total = dl_mysql_num_fields(sql->res); if (total > SQL_FIELD_MAX) { xprintf("db_mysql_open: Too many fields (> %d) in query.\n" "\"%s\"\n", SQL_FIELD_MAX, query); xprintf("%s\n",dl_mysql_error(sql->con)); dl_mysql_close(sql->con); xfree(query); xfree(sql); return NULL; } fields = dl_mysql_fetch_fields(sql->res); for (i = 1; i <= total; i++) { for (j = sql->nf; j >= 1; j--) { if (strcmp(mpl_tab_get_name(dca, j), fields[i-1].name) == 0) break; } sql->ref[i] = j; } } else { if(dl_mysql_field_count(sql->con) == 0) { xprintf("db_mysql_open: Query was not a SELECT\n\"%s\"\n", query); xprintf("%s\n",dl_mysql_error(sql->con)); xfree(query); xfree(sql); return NULL; } else { xprintf("db_mysql_open: Query\n\"%s\"\nfailed.\n", query); xprintf("%s\n",dl_mysql_error(sql->con)); xfree(query); xfree(sql); return NULL; } } } else if ( sql->mode == 'W' ) { for(j = 0; sqllines[j] != NULL; j++) arg = (char *) sqllines[j]; if ( NULL != strchr(arg, '?') ) { total = strlen(arg); query = xmalloc( (total+1) * sizeof(char)); strcpy (query, arg); } else query = db_generate_insert_stmt(dca); sql->query = query; xprintf("%s\n", query); } return sql; } int db_mysql_read(TABDCA *dca, void *link) { struct db_mysql *sql; char buf[255+1]; char **row; unsigned long *lengths; MYSQL_FIELD *fields; double num; int len; unsigned long num_fields; int i; sql = (struct db_mysql *) link; xassert(sql != NULL); xassert(sql->mode == 'R'); if (NULL == sql->res) { xprintf("db_mysql_read: no result set available"); return 1; } if (NULL==(row = (char **)dl_mysql_fetch_row(sql->res))) { return -1; /*EOF*/ } lengths = dl_mysql_fetch_lengths(sql->res); fields = dl_mysql_fetch_fields(sql->res); num_fields = dl_mysql_num_fields(sql->res); for (i=1; i <= num_fields; i++) { if (row[i-1] != NULL) { len = (size_t) lengths[i-1]; if (len > 255) len = 255; strncpy(buf, (const char *) row[i-1], len); buf[len] = 0x00; if (0 != (fields[i-1].flags & NUM_FLAG)) { strspx(buf); /* remove spaces*/ if (str2num(buf, &num) != 0) { xprintf("'%s' cannot be converted to a number.\n", buf); return 1; } if (sql->ref[i] > 0) mpl_tab_set_num(dca, sql->ref[i], num); } else { if (sql->ref[i] > 0) mpl_tab_set_str(dca, sql->ref[i], strtrim(buf)); } } } return 0; } int db_mysql_write(TABDCA *dca, void *link) { struct db_mysql *sql; char *part; char *query; char *template; char num[50]; int k; int len; int nf; sql = (struct db_mysql *) link; xassert(sql != NULL); xassert(sql->mode == 'W'); len = strlen(sql->query); template = (char *) xmalloc( (len + 1) * sizeof(char) ); strcpy(template, sql->query); nf = mpl_tab_num_flds(dca); for (k = 1; k <= nf; k++) { switch (mpl_tab_get_type(dca, k)) { case 'N': len += 20; break; case 'S': len += db_escaped_string_length(mpl_tab_get_str(dca, k)); len += 2; break; default: xassert(dca != dca); } } query = xmalloc( (len + 1 ) * sizeof(char) ); query[0] = 0x00; for (k = 1, part = strtok (template, "?"); (part != NULL); part = strtok (NULL, "?"), k++) { if (k > nf) break; strcat( query, part ); switch (mpl_tab_get_type(dca, k)) { case 'N': #if 0 /* 02/XI-2010 by xypron */ sprintf(num, "%-18g",mpl_tab_get_num(dca, k)); #else sprintf(num, "%.*g", DBL_DIG, mpl_tab_get_num(dca, k)); #endif strcat( query, num ); break; case 'S': strcat( query, "'"); db_escape_string( query + strlen(query), mpl_tab_get_str(dca, k) ); strcat( query, "'"); break; default: xassert(dca != dca); } } if (part != NULL) strcat(query, part); if (dl_mysql_query(sql->con, query)) { xprintf("db_mysql_write: Query\n\"%s\"\nfailed.\n", query); xprintf("%s\n",dl_mysql_error(sql->con)); xfree(query); xfree(template); return 1; } xfree(query); xfree(template); return 0; } int db_mysql_close(TABDCA *dca, void *link) { struct db_mysql *sql; sql = (struct db_mysql *) link; xassert(sql != NULL); dl_mysql_close(sql->con); if ( sql->mode == 'W' ) xfree(sql->query); xfree(sql); dca->link = NULL; return 0; } #endif /* eof */ Rglpk/src/GLPK/sgf.h0000644000176000001440000002030612245352174013643 0ustar ripleyusers/* sgf.h (sparse Gaussian factorizer) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef SGF_H #define SGF_H #include "luf.h" typedef struct SGF SGF; struct SGF { /* sparse Gaussian factorizer workspace */ LUF *luf; /* LU-factorization being computed */ /*--------------------------------------------------------------*/ /* to efficiently choose pivot elements according to Markowitz * strategy, the search technique proposed by Iain Duff is used; * it is based on using two families of sets {R[0], ..., R[n]} * and {C[0], ..., C[n]}, where R[k] and C[k], 0 <= k <= n, are, * respectively, sets of rows and columns of the active submatrix * of matrix V having k non-zeros (i.e. whose length is k); each * set R[k] and C[k] is implemented as a doubly linked list */ int *rs_head; /* int rs_head[1+n]; */ /* rs_head[k], 0 <= k <= n, is the number of first row, which * has k non-zeros in the active submatrix */ int *rs_prev; /* int rs_prev[1+n]; */ /* rs_prev[0] is not used; * rs_prev[i], 1 <= i <= n, is the number of previous row, which * has the same number of non-zeros as i-th row; * rs_prev[i] < 0 means that i-th row is inactive */ int *rs_next; /* int rs_next[1+n]; */ /* rs_next[0] is not used; * rs_next[i], 1 <= i <= n, is the number of next row, which has * the same number of non-zeros as i-th row; * rs_next[i] < 0 means that i-th row is inactive */ int *cs_head; /* int cs_head[1+n]; */ /* cs_head[k], 0 <= k <= n, is the number of first column, which * has k non-zeros in the active submatrix */ int *cs_prev; /* int cs_prev[1+n]; */ /* cs_prev[0] is not used; * cs_prev[j], 1 <= j <= n, is the number of previous column, * which has the same number of non-zeros as j-th column; * cs_prev[j] < 0 means that j-th column is inactive */ int *cs_next; /* int cs_next[1+n]; */ /* cs_next[0] is not used; * cs_next[j], 1 <= j <= n, is the number of next column, which * has the same number of non-zeros as j-th column; * cs_next[j] < 0 means that j-th column is inactive */ /* NOTE: cs_prev[j] = cs_next[j] = j means that j-th column was * temporarily removed from corresponding set C[k] by the * pivoting routine according to Uwe Suhl's heuristic */ /*--------------------------------------------------------------*/ /* working arrays */ double *vr_max; /* int vr_max[1+n]; */ /* vr_max[0] is not used; * vr_max[i], 1 <= i <= n, is used only if i-th row of matrix V * is active (i.e. belongs to the active submatrix), and is the * largest magnitude of elements in that row; if vr_max[i] < 0, * the largest magnitude is unknown yet */ char *flag; /* char flag[1+n]; */ /* boolean working array */ double *work; /* double work[1+n]; */ /* floating-point working array */ /*--------------------------------------------------------------*/ /* control parameters */ int updat; /* if this flag is set, the matrix V is assumed to be updatable; * in this case factorized (non-active) part of V is stored in * the left part of SVA rather than in its right part */ double piv_tol; /* threshold pivoting tolerance, 0 < piv_tol < 1; element v[i,j] * of the active submatrix fits to be pivot if it satisfies to * the stability criterion |v[i,j]| >= piv_tol * max |v[i,*]|, * i.e. if it is not very small in the magnitude among other * elements in the same row; decreasing this parameter gives * better sparsity at the expense of numerical accuracy and vice * versa */ int piv_lim; /* maximal allowable number of pivot candidates to be considered; * if piv_lim pivot candidates have been considered, the pivoting * routine terminates the search with the best candidate found */ int suhl; /* if this flag is set, the pivoting routine applies a heuristic * proposed by Uwe Suhl: if a column of the active submatrix has * no eligible pivot candidates (i.e. all its elements do not * satisfy to the stability criterion), the routine excludes it * from futher consideration until it becomes column singleton; * in many cases this allows reducing the time needed to choose * the pivot */ double eps_tol; /* epsilon tolerance; each element of the active submatrix, whose * magnitude is less than eps_tol, is replaced by exact zero */ #if 0 /* FIXME */ double den_lim; /* density limit; if the density of the active submatrix reaches * this limit, the factorization routine switches from sparse to * dense mode */ #endif }; #define sgf_activate_row(i) \ do \ { int len = vr_len[i]; \ rs_prev[i] = 0; \ rs_next[i] = rs_head[len]; \ if (rs_next[i] != 0) \ rs_prev[rs_next[i]] = i; \ rs_head[len] = i; \ } while (0) /* include i-th row of matrix V in active set R[len] */ #define sgf_deactivate_row(i) \ do \ { if (rs_prev[i] == 0) \ rs_head[vr_len[i]] = rs_next[i]; \ else \ rs_next[rs_prev[i]] = rs_next[i]; \ if (rs_next[i] == 0) \ ; \ else \ rs_prev[rs_next[i]] = rs_prev[i]; \ rs_prev[i] = rs_next[i] = -1; \ } while (0) /* remove i-th row of matrix V from active set R[len] */ #define sgf_activate_col(j) \ do \ { int len = vc_len[j]; \ cs_prev[j] = 0; \ cs_next[j] = cs_head[len]; \ if (cs_next[j] != 0) \ cs_prev[cs_next[j]] = j; \ cs_head[len] = j; \ } while (0) /* include j-th column of matrix V in active set C[len] */ #define sgf_deactivate_col(j) \ do \ { if (cs_prev[j] == 0) \ cs_head[vc_len[j]] = cs_next[j]; \ else \ cs_next[cs_prev[j]] = cs_next[j]; \ if (cs_next[j] == 0) \ ; \ else \ cs_prev[cs_next[j]] = cs_prev[j]; \ cs_prev[j] = cs_next[j] = -1; \ } while (0) /* remove j-th column of matrix V from active set C[len] */ #define sgf_reduce_nuc _glp_sgf_reduce_nuc void sgf_reduce_nuc(LUF *luf, int *k1, int *k2, int cnt[/*1+n*/], int list[/*1+n*/]); /* initial reordering to minimize nucleus size */ #define sgf_singl_phase _glp_sgf_singl_phase int sgf_singl_phase(LUF *luf, int k1, int k2, int updat, int ind[/*1+n*/], double val[/*1+n*/]); /* compute LU-factorization (singleton phase) */ #define sgf_choose_pivot _glp_sgf_choose_pivot int sgf_choose_pivot(SGF *sgf, int *p, int *q); /* choose pivot element v[p,q] */ #define sgf_eliminate _glp_sgf_eliminate int sgf_eliminate(SGF *sgf, int p, int q); /* perform gaussian elimination */ #define sgf_dense_lu _glp_sgf_dense_lu int sgf_dense_lu(int n, double a[], int r[], int c[], double eps); /* compute dense LU-factorization with full pivoting */ #define sgf_dense_phase _glp_sgf_dense_phase int sgf_dense_phase(LUF *luf, int k, int updat); /* compute LU-factorization (dense phase) */ #define sgf_factorize _glp_sgf_factorize int sgf_factorize(SGF *sgf, int singl); /* compute LU-factorization (main routine) */ #endif /* eof */ Rglpk/src/GLPK/glpscl.c0000644000176000001440000003732512245352174014354 0ustar ripleyusers/* glpscl.c (problem scaling routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpapi.h" #include "glplib.h" /*********************************************************************** * min_row_aij - determine minimal |a[i,j]| in i-th row * * This routine returns minimal magnitude of (non-zero) constraint * coefficients in i-th row of the constraint matrix. * * If the parameter scaled is zero, the original constraint matrix A is * assumed. Otherwise, the scaled constraint matrix R*A*S is assumed. * * If i-th row of the matrix is empty, the routine returns 1. */ static double min_row_aij(glp_prob *lp, int i, int scaled) { GLPAIJ *aij; double min_aij, temp; xassert(1 <= i && i <= lp->m); min_aij = 1.0; for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next) { temp = fabs(aij->val); if (scaled) temp *= (aij->row->rii * aij->col->sjj); if (aij->r_prev == NULL || min_aij > temp) min_aij = temp; } return min_aij; } /*********************************************************************** * max_row_aij - determine maximal |a[i,j]| in i-th row * * This routine returns maximal magnitude of (non-zero) constraint * coefficients in i-th row of the constraint matrix. * * If the parameter scaled is zero, the original constraint matrix A is * assumed. Otherwise, the scaled constraint matrix R*A*S is assumed. * * If i-th row of the matrix is empty, the routine returns 1. */ static double max_row_aij(glp_prob *lp, int i, int scaled) { GLPAIJ *aij; double max_aij, temp; xassert(1 <= i && i <= lp->m); max_aij = 1.0; for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next) { temp = fabs(aij->val); if (scaled) temp *= (aij->row->rii * aij->col->sjj); if (aij->r_prev == NULL || max_aij < temp) max_aij = temp; } return max_aij; } /*********************************************************************** * min_col_aij - determine minimal |a[i,j]| in j-th column * * This routine returns minimal magnitude of (non-zero) constraint * coefficients in j-th column of the constraint matrix. * * If the parameter scaled is zero, the original constraint matrix A is * assumed. Otherwise, the scaled constraint matrix R*A*S is assumed. * * If j-th column of the matrix is empty, the routine returns 1. */ static double min_col_aij(glp_prob *lp, int j, int scaled) { GLPAIJ *aij; double min_aij, temp; xassert(1 <= j && j <= lp->n); min_aij = 1.0; for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next) { temp = fabs(aij->val); if (scaled) temp *= (aij->row->rii * aij->col->sjj); if (aij->c_prev == NULL || min_aij > temp) min_aij = temp; } return min_aij; } /*********************************************************************** * max_col_aij - determine maximal |a[i,j]| in j-th column * * This routine returns maximal magnitude of (non-zero) constraint * coefficients in j-th column of the constraint matrix. * * If the parameter scaled is zero, the original constraint matrix A is * assumed. Otherwise, the scaled constraint matrix R*A*S is assumed. * * If j-th column of the matrix is empty, the routine returns 1. */ static double max_col_aij(glp_prob *lp, int j, int scaled) { GLPAIJ *aij; double max_aij, temp; xassert(1 <= j && j <= lp->n); max_aij = 1.0; for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next) { temp = fabs(aij->val); if (scaled) temp *= (aij->row->rii * aij->col->sjj); if (aij->c_prev == NULL || max_aij < temp) max_aij = temp; } return max_aij; } /*********************************************************************** * min_mat_aij - determine minimal |a[i,j]| in constraint matrix * * This routine returns minimal magnitude of (non-zero) constraint * coefficients in the constraint matrix. * * If the parameter scaled is zero, the original constraint matrix A is * assumed. Otherwise, the scaled constraint matrix R*A*S is assumed. * * If the matrix is empty, the routine returns 1. */ static double min_mat_aij(glp_prob *lp, int scaled) { int i; double min_aij, temp; min_aij = 1.0; for (i = 1; i <= lp->m; i++) { temp = min_row_aij(lp, i, scaled); if (i == 1 || min_aij > temp) min_aij = temp; } return min_aij; } /*********************************************************************** * max_mat_aij - determine maximal |a[i,j]| in constraint matrix * * This routine returns maximal magnitude of (non-zero) constraint * coefficients in the constraint matrix. * * If the parameter scaled is zero, the original constraint matrix A is * assumed. Otherwise, the scaled constraint matrix R*A*S is assumed. * * If the matrix is empty, the routine returns 1. */ static double max_mat_aij(glp_prob *lp, int scaled) { int i; double max_aij, temp; max_aij = 1.0; for (i = 1; i <= lp->m; i++) { temp = max_row_aij(lp, i, scaled); if (i == 1 || max_aij < temp) max_aij = temp; } return max_aij; } /*********************************************************************** * eq_scaling - perform equilibration scaling * * This routine performs equilibration scaling of rows and columns of * the constraint matrix. * * If the parameter flag is zero, the routine scales rows at first and * then columns. Otherwise, the routine scales columns and then rows. * * Rows are scaled as follows: * * n * a'[i,j] = a[i,j] / max |a[i,j]|, i = 1,...,m. * j=1 * * This makes the infinity (maximum) norm of each row of the matrix * equal to 1. * * Columns are scaled as follows: * * m * a'[i,j] = a[i,j] / max |a[i,j]|, j = 1,...,n. * i=1 * * This makes the infinity (maximum) norm of each column of the matrix * equal to 1. */ static void eq_scaling(glp_prob *lp, int flag) { int i, j, pass; double temp; xassert(flag == 0 || flag == 1); for (pass = 0; pass <= 1; pass++) { if (pass == flag) { /* scale rows */ for (i = 1; i <= lp->m; i++) { temp = max_row_aij(lp, i, 1); glp_set_rii(lp, i, glp_get_rii(lp, i) / temp); } } else { /* scale columns */ for (j = 1; j <= lp->n; j++) { temp = max_col_aij(lp, j, 1); glp_set_sjj(lp, j, glp_get_sjj(lp, j) / temp); } } } return; } /*********************************************************************** * gm_scaling - perform geometric mean scaling * * This routine performs geometric mean scaling of rows and columns of * the constraint matrix. * * If the parameter flag is zero, the routine scales rows at first and * then columns. Otherwise, the routine scales columns and then rows. * * Rows are scaled as follows: * * a'[i,j] = a[i,j] / sqrt(alfa[i] * beta[i]), i = 1,...,m, * * where: * n n * alfa[i] = min |a[i,j]|, beta[i] = max |a[i,j]|. * j=1 j=1 * * This allows decreasing the ratio beta[i] / alfa[i] for each row of * the matrix. * * Columns are scaled as follows: * * a'[i,j] = a[i,j] / sqrt(alfa[j] * beta[j]), j = 1,...,n, * * where: * m m * alfa[j] = min |a[i,j]|, beta[j] = max |a[i,j]|. * i=1 i=1 * * This allows decreasing the ratio beta[j] / alfa[j] for each column * of the matrix. */ static void gm_scaling(glp_prob *lp, int flag) { int i, j, pass; double temp; xassert(flag == 0 || flag == 1); for (pass = 0; pass <= 1; pass++) { if (pass == flag) { /* scale rows */ for (i = 1; i <= lp->m; i++) { temp = min_row_aij(lp, i, 1) * max_row_aij(lp, i, 1); glp_set_rii(lp, i, glp_get_rii(lp, i) / sqrt(temp)); } } else { /* scale columns */ for (j = 1; j <= lp->n; j++) { temp = min_col_aij(lp, j, 1) * max_col_aij(lp, j, 1); glp_set_sjj(lp, j, glp_get_sjj(lp, j) / sqrt(temp)); } } } return; } /*********************************************************************** * max_row_ratio - determine worst scaling "quality" for rows * * This routine returns the worst scaling "quality" for rows of the * currently scaled constraint matrix: * * m * ratio = max ratio[i], * i=1 * where: * n n * ratio[i] = max |a[i,j]| / min |a[i,j]|, 1 <= i <= m, * j=1 j=1 * * is the scaling "quality" of i-th row. */ static double max_row_ratio(glp_prob *lp) { int i; double ratio, temp; ratio = 1.0; for (i = 1; i <= lp->m; i++) { temp = max_row_aij(lp, i, 1) / min_row_aij(lp, i, 1); if (i == 1 || ratio < temp) ratio = temp; } return ratio; } /*********************************************************************** * max_col_ratio - determine worst scaling "quality" for columns * * This routine returns the worst scaling "quality" for columns of the * currently scaled constraint matrix: * * n * ratio = max ratio[j], * j=1 * where: * m m * ratio[j] = max |a[i,j]| / min |a[i,j]|, 1 <= j <= n, * i=1 i=1 * * is the scaling "quality" of j-th column. */ static double max_col_ratio(glp_prob *lp) { int j; double ratio, temp; ratio = 1.0; for (j = 1; j <= lp->n; j++) { temp = max_col_aij(lp, j, 1) / min_col_aij(lp, j, 1); if (j == 1 || ratio < temp) ratio = temp; } return ratio; } /*********************************************************************** * gm_iterate - perform iterative geometric mean scaling * * This routine performs iterative geometric mean scaling of rows and * columns of the constraint matrix. * * The parameter it_max specifies the maximal number of iterations. * Recommended value of it_max is 15. * * The parameter tau specifies a minimal improvement of the scaling * "quality" on each iteration, 0 < tau < 1. It means than the scaling * process continues while the following condition is satisfied: * * ratio[k] <= tau * ratio[k-1], * * where ratio = max |a[i,j]| / min |a[i,j]| is the scaling "quality" * to be minimized, k is the iteration number. Recommended value of tau * is 0.90. */ static void gm_iterate(glp_prob *lp, int it_max, double tau) { int k, flag; double ratio = 0.0, r_old; /* if the scaling "quality" for rows is better than for columns, the rows are scaled first; otherwise, the columns are scaled first */ flag = (max_row_ratio(lp) > max_col_ratio(lp)); for (k = 1; k <= it_max; k++) { /* save the scaling "quality" from previous iteration */ r_old = ratio; /* determine the current scaling "quality" */ ratio = max_mat_aij(lp, 1) / min_mat_aij(lp, 1); #if 0 xprintf("k = %d; ratio = %g\n", k, ratio); #endif /* if improvement is not enough, terminate scaling */ if (k > 1 && ratio > tau * r_old) break; /* otherwise, perform another iteration */ gm_scaling(lp, flag); } return; } /*********************************************************************** * NAME * * scale_prob - scale problem data * * SYNOPSIS * * #include "glpscl.h" * void scale_prob(glp_prob *lp, int flags); * * DESCRIPTION * * The routine scale_prob performs automatic scaling of problem data * for the specified problem object. */ static void scale_prob(glp_prob *lp, int flags) { static const char *fmt = "%s: min|aij| = %10.3e max|aij| = %10.3e ratio = %10.3e\n"; double min_aij, max_aij, ratio; xprintf("Scaling...\n"); /* cancel the current scaling effect */ glp_unscale_prob(lp); /* report original scaling "quality" */ min_aij = min_mat_aij(lp, 1); max_aij = max_mat_aij(lp, 1); ratio = max_aij / min_aij; xprintf(fmt, " A", min_aij, max_aij, ratio); /* check if the problem is well scaled */ if (min_aij >= 0.10 && max_aij <= 10.0) { xprintf("Problem data seem to be well scaled\n"); /* skip scaling, if required */ if (flags & GLP_SF_SKIP) goto done; } /* perform iterative geometric mean scaling, if required */ if (flags & GLP_SF_GM) { gm_iterate(lp, 15, 0.90); min_aij = min_mat_aij(lp, 1); max_aij = max_mat_aij(lp, 1); ratio = max_aij / min_aij; xprintf(fmt, "GM", min_aij, max_aij, ratio); } /* perform equilibration scaling, if required */ if (flags & GLP_SF_EQ) { eq_scaling(lp, max_row_ratio(lp) > max_col_ratio(lp)); min_aij = min_mat_aij(lp, 1); max_aij = max_mat_aij(lp, 1); ratio = max_aij / min_aij; xprintf(fmt, "EQ", min_aij, max_aij, ratio); } /* round scale factors to nearest power of two, if required */ if (flags & GLP_SF_2N) { int i, j; for (i = 1; i <= lp->m; i++) glp_set_rii(lp, i, round2n(glp_get_rii(lp, i))); for (j = 1; j <= lp->n; j++) glp_set_sjj(lp, j, round2n(glp_get_sjj(lp, j))); min_aij = min_mat_aij(lp, 1); max_aij = max_mat_aij(lp, 1); ratio = max_aij / min_aij; xprintf(fmt, "2N", min_aij, max_aij, ratio); } done: return; } /*********************************************************************** * NAME * * glp_scale_prob - scale problem data * * SYNOPSIS * * void glp_scale_prob(glp_prob *lp, int flags); * * DESCRIPTION * * The routine glp_scale_prob performs automatic scaling of problem * data for the specified problem object. * * The parameter flags specifies scaling options used by the routine. * Options can be combined with the bitwise OR operator and may be the * following: * * GLP_SF_GM perform geometric mean scaling; * GLP_SF_EQ perform equilibration scaling; * GLP_SF_2N round scale factors to nearest power of two; * GLP_SF_SKIP skip scaling, if the problem is well scaled. * * The parameter flags may be specified as GLP_SF_AUTO, in which case * the routine chooses scaling options automatically. */ void glp_scale_prob(glp_prob *lp, int flags) { if (flags & ~(GLP_SF_GM | GLP_SF_EQ | GLP_SF_2N | GLP_SF_SKIP | GLP_SF_AUTO)) xerror("glp_scale_prob: flags = 0x%02X; invalid scaling option" "s\n", flags); if (flags & GLP_SF_AUTO) flags = (GLP_SF_GM | GLP_SF_EQ | GLP_SF_SKIP); scale_prob(lp, flags); return; } /* eof */ Rglpk/src/GLPK/glpapi.h0000644000176000001440000003002412245352174014336 0ustar ripleyusers/* glpapi.h (application program interface) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPAPI_H #define GLPAPI_H #include "glpk.h" #include "glpavl.h" #include "glpbfd.h" #include "glplpx.h" #include "env.h" typedef struct GLPROW GLPROW; typedef struct GLPCOL GLPCOL; typedef struct GLPAIJ GLPAIJ; #define GLP_PROB_MAGIC 0xD7D9D6C2 struct glp_prob { /* LP/MIP problem object */ unsigned magic; /* magic value used for debugging */ DMP *pool; /* memory pool to store problem object components */ glp_tree *tree; /* pointer to the search tree; set by the MIP solver when this object is used in the tree as a core MIP object */ void *parms; /* reserved for backward compatibility */ /*--------------------------------------------------------------*/ /* LP/MIP data */ 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 */ int dir; /* optimization direction flag (objective "sense"): GLP_MIN - minimization GLP_MAX - maximization */ double c0; /* constant term of the objective function ("shift") */ int m_max; /* length of the array of rows (enlarged automatically) */ int n_max; /* length of the array of columns (enlarged automatically) */ int m; /* number of rows, 0 <= m <= m_max */ int n; /* number of columns, 0 <= n <= n_max */ int nnz; /* number of non-zero constraint coefficients, nnz >= 0 */ GLPROW **row; /* GLPROW *row[1+m_max]; */ /* row[i], 1 <= i <= m, is a pointer to i-th row */ GLPCOL **col; /* GLPCOL *col[1+n_max]; */ /* col[j], 1 <= j <= n, is a pointer to j-th column */ AVL *r_tree; /* row index to find rows by their names; NULL means this index does not exist */ AVL *c_tree; /* column index to find columns by their names; NULL means this index does not exist */ /*--------------------------------------------------------------*/ /* basis factorization (LP) */ int valid; /* the factorization is valid only if this flag is set */ int *head; /* int head[1+m_max]; */ /* basis header (valid only if the factorization is valid); head[i] = k is the ordinal number of auxiliary (1 <= k <= m) or structural (m+1 <= k <= m+n) variable which corresponds to i-th basic variable xB[i], 1 <= i <= m */ glp_bfcp *bfcp; /* basis factorization control parameters; may be NULL */ BFD *bfd; /* BFD bfd[1:m,1:m]; */ /* basis factorization driver; may be NULL */ /*--------------------------------------------------------------*/ /* basic solution (LP) */ int pbs_stat; /* primal basic solution status: 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 dbs_stat; /* dual basic solution status: 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 */ double obj_val; /* objective function value */ int it_cnt; /* simplex method iteration count; increased by one on performing one simplex iteration */ int some; /* ordinal number of some auxiliary or structural variable having certain property, 0 <= some <= m+n */ /*--------------------------------------------------------------*/ /* interior-point solution (LP) */ int ipt_stat; /* interior-point solution status: GLP_UNDEF - interior solution is undefined GLP_OPT - interior solution is optimal GLP_INFEAS - interior solution is infeasible GLP_NOFEAS - no feasible solution exists */ double ipt_obj; /* objective function value */ /*--------------------------------------------------------------*/ /* integer solution (MIP) */ int mip_stat; /* integer solution status: GLP_UNDEF - integer solution is undefined GLP_OPT - integer solution is optimal GLP_FEAS - integer solution is feasible GLP_NOFEAS - no integer solution exists */ double mip_obj; /* objective function value */ }; struct GLPROW { /* LP/MIP row (auxiliary variable) */ int i; /* ordinal number (1 to m) assigned to this row */ char *name; /* row name (1 to 255 chars); NULL means no name is assigned to this row */ AVLNODE *node; /* pointer to corresponding node in the row index; NULL means that either the row index does not exist or this row has no name assigned */ #if 1 /* 20/IX-2008 */ int level; unsigned char origin; unsigned char klass; #endif int type; /* type of the auxiliary variable: GLP_FR - free variable GLP_LO - variable with lower bound GLP_UP - variable with upper bound GLP_DB - double-bounded variable GLP_FX - fixed variable */ double lb; /* non-scaled */ /* lower bound; if the row has no lower bound, lb is zero */ double ub; /* non-scaled */ /* upper bound; if the row has no upper bound, ub is zero */ /* if the row type is GLP_FX, ub is equal to lb */ GLPAIJ *ptr; /* non-scaled */ /* pointer to doubly linked list of constraint coefficients which are placed in this row */ double rii; /* diagonal element r[i,i] of scaling matrix R for this row; if the scaling is not used, r[i,i] is 1 */ int stat; /* status of the auxiliary variable: 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 */ int bind; /* if the auxiliary variable is basic, head[bind] refers to this row, otherwise, bind is 0; this attribute is valid only if the basis factorization is valid */ double prim; /* non-scaled */ /* primal value of the auxiliary variable in basic solution */ double dual; /* non-scaled */ /* dual value of the auxiliary variable in basic solution */ double pval; /* non-scaled */ /* primal value of the auxiliary variable in interior solution */ double dval; /* non-scaled */ /* dual value of the auxiliary variable in interior solution */ double mipx; /* non-scaled */ /* primal value of the auxiliary variable in integer solution */ }; struct GLPCOL { /* LP/MIP column (structural variable) */ int j; /* ordinal number (1 to n) assigned to this column */ char *name; /* column name (1 to 255 chars); NULL means no name is assigned to this column */ AVLNODE *node; /* pointer to corresponding node in the column index; NULL means that either the column index does not exist or the column has no name assigned */ int kind; /* kind of the structural variable: GLP_CV - continuous variable GLP_IV - integer or binary variable */ int type; /* type of the structural variable: GLP_FR - free variable GLP_LO - variable with lower bound GLP_UP - variable with upper bound GLP_DB - double-bounded variable GLP_FX - fixed variable */ double lb; /* non-scaled */ /* lower bound; if the column has no lower bound, lb is zero */ double ub; /* non-scaled */ /* upper bound; if the column has no upper bound, ub is zero */ /* if the column type is GLP_FX, ub is equal to lb */ double coef; /* non-scaled */ /* objective coefficient at the structural variable */ GLPAIJ *ptr; /* non-scaled */ /* pointer to doubly linked list of constraint coefficients which are placed in this column */ double sjj; /* diagonal element s[j,j] of scaling matrix S for this column; if the scaling is not used, s[j,j] is 1 */ int stat; /* status of the structural variable: 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 */ int bind; /* if the structural variable is basic, head[bind] refers to this column; otherwise, bind is 0; this attribute is valid only if the basis factorization is valid */ double prim; /* non-scaled */ /* primal value of the structural variable in basic solution */ double dual; /* non-scaled */ /* dual value of the structural variable in basic solution */ double pval; /* non-scaled */ /* primal value of the structural variable in interior solution */ double dval; /* non-scaled */ /* dual value of the structural variable in interior solution */ double mipx; /* non-scaled */ /* primal value of the structural variable in integer solution */ }; struct GLPAIJ { /* constraint coefficient a[i,j] */ GLPROW *row; /* pointer to row, where this coefficient is placed */ GLPCOL *col; /* pointer to column, where this coefficient is placed */ double val; /* numeric (non-zero) value of this coefficient */ GLPAIJ *r_prev; /* pointer to previous coefficient in the same row */ GLPAIJ *r_next; /* pointer to next coefficient in the same row */ GLPAIJ *c_prev; /* pointer to previous coefficient in the same column */ GLPAIJ *c_next; /* pointer to next coefficient in the same column */ }; #define lpx_put_solution _glp_put_solution void lpx_put_solution(glp_prob *lp, int inval, const int *p_stat, const int *d_stat, const double *obj_val, const int r_stat[], const double r_prim[], const double r_dual[], const int c_stat[], const double c_prim[], const double c_dual[]); /* store basic solution components */ #define lpx_put_mip_soln _glp_put_mip_soln void lpx_put_mip_soln(LPX *lp, int i_stat, double row_mipx[], double col_mipx[]); /* store mixed integer solution components */ #if 1 /* 28/XI-2009 */ int _glp_analyze_row(glp_prob *P, int len, const int ind[], const double val[], int type, double rhs, double eps, int *_piv, double *_x, double *_dx, double *_y, double *_dy, double *_dz); /* simulate one iteration of dual simplex method */ #endif #if 1 /* 08/XII-2009 */ void _glp_mpl_init_rand(glp_tran *tran, int seed); #endif #define glp_skpgen _glp_skpgen void glp_skpgen(int n, int r, int type, int v, int s, int a[], int *b, int c[]); /* Pisinger's 0-1 single knapsack problem generator */ #if 1 /* 28/V-2010 */ int _glp_intopt1(glp_prob *P, const glp_iocp *parm); #endif #endif /* eof */ Rglpk/src/GLPK/glpenv07.c.orig0000644000176000001440000003727712175147600015475 0ustar ripleyusers/* glpenv07.c (stream input/output) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env2.h" #include "zlib.h" #if 1 /* 11/VI-2013 */ #define IOERR_MSG_SIZE 1024 /* i/o error message buffer size, in bytes */ static char env_ioerr_msg[IOERR_MSG_SIZE] = "No error"; /* input/output error message buffer */ struct XFILE { /* input/output stream descriptor */ int type; /* stream handle type: */ #define FH_FILE 0x11 /* FILE */ #define FH_ZLIB 0x22 /* gzFile */ void *fh; /* pointer to stream handle */ #if 0 /* 11/VI-2013 */ XFILE *prev; /* pointer to previous stream descriptor */ XFILE *next; /* pointer to next stream descriptor */ #endif }; #endif /*********************************************************************** * NAME * * lib_err_msg - save error message string * * SYNOPSIS * * #include "glpenv.h" * void lib_err_msg(const char *msg); * * DESCRIPTION * * The routine lib_err_msg saves an error message string specified by * the parameter msg. The message is obtained by some library routines * with a call to strerror(errno). */ void lib_err_msg(const char *msg) { /*ENV *env = get_env_ptr();*/ int len = strlen(msg); if (len >= IOERR_MSG_SIZE) len = IOERR_MSG_SIZE - 1; #if 0 /* 11/VI-2013 */ memcpy(env->ioerr_msg, msg, len); if (len > 0 && env->ioerr_msg[len-1] == '\n') len--; env->ioerr_msg[len] = '\0'; #else memcpy(env_ioerr_msg, msg, len); if (len > 0 && env_ioerr_msg[len-1] == '\n') len--; env_ioerr_msg[len] = '\0'; #endif return; } /*********************************************************************** * NAME * * xerrmsg - retrieve error message string * * SYNOPSIS * * #include "glpenv.h" * const char *xerrmsg(void); * * RETURNS * * The routine xerrmsg returns a pointer to an error message string * previously set by some library routine to indicate an error. */ const char *xerrmsg(void) { /*ENV *env = get_env_ptr();*/ #if 0 /* 11/VI-2013 */ return env->ioerr_msg; #else return env_ioerr_msg; #endif } /*********************************************************************** * NAME * * xfopen - open a stream * * SYNOPSIS * * #include "glpenv.h" * XFILE *xfopen(const char *fname, const char *mode); * * DESCRIPTION * * The routine xfopen opens the file whose name is a string pointed to * by fname and associates a stream with it. * * The parameter mode points to a string, which indicates the open mode * and should be one of the following: * * "r" open text file for reading; * "w" truncate to zero length or create text file for writing; * "rb" open binary file for reading; * "wb" truncate to zero length or create binary file for writing. * * RETURNS * * The routine xfopen returns a pointer to the object controlling the * stream. If the open operation fails, xfopen returns NULL. */ static void *c_fopen(const char *fname, const char *mode); static void *z_fopen(const char *fname, const char *mode); static int is_gz_file(const char *fname) { char *ext = strrchr(fname, '.'); return ext != NULL && strcmp(ext, ".gz") == 0; } XFILE *xfopen(const char *fname, const char *mode) { /*ENV *env = get_env_ptr();*/ XFILE *fp; int type; void *fh; if (!is_gz_file(fname)) { type = FH_FILE; fh = c_fopen(fname, mode); } else { type = FH_ZLIB; fh = z_fopen(fname, mode); } if (fh == NULL) { fp = NULL; goto done; } fp = xmalloc(sizeof(XFILE)); fp->type = type; fp->fh = fh; #if 0 /* 11/VI-2013 */ fp->prev = NULL; fp->next = env->file_ptr; if (fp->next != NULL) fp->next->prev = fp; env->file_ptr = fp; #endif done: return fp; } /*********************************************************************** * NAME * * xfgetc - read character from the stream * * SYNOPSIS * * #include "glpenv.h" * int xfgetc(XFILE *fp); * * DESCRIPTION * * If the end-of-file indicator for the input stream pointed to by fp * is not set and a next character is present, the routine xfgetc * obtains that character as an unsigned char converted to an int and * advances the associated file position indicator for the stream (if * defined). * * RETURNS * * If the end-of-file indicator for the stream is set, or if the * stream is at end-of-file, the end-of-file indicator for the stream * is set and the routine xfgetc returns XEOF. Otherwise, the routine * xfgetc returns the next character from the input stream pointed to * by fp. If a read error occurs, the error indicator for the stream is * set and the xfgetc routine returns XEOF. * * Note: An end-of-file and a read error can be distinguished by use of * the routines xfeof and xferror. */ static int c_fgetc(void *fh); static int z_fgetc(void *fh); int xfgetc(XFILE *fp) { int c; switch (fp->type) { case FH_FILE: c = c_fgetc(fp->fh); break; case FH_ZLIB: c = z_fgetc(fp->fh); break; default: xassert(fp != fp); } return c; } /*********************************************************************** * NAME * * xfputc - write character to the stream * * SYNOPSIS * * #include "glpenv.h" * int xfputc(int c, XFILE *fp); * * DESCRIPTION * * The routine xfputc writes the character specified by c (converted * to an unsigned char) to the output stream pointed to by fp, at the * position indicated by the associated file position indicator (if * defined), and advances the indicator appropriately. * * RETURNS * * The routine xfputc returns the character written. If a write error * occurs, the error indicator for the stream is set and xfputc returns * XEOF. */ static int c_fputc(int c, void *fh); static int z_fputc(int c, void *fh); int xfputc(int c, XFILE *fp) { switch (fp->type) { case FH_FILE: c = c_fputc(c, fp->fh); break; case FH_ZLIB: c = z_fputc(c, fp->fh); break; default: xassert(fp != fp); } return c; } /*********************************************************************** * NAME * * xferror - test error indicator for the stream * * SYNOPSIS * * #include "glpenv.h" * int xferror(XFILE *fp); * * DESCRIPTION * * The routine xferror tests the error indicator for the stream * pointed to by fp. * * RETURNS * * The routine xferror returns non-zero if and only if the error * indicator is set for the stream. */ static int c_ferror(void *fh); static int z_ferror(void *fh); int xferror(XFILE *fp) { int ret; switch (fp->type) { case FH_FILE: ret = c_ferror(fp->fh); break; case FH_ZLIB: ret = z_ferror(fp->fh); break; default: xassert(fp != fp); } return ret; } /*********************************************************************** * NAME * * xfeof - test end-of-file indicator for the stream * * SYNOPSIS * * #include "glpenv.h" * int xfeof(XFILE *fp); * * DESCRIPTION * * The routine xfeof tests the end-of-file indicator for the stream * pointed to by fp. * * RETURNS * * The routine xfeof returns non-zero if and only if the end-of-file * indicator is set for the stream. */ static int c_feof(void *fh); static int z_feof(void *fh); int xfeof(XFILE *fp) { int ret; switch (fp->type) { case FH_FILE: ret = c_feof(fp->fh); break; case FH_ZLIB: ret = z_feof(fp->fh); break; default: xassert(fp != fp); } return ret; } int xfprintf(XFILE *file, const char *fmt, ...) { ENV *env = get_env_ptr(); int cnt, j; va_list arg; va_start(arg, fmt); cnt = vsprintf(env->term_buf, fmt, arg); va_end(arg); for (j = 0; j < cnt; j++) { if (xfputc(env->term_buf[j], file) < 0) { cnt = -1; break; } } return cnt; } /*********************************************************************** * NAME * * xfflush - flush the stream * * SYNOPSIS * * #include "glpenv.h" * int xfflush(XFILE *fp); * * DESCRIPTION * * The routine xfflush causes any unwritten data for the output stream * pointed to by fp to be written to the associated file. * * RETURNS * * The routine xfflush returns zero if the stream was successfully * flushed. Otherwise, xfflush sets the error indicator for the stream * and returns XEOF. */ static int c_fflush(void *fh); static int z_fflush(void *fh); int xfflush(XFILE *fp) { int ret; switch (fp->type) { case FH_FILE: ret = c_fflush(fp->fh); break; case FH_ZLIB: ret = z_fflush(fp->fh); break; default: xassert(fp != fp); } return ret; } /*********************************************************************** * NAME * * xfclose - close the stream * * SYNOPSIS * * #include "glpenv.h" * int xfclose(XFILE *fp); * * DESCRIPTION * * A successful call to the routine xfclose causes the stream pointed * to by fp to be flushed and the associated file to be closed. Whether * or not the call succeeds, the stream is disassociated from the file. * * RETURNS * * The routine xfclose returns zero if the stream was successfully * closed, or XEOF if any errors were detected. */ static int c_fclose(void *fh); static int z_fclose(void *fh); int xfclose(XFILE *fp) { /*ENV *env = get_env_ptr();*/ int ret; switch (fp->type) { case FH_FILE: ret = c_fclose(fp->fh); break; case FH_ZLIB: ret = z_fclose(fp->fh); break; default: xassert(fp != fp); } fp->type = 0xF00BAD; #if 0 /* 11/VI-2013 */ if (fp->prev == NULL) env->file_ptr = fp->next; else fp->prev->next = fp->next; if (fp->next == NULL) ; else fp->next->prev = fp->prev; #endif xfree(fp); return ret; } /*********************************************************************** * The following routines implement stream input/output based on the * standard C streams. */ static void *c_fopen(const char *fname, const char *mode) { FILE *fh; if (strcmp(fname, "/dev/stdin") == 0) fh = stdin; else if (strcmp(fname, "/dev/stdout") == 0) fh = stdout; else if (strcmp(fname, "/dev/stderr") == 0) fh = stderr; else fh = fopen(fname, mode); if (fh == NULL) lib_err_msg(strerror(errno)); return fh; } static int c_fgetc(void *_fh) { FILE *fh = _fh; int c; if (ferror(fh) || feof(fh)) { c = XEOF; goto done; } c = fgetc(fh); if (ferror(fh)) { lib_err_msg(strerror(errno)); c = XEOF; } else if (feof(fh)) c = XEOF; else xassert(0x00 <= c && c <= 0xFF); done: return c; } static int c_fputc(int c, void *_fh) { FILE *fh = _fh; if (ferror(fh)) { c = XEOF; goto done; } c = (unsigned char)c; fputc(c, fh); if (ferror(fh)) { lib_err_msg(strerror(errno)); c = XEOF; } done: return c; } static int c_ferror(void *_fh) { FILE *fh = _fh; return ferror(fh); } static int c_feof(void *_fh) { FILE *fh = _fh; return feof(fh); } static int c_fflush(void *_fh) { FILE *fh = _fh; int ret; ret = fflush(fh); if (ret != 0) { lib_err_msg(strerror(errno)); ret = XEOF; } return ret; } static int c_fclose(void *_fh) { FILE *fh = _fh; int ret; if (fh == stdin) ret = 0; else if (fh == stdout || fh == stderr) fflush(fh), ret = 0; else ret = fclose(fh); if (ret != 0) { lib_err_msg(strerror(errno)); ret = XEOF; } return ret; } /*********************************************************************** * The following routines implement stream input/output based on the * zlib library, which provides processing .gz files "on the fly". */ struct z_file { /* .gz file handle */ gzFile file; /* pointer to .gz stream */ int err; /* i/o error indicator */ int eof; /* end-of-file indicator */ }; static void *z_fopen(const char *fname, const char *mode) { struct z_file *fh; gzFile file; if (strcmp(mode, "r") == 0 || strcmp(mode, "rb") == 0) mode = "rb"; else if (strcmp(mode, "w") == 0 || strcmp(mode, "wb") == 0) mode = "wb"; else { lib_err_msg("Invalid open mode"); fh = NULL; goto done; } file = gzopen(fname, mode); if (file == NULL) { lib_err_msg(strerror(errno)); fh = NULL; goto done; } fh = xmalloc(sizeof(struct z_file)); fh->file = file; fh->err = fh->eof = 0; done: return fh; } static int z_fgetc(void *_fh) { struct z_file *fh = _fh; int c; if (fh->err || fh->eof) { c = XEOF; goto done; } c = gzgetc(fh->file); if (c < 0) { int errnum; const char *msg; msg = gzerror(fh->file, &errnum); if (errnum == Z_STREAM_END) fh->eof = 1; else if (errnum == Z_ERRNO) { fh->err = 1; lib_err_msg(strerror(errno)); } else { fh->err = 1; lib_err_msg(msg); } c = XEOF; } else xassert(0x00 <= c && c <= 0xFF); done: return c; } static int z_fputc(int c, void *_fh) { struct z_file *fh = _fh; if (fh->err) { c = XEOF; goto done; } c = (unsigned char)c; if (gzputc(fh->file, c) < 0) { int errnum; const char *msg; fh->err = 1; msg = gzerror(fh->file, &errnum); if (errnum == Z_ERRNO) lib_err_msg(strerror(errno)); else lib_err_msg(msg); c = XEOF; } done: return c; } static int z_ferror(void *_fh) { struct z_file *fh = _fh; return fh->err; } static int z_feof(void *_fh) { struct z_file *fh = _fh; return fh->eof; } static int z_fflush(void *_fh) { struct z_file *fh = _fh; int ret; ret = gzflush(fh->file, Z_FINISH); if (ret == Z_OK) ret = 0; else { int errnum; const char *msg; fh->err = 1; msg = gzerror(fh->file, &errnum); if (errnum == Z_ERRNO) lib_err_msg(strerror(errno)); else lib_err_msg(msg); ret = XEOF; } return ret; } static int z_fclose(void *_fh) { struct z_file *fh = _fh; gzclose(fh->file); xfree(fh); return 0; } /* eof */ Rglpk/src/GLPK/glpios.h0000644000176000001440000005505712245352174014374 0ustar ripleyusers/* glpios.h (integer optimization suite) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPIOS_H #define GLPIOS_H #include "glpapi.h" typedef struct IOSLOT IOSLOT; typedef struct IOSNPD IOSNPD; typedef struct IOSBND IOSBND; typedef struct IOSTAT IOSTAT; typedef struct IOSROW IOSROW; typedef struct IOSAIJ IOSAIJ; typedef struct IOSPOOL IOSPOOL; typedef struct IOSCUT IOSCUT; struct glp_tree { /* branch-and-bound tree */ int magic; /* magic value used for debugging */ DMP *pool; /* memory pool to store all IOS components */ int n; /* number of columns (variables) */ /*--------------------------------------------------------------*/ /* problem components corresponding to the original MIP and its LP relaxation (used to restore the original problem object on exit from the solver) */ int orig_m; /* number of rows */ unsigned char *orig_type; /* uchar orig_type[1+orig_m+n]; */ /* types of all variables */ double *orig_lb; /* double orig_lb[1+orig_m+n]; */ /* lower bounds of all variables */ double *orig_ub; /* double orig_ub[1+orig_m+n]; */ /* upper bounds of all variables */ unsigned char *orig_stat; /* uchar orig_stat[1+orig_m+n]; */ /* statuses of all variables */ double *orig_prim; /* double orig_prim[1+orig_m+n]; */ /* primal values of all variables */ double *orig_dual; /* double orig_dual[1+orig_m+n]; */ /* dual values of all variables */ double orig_obj; /* optimal objective value for LP relaxation */ /*--------------------------------------------------------------*/ /* branch-and-bound tree */ int nslots; /* length of the array of slots (enlarged automatically) */ int avail; /* index of the first free slot; 0 means all slots are in use */ IOSLOT *slot; /* IOSLOT slot[1+nslots]; */ /* array of slots: slot[0] is not used; slot[p], 1 <= p <= nslots, either contains a pointer to some node of the branch-and-bound tree, in which case p is used on API level as the reference number of corresponding subproblem, or is free; all free slots are linked into single linked list; slot[1] always contains a pointer to the root node (it is free only if the tree is empty) */ IOSNPD *head; /* pointer to the head of the active list */ IOSNPD *tail; /* pointer to the tail of the active list */ /* the active list is a doubly linked list of active subproblems which correspond to leaves of the tree; all subproblems in the active list are ordered chronologically (each a new subproblem is always added to the tail of the list) */ int a_cnt; /* current number of active nodes (including the current one) */ int n_cnt; /* current number of all (active and inactive) nodes */ int t_cnt; /* total number of nodes including those which have been already removed from the tree; this count is increased by one whenever a new node is created and never decreased */ /*--------------------------------------------------------------*/ /* problem components corresponding to the root subproblem */ int root_m; /* number of rows */ unsigned char *root_type; /* uchar root_type[1+root_m+n]; */ /* types of all variables */ double *root_lb; /* double root_lb[1+root_m+n]; */ /* lower bounds of all variables */ double *root_ub; /* double root_ub[1+root_m+n]; */ /* upper bounds of all variables */ unsigned char *root_stat; /* uchar root_stat[1+root_m+n]; */ /* statuses of all variables */ /*--------------------------------------------------------------*/ /* current subproblem and its LP relaxation */ IOSNPD *curr; /* pointer to the current subproblem (which can be only active); NULL means the current subproblem does not exist */ glp_prob *mip; /* original problem object passed to the solver; if the current subproblem exists, its LP segment corresponds to LP relaxation of the current subproblem; if the current subproblem does not exist, its LP segment corresponds to LP relaxation of the root subproblem (note that the root subproblem may differ from the original MIP, because it may be preprocessed and/or may have additional rows) */ unsigned char *non_int; /* uchar non_int[1+n]; */ /* these column flags are set each time when LP relaxation of the current subproblem has been solved; non_int[0] is not used; non_int[j], 1 <= j <= n, is j-th column flag; if this flag is set, corresponding variable is required to be integer, but its value in basic solution is fractional */ /*--------------------------------------------------------------*/ /* problem components corresponding to the parent (predecessor) subproblem for the current subproblem; used to inspect changes on freezing the current subproblem */ int pred_m; /* number of rows */ int pred_max; /* length of the following four arrays (enlarged automatically), pred_max >= pred_m + n */ unsigned char *pred_type; /* uchar pred_type[1+pred_m+n]; */ /* types of all variables */ double *pred_lb; /* double pred_lb[1+pred_m+n]; */ /* lower bounds of all variables */ double *pred_ub; /* double pred_ub[1+pred_m+n]; */ /* upper bounds of all variables */ unsigned char *pred_stat; /* uchar pred_stat[1+pred_m+n]; */ /* statuses of all variables */ /****************************************************************/ /* built-in cut generators segment */ IOSPOOL *local; /* local cut pool */ void *mir_gen; /* pointer to working area used by the MIR cut generator */ void *clq_gen; /* pointer to working area used by the clique cut generator */ /*--------------------------------------------------------------*/ void *pcost; /* pointer to working area used on pseudocost branching */ int *iwrk; /* int iwrk[1+n]; */ /* working array */ double *dwrk; /* double dwrk[1+n]; */ /* working array */ /*--------------------------------------------------------------*/ /* control parameters and statistics */ const glp_iocp *parm; /* copy of control parameters passed to the solver */ #if 0 /* 10/VI-2013 */ glp_long tm_beg; #else double tm_beg; #endif /* starting time of the search, in seconds; the total time of the search is the difference between xtime() and tm_beg */ #if 0 /* 10/VI-2013 */ glp_long tm_lag; #else double tm_lag; #endif /* the most recent time, in seconds, at which the progress of the the search was displayed */ int sol_cnt; /* number of integer feasible solutions found */ #if 1 /* 11/VII-2013 */ void *P; /* glp_prob *P; */ /* problem passed to glp_intopt */ void *npp; /* NPP *npp; */ /* preprocessor workspace or NULL */ const char *save_sol; /* filename (template) to save every new solution */ int save_cnt; /* count to generate filename */ #endif /*--------------------------------------------------------------*/ /* advanced solver interface */ int reason; /* flag indicating the reason why the callback routine is being called (see glpk.h) */ int stop; /* flag indicating that the callback routine requires premature termination of the search */ int next_p; /* reference number of active subproblem selected to continue the search; 0 means no subproblem has been selected */ int reopt; /* flag indicating that the current LP relaxation needs to be re-optimized */ int reinv; /* flag indicating that some (non-active) rows were removed from the current LP relaxation, so if there no new rows appear, the basis must be re-factorized */ int br_var; /* the number of variable chosen to branch on */ int br_sel; /* flag indicating which branch (subproblem) is suggested to be selected to continue the search: GLP_DN_BRNCH - select down-branch GLP_UP_BRNCH - select up-branch GLP_NO_BRNCH - use general selection technique */ int child; /* subproblem reference number corresponding to br_sel */ }; struct IOSLOT { /* node subproblem slot */ IOSNPD *node; /* pointer to subproblem descriptor; NULL means free slot */ int next; /* index of another free slot (only if this slot is free) */ }; struct IOSNPD { /* node subproblem descriptor */ int p; /* subproblem reference number (it is the index to corresponding slot, i.e. slot[p] points to this descriptor) */ IOSNPD *up; /* pointer to the parent subproblem; NULL means this node is the root of the tree, in which case p = 1 */ int level; /* node level (the root node has level 0) */ int count; /* if count = 0, this subproblem is active; if count > 0, this subproblem is inactive, in which case count is the number of its child subproblems */ /* the following three linked lists are destroyed on reviving and built anew on freezing the subproblem: */ IOSBND *b_ptr; /* linked list of rows and columns of the parent subproblem whose types and bounds were changed */ IOSTAT *s_ptr; /* linked list of rows and columns of the parent subproblem whose statuses were changed */ IOSROW *r_ptr; /* linked list of rows (cuts) added to the parent subproblem */ int solved; /* how many times LP relaxation of this subproblem was solved; for inactive subproblem this count is always non-zero; for active subproblem, which is not current, this count may be non-zero, if the subproblem was temporarily suspended */ double lp_obj; /* optimal objective value to LP relaxation of this subproblem; on creating a subproblem this value is inherited from its parent; for the root subproblem, which has no parent, this value is initially set to -DBL_MAX (minimization) or +DBL_MAX (maximization); each time the subproblem is re-optimized, this value is appropriately changed */ double bound; /* local lower (minimization) or upper (maximization) bound for integer optimal solution to *this* subproblem; this bound is local in the sense that only subproblems in the subtree rooted at this node cannot have better integer feasible solutions; on creating a subproblem its local bound is inherited from its parent and then can be made stronger (never weaker); for the root subproblem its local bound is initially set to -DBL_MAX (minimization) or +DBL_MAX (maximization) and then improved as the root LP relaxation has been solved */ /* the following two quantities are defined only if LP relaxation of this subproblem was solved at least once (solved > 0): */ int ii_cnt; /* number of integer variables whose value in optimal solution to LP relaxation of this subproblem is fractional */ double ii_sum; /* sum of integer infeasibilities */ #if 1 /* 30/XI-2009 */ int changed; /* how many times this subproblem was re-formulated (by adding cutting plane constraints) */ #endif int br_var; /* ordinal number of branching variable, 1 <= br_var <= n, used to split this subproblem; 0 means that either this subproblem is active or branching was made on a constraint */ double br_val; /* (fractional) value of branching variable in optimal solution to final LP relaxation of this subproblem */ void *data; /* char data[tree->cb_size]; */ /* pointer to the application-specific data */ IOSNPD *temp; /* working pointer used by some routines */ IOSNPD *prev; /* pointer to previous subproblem in the active list */ IOSNPD *next; /* pointer to next subproblem in the active list */ }; struct IOSBND { /* bounds change entry */ int k; /* ordinal number of corresponding row (1 <= k <= m) or column (m+1 <= k <= m+n), where m and n are the number of rows and columns, resp., in the parent subproblem */ unsigned char type; /* new type */ double lb; /* new lower bound */ double ub; /* new upper bound */ IOSBND *next; /* pointer to next entry for the same subproblem */ }; struct IOSTAT { /* status change entry */ int k; /* ordinal number of corresponding row (1 <= k <= m) or column (m+1 <= k <= m+n), where m and n are the number of rows and columns, resp., in the parent subproblem */ unsigned char stat; /* new status */ IOSTAT *next; /* pointer to next entry for the same subproblem */ }; struct IOSROW { /* row (constraint) addition entry */ char *name; /* row name or NULL */ unsigned char origin; /* row origin flag (see glp_attr.origin) */ unsigned char klass; /* row class descriptor (see glp_attr.klass) */ unsigned char type; /* row type (GLP_LO, GLP_UP, etc.) */ double lb; /* row lower bound */ double ub; /* row upper bound */ IOSAIJ *ptr; /* pointer to the row coefficient list */ double rii; /* row scale factor */ unsigned char stat; /* row status (GLP_BS, GLP_NL, etc.) */ IOSROW *next; /* pointer to next entry for the same subproblem */ }; struct IOSAIJ { /* constraint coefficient */ int j; /* variable (column) number, 1 <= j <= n */ double val; /* non-zero coefficient value */ IOSAIJ *next; /* pointer to next coefficient for the same row */ }; struct IOSPOOL { /* cut pool */ int size; /* pool size = number of cuts in the pool */ IOSCUT *head; /* pointer to the first cut */ IOSCUT *tail; /* pointer to the last cut */ int ord; /* ordinal number of the current cut, 1 <= ord <= size */ IOSCUT *curr; /* pointer to the current cut */ }; struct IOSCUT { /* cut (cutting plane constraint) */ char *name; /* cut name or NULL */ unsigned char klass; /* cut class descriptor (see glp_attr.klass) */ IOSAIJ *ptr; /* pointer to the cut coefficient list */ unsigned char type; /* cut type: GLP_LO: sum a[j] * x[j] >= b GLP_UP: sum a[j] * x[j] <= b GLP_FX: sum a[j] * x[j] = b */ double rhs; /* cut right-hand side */ IOSCUT *prev; /* pointer to previous cut */ IOSCUT *next; /* pointer to next cut */ }; #define ios_create_tree _glp_ios_create_tree glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm); /* create branch-and-bound tree */ #define ios_revive_node _glp_ios_revive_node void ios_revive_node(glp_tree *tree, int p); /* revive specified subproblem */ #define ios_freeze_node _glp_ios_freeze_node void ios_freeze_node(glp_tree *tree); /* freeze current subproblem */ #define ios_clone_node _glp_ios_clone_node void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[]); /* clone specified subproblem */ #define ios_delete_node _glp_ios_delete_node void ios_delete_node(glp_tree *tree, int p); /* delete specified subproblem */ #define ios_delete_tree _glp_ios_delete_tree void ios_delete_tree(glp_tree *tree); /* delete branch-and-bound tree */ #define ios_eval_degrad _glp_ios_eval_degrad void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up); /* estimate obj. degrad. for down- and up-branches */ #define ios_round_bound _glp_ios_round_bound double ios_round_bound(glp_tree *tree, double bound); /* improve local bound by rounding */ #define ios_is_hopeful _glp_ios_is_hopeful int ios_is_hopeful(glp_tree *tree, double bound); /* check if subproblem is hopeful */ #define ios_best_node _glp_ios_best_node int ios_best_node(glp_tree *tree); /* find active node with best local bound */ #define ios_relative_gap _glp_ios_relative_gap double ios_relative_gap(glp_tree *tree); /* compute relative mip gap */ #define ios_solve_node _glp_ios_solve_node int ios_solve_node(glp_tree *tree); /* solve LP relaxation of current subproblem */ #define ios_create_pool _glp_ios_create_pool IOSPOOL *ios_create_pool(glp_tree *tree); /* create cut pool */ #define ios_add_row _glp_ios_add_row int ios_add_row(glp_tree *tree, IOSPOOL *pool, const char *name, int klass, int flags, int len, const int ind[], const double val[], int type, double rhs); /* add row (constraint) to the cut pool */ #define ios_find_row _glp_ios_find_row IOSCUT *ios_find_row(IOSPOOL *pool, int i); /* find row (constraint) in the cut pool */ #define ios_del_row _glp_ios_del_row void ios_del_row(glp_tree *tree, IOSPOOL *pool, int i); /* remove row (constraint) from the cut pool */ #define ios_clear_pool _glp_ios_clear_pool void ios_clear_pool(glp_tree *tree, IOSPOOL *pool); /* remove all rows (constraints) from the cut pool */ #define ios_delete_pool _glp_ios_delete_pool void ios_delete_pool(glp_tree *tree, IOSPOOL *pool); /* delete cut pool */ #if 1 /* 11/VII-2013 */ #define ios_process_sol _glp_ios_process_sol void ios_process_sol(glp_tree *T); /* process integer feasible solution just found */ #endif #define ios_preprocess_node _glp_ios_preprocess_node int ios_preprocess_node(glp_tree *tree, int max_pass); /* preprocess current subproblem */ #define ios_driver _glp_ios_driver int ios_driver(glp_tree *tree); /* branch-and-bound driver */ /**********************************************************************/ typedef struct IOSVEC IOSVEC; struct IOSVEC { /* sparse vector v = (v[j]) */ int n; /* dimension, n >= 0 */ int nnz; /* number of non-zero components, 0 <= nnz <= n */ int *pos; /* int pos[1+n]; */ /* pos[j] = k, 1 <= j <= n, is position of (non-zero) v[j] in the arrays ind and val, where 1 <= k <= nnz; pos[j] = 0 means that v[j] is structural zero */ int *ind; /* int ind[1+n]; */ /* ind[k] = j, 1 <= k <= nnz, is index of v[j] */ double *val; /* double val[1+n]; */ /* val[k], 1 <= k <= nnz, is a numeric value of v[j] */ }; #define ios_create_vec _glp_ios_create_vec IOSVEC *ios_create_vec(int n); /* create sparse vector */ #define ios_check_vec _glp_ios_check_vec void ios_check_vec(IOSVEC *v); /* check that sparse vector has correct representation */ #define ios_get_vj _glp_ios_get_vj double ios_get_vj(IOSVEC *v, int j); /* retrieve component of sparse vector */ #define ios_set_vj _glp_ios_set_vj void ios_set_vj(IOSVEC *v, int j, double val); /* set/change component of sparse vector */ #define ios_clear_vec _glp_ios_clear_vec void ios_clear_vec(IOSVEC *v); /* set all components of sparse vector to zero */ #define ios_clean_vec _glp_ios_clean_vec void ios_clean_vec(IOSVEC *v, double eps); /* remove zero or small components from sparse vector */ #define ios_copy_vec _glp_ios_copy_vec void ios_copy_vec(IOSVEC *x, IOSVEC *y); /* copy sparse vector (x := y) */ #define ios_linear_comb _glp_ios_linear_comb void ios_linear_comb(IOSVEC *x, double a, IOSVEC *y); /* compute linear combination (x := x + a * y) */ #define ios_delete_vec _glp_ios_delete_vec void ios_delete_vec(IOSVEC *v); /* delete sparse vector */ /**********************************************************************/ #define ios_gmi_gen _glp_ios_gmi_gen void ios_gmi_gen(glp_tree *tree); /* generate Gomory's mixed integer cuts */ #define ios_mir_init _glp_ios_mir_init void *ios_mir_init(glp_tree *tree); /* initialize MIR cut generator */ #define ios_mir_gen _glp_ios_mir_gen void ios_mir_gen(glp_tree *tree, void *gen); /* generate MIR cuts */ #define ios_mir_term _glp_ios_mir_term void ios_mir_term(void *gen); /* terminate MIR cut generator */ #define ios_cov_gen _glp_ios_cov_gen void ios_cov_gen(glp_tree *tree); /* generate mixed cover cuts */ #define ios_clq_init _glp_ios_clq_init void *ios_clq_init(glp_tree *tree); /* initialize clique cut generator */ #define ios_clq_gen _glp_ios_clq_gen void ios_clq_gen(glp_tree *tree, void *gen); /* generate clique cuts */ #define ios_clq_term _glp_ios_clq_term void ios_clq_term(void *gen); /* terminate clique cut generator */ #define ios_pcost_init _glp_ios_pcost_init void *ios_pcost_init(glp_tree *tree); /* initialize working data used on pseudocost branching */ #define ios_pcost_branch _glp_ios_pcost_branch int ios_pcost_branch(glp_tree *T, int *next); /* choose branching variable with pseudocost branching */ #define ios_pcost_update _glp_ios_pcost_update void ios_pcost_update(glp_tree *tree); /* update history information for pseudocost branching */ #define ios_pcost_free _glp_ios_pcost_free void ios_pcost_free(glp_tree *tree); /* free working area used on pseudocost branching */ #define ios_feas_pump _glp_ios_feas_pump void ios_feas_pump(glp_tree *T); /* feasibility pump heuristic */ #if 1 /* 25/V-2013 */ #define ios_proxy_heur _glp_ios_proxy_heur void ios_proxy_heur(glp_tree *T); /* proximity search heuristic */ #endif #define ios_process_cuts _glp_ios_process_cuts void ios_process_cuts(glp_tree *T); /* process cuts stored in the local cut pool */ #define ios_choose_node _glp_ios_choose_node int ios_choose_node(glp_tree *T); /* select subproblem to continue the search */ #define ios_choose_var _glp_ios_choose_var int ios_choose_var(glp_tree *T, int *next); /* select variable to branch on */ #endif /* eof */ Rglpk/src/GLPK/wclique.h0000644000176000001440000000240212245352174014532 0ustar ripleyusers/* wclique.h (maximum weight clique, Ostergard's algorithm) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2009, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef WCLIQUE_H #define WCLIQUE_H #define wclique _glp_wclique int wclique(int n, const int w[], const unsigned char a[], int ind[]); /* find maximum weight clique with Ostergard's algorithm */ #endif /* eof */ Rglpk/src/GLPK/glpapi05.c0000644000176000001440000001314512245352174014503 0ustar ripleyusers/* glpapi05.c (LP basis constructing routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpapi.h" /*********************************************************************** * NAME * * glp_set_row_stat - set (change) row status * * SYNOPSIS * * void glp_set_row_stat(glp_prob *lp, int i, int stat); * * DESCRIPTION * * The routine glp_set_row_stat sets (changes) status of the auxiliary * variable associated with i-th row. * * The new status of the auxiliary variable should be specified by the * parameter stat as follows: * * GLP_BS - basic variable; * GLP_NL - non-basic variable; * GLP_NU - non-basic variable on its upper bound; if the variable is * not double-bounded, this means the same as GLP_NL (only in * case of this routine); * GLP_NF - the same as GLP_NL (only in case of this routine); * GLP_NS - the same as GLP_NL (only in case of this routine). */ void glp_set_row_stat(glp_prob *lp, int i, int stat) { GLPROW *row; if (!(1 <= i && i <= lp->m)) xerror("glp_set_row_stat: i = %d; row number out of range\n", i); if (!(stat == GLP_BS || stat == GLP_NL || stat == GLP_NU || stat == GLP_NF || stat == GLP_NS)) xerror("glp_set_row_stat: i = %d; stat = %d; invalid status\n", i, stat); row = lp->row[i]; if (stat != GLP_BS) { switch (row->type) { case GLP_FR: stat = GLP_NF; break; case GLP_LO: stat = GLP_NL; break; case GLP_UP: stat = GLP_NU; break; case GLP_DB: if (stat != GLP_NU) stat = GLP_NL; break; case GLP_FX: stat = GLP_NS; break; default: xassert(row != row); } } if (row->stat == GLP_BS && stat != GLP_BS || row->stat != GLP_BS && stat == GLP_BS) { /* invalidate the basis factorization */ lp->valid = 0; } row->stat = stat; return; } /*********************************************************************** * NAME * * glp_set_col_stat - set (change) column status * * SYNOPSIS * * void glp_set_col_stat(glp_prob *lp, int j, int stat); * * DESCRIPTION * * The routine glp_set_col_stat sets (changes) status of the structural * variable associated with j-th column. * * The new status of the structural variable should be specified by the * parameter stat as follows: * * GLP_BS - basic variable; * GLP_NL - non-basic variable; * GLP_NU - non-basic variable on its upper bound; if the variable is * not double-bounded, this means the same as GLP_NL (only in * case of this routine); * GLP_NF - the same as GLP_NL (only in case of this routine); * GLP_NS - the same as GLP_NL (only in case of this routine). */ void glp_set_col_stat(glp_prob *lp, int j, int stat) { GLPCOL *col; if (!(1 <= j && j <= lp->n)) xerror("glp_set_col_stat: j = %d; column number out of range\n" , j); if (!(stat == GLP_BS || stat == GLP_NL || stat == GLP_NU || stat == GLP_NF || stat == GLP_NS)) xerror("glp_set_col_stat: j = %d; stat = %d; invalid status\n", j, stat); col = lp->col[j]; if (stat != GLP_BS) { switch (col->type) { case GLP_FR: stat = GLP_NF; break; case GLP_LO: stat = GLP_NL; break; case GLP_UP: stat = GLP_NU; break; case GLP_DB: if (stat != GLP_NU) stat = GLP_NL; break; case GLP_FX: stat = GLP_NS; break; default: xassert(col != col); } } if (col->stat == GLP_BS && stat != GLP_BS || col->stat != GLP_BS && stat == GLP_BS) { /* invalidate the basis factorization */ lp->valid = 0; } col->stat = stat; return; } /*********************************************************************** * NAME * * glp_std_basis - construct standard initial LP basis * * SYNOPSIS * * void glp_std_basis(glp_prob *lp); * * DESCRIPTION * * The routine glp_std_basis builds the "standard" (trivial) initial * basis for the specified problem object. * * In the "standard" basis all auxiliary variables are basic, and all * structural variables are non-basic. */ void glp_std_basis(glp_prob *lp) { int i, j; /* make all auxiliary variables basic */ for (i = 1; i <= lp->m; i++) glp_set_row_stat(lp, i, GLP_BS); /* make all structural variables non-basic */ for (j = 1; j <= lp->n; j++) { GLPCOL *col = lp->col[j]; if (col->type == GLP_DB && fabs(col->lb) > fabs(col->ub)) glp_set_col_stat(lp, j, GLP_NU); else glp_set_col_stat(lp, j, GLP_NL); } return; } /* eof */ Rglpk/src/GLPK/glpapi14.c0000644000176000001440000002203312245352174014477 0ustar ripleyusers/* glpapi14.c (processing models in GNU MathProg language) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpapi.h" #include "glpmpl.h" glp_tran *glp_mpl_alloc_wksp(void) { /* allocate the MathProg translator workspace */ glp_tran *tran; tran = mpl_initialize(); return tran; } #if 1 /* 08/XII-2009 */ void _glp_mpl_init_rand(glp_tran *tran, int seed) { if (tran->phase != 0) xerror("glp_mpl_init_rand: invalid call sequence\n"); rng_init_rand(tran->rand, seed); return; } #endif int glp_mpl_read_model(glp_tran *tran, const char *fname, int skip) { /* read and translate model section */ int ret; if (tran->phase != 0) xerror("glp_mpl_read_model: invalid call sequence\n"); ret = mpl_read_model(tran, (char *)fname, skip); if (ret == 1 || ret == 2) ret = 0; else if (ret == 4) ret = 1; else xassert(ret != ret); return ret; } int glp_mpl_read_data(glp_tran *tran, const char *fname) { /* read and translate data section */ int ret; if (!(tran->phase == 1 || tran->phase == 2)) xerror("glp_mpl_read_data: invalid call sequence\n"); ret = mpl_read_data(tran, (char *)fname); if (ret == 2) ret = 0; else if (ret == 4) ret = 1; else xassert(ret != ret); return ret; } int glp_mpl_generate(glp_tran *tran, const char *fname) { /* generate the model */ int ret; if (!(tran->phase == 1 || tran->phase == 2)) xerror("glp_mpl_generate: invalid call sequence\n"); ret = mpl_generate(tran, (char *)fname); if (ret == 3) ret = 0; else if (ret == 4) ret = 1; return ret; } void glp_mpl_build_prob(glp_tran *tran, glp_prob *prob) { /* build LP/MIP problem instance from the model */ int m, n, i, j, t, kind, type, len, *ind; double lb, ub, *val; if (tran->phase != 3) xerror("glp_mpl_build_prob: invalid call sequence\n"); /* erase the problem object */ glp_erase_prob(prob); /* set problem name */ glp_set_prob_name(prob, mpl_get_prob_name(tran)); /* build rows (constraints) */ m = mpl_get_num_rows(tran); if (m > 0) glp_add_rows(prob, m); for (i = 1; i <= m; i++) { /* set row name */ glp_set_row_name(prob, i, mpl_get_row_name(tran, i)); /* set row bounds */ type = mpl_get_row_bnds(tran, i, &lb, &ub); switch (type) { case MPL_FR: type = GLP_FR; break; case MPL_LO: type = GLP_LO; break; case MPL_UP: type = GLP_UP; break; case MPL_DB: type = GLP_DB; break; case MPL_FX: type = GLP_FX; break; default: xassert(type != type); } if (type == GLP_DB && fabs(lb - ub) < 1e-9 * (1.0 + fabs(lb))) { type = GLP_FX; if (fabs(lb) <= fabs(ub)) ub = lb; else lb = ub; } glp_set_row_bnds(prob, i, type, lb, ub); /* warn about non-zero constant term */ if (mpl_get_row_c0(tran, i) != 0.0) xprintf("glp_mpl_build_prob: row %s; constant term %.12g ig" "nored\n", mpl_get_row_name(tran, i), mpl_get_row_c0(tran, i)); } /* build columns (variables) */ n = mpl_get_num_cols(tran); if (n > 0) glp_add_cols(prob, n); for (j = 1; j <= n; j++) { /* set column name */ glp_set_col_name(prob, j, mpl_get_col_name(tran, j)); /* set column kind */ kind = mpl_get_col_kind(tran, j); switch (kind) { case MPL_NUM: break; case MPL_INT: case MPL_BIN: glp_set_col_kind(prob, j, GLP_IV); break; default: xassert(kind != kind); } /* set column bounds */ type = mpl_get_col_bnds(tran, j, &lb, &ub); switch (type) { case MPL_FR: type = GLP_FR; break; case MPL_LO: type = GLP_LO; break; case MPL_UP: type = GLP_UP; break; case MPL_DB: type = GLP_DB; break; case MPL_FX: type = GLP_FX; break; default: xassert(type != type); } if (kind == MPL_BIN) { if (type == GLP_FR || type == GLP_UP || lb < 0.0) lb = 0.0; if (type == GLP_FR || type == GLP_LO || ub > 1.0) ub = 1.0; type = GLP_DB; } if (type == GLP_DB && fabs(lb - ub) < 1e-9 * (1.0 + fabs(lb))) { type = GLP_FX; if (fabs(lb) <= fabs(ub)) ub = lb; else lb = ub; } glp_set_col_bnds(prob, j, type, lb, ub); } /* load the constraint matrix */ ind = xcalloc(1+n, sizeof(int)); val = xcalloc(1+n, sizeof(double)); for (i = 1; i <= m; i++) { len = mpl_get_mat_row(tran, i, ind, val); glp_set_mat_row(prob, i, len, ind, val); } /* build objective function (the first objective is used) */ for (i = 1; i <= m; i++) { kind = mpl_get_row_kind(tran, i); if (kind == MPL_MIN || kind == MPL_MAX) { /* set objective name */ glp_set_obj_name(prob, mpl_get_row_name(tran, i)); /* set optimization direction */ glp_set_obj_dir(prob, kind == MPL_MIN ? GLP_MIN : GLP_MAX); /* set constant term */ glp_set_obj_coef(prob, 0, mpl_get_row_c0(tran, i)); /* set objective coefficients */ len = mpl_get_mat_row(tran, i, ind, val); for (t = 1; t <= len; t++) glp_set_obj_coef(prob, ind[t], val[t]); break; } } /* free working arrays */ xfree(ind); xfree(val); return; } int glp_mpl_postsolve(glp_tran *tran, glp_prob *prob, int sol) { /* postsolve the model */ int i, j, m, n, stat, ret; double prim, dual; if (!(tran->phase == 3 && !tran->flag_p)) xerror("glp_mpl_postsolve: invalid call sequence\n"); if (!(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP)) xerror("glp_mpl_postsolve: sol = %d; invalid parameter\n", sol); m = mpl_get_num_rows(tran); n = mpl_get_num_cols(tran); if (!(m == glp_get_num_rows(prob) && n == glp_get_num_cols(prob))) xerror("glp_mpl_postsolve: wrong problem object\n"); if (!mpl_has_solve_stmt(tran)) { ret = 0; goto done; } for (i = 1; i <= m; i++) { if (sol == GLP_SOL) { stat = glp_get_row_stat(prob, i); prim = glp_get_row_prim(prob, i); dual = glp_get_row_dual(prob, i); } else if (sol == GLP_IPT) { stat = 0; prim = glp_ipt_row_prim(prob, i); dual = glp_ipt_row_dual(prob, i); } else if (sol == GLP_MIP) { stat = 0; prim = glp_mip_row_val(prob, i); dual = 0.0; } else xassert(sol != sol); if (fabs(prim) < 1e-9) prim = 0.0; if (fabs(dual) < 1e-9) dual = 0.0; mpl_put_row_soln(tran, i, stat, prim, dual); } for (j = 1; j <= n; j++) { if (sol == GLP_SOL) { stat = glp_get_col_stat(prob, j); prim = glp_get_col_prim(prob, j); dual = glp_get_col_dual(prob, j); } else if (sol == GLP_IPT) { stat = 0; prim = glp_ipt_col_prim(prob, j); dual = glp_ipt_col_dual(prob, j); } else if (sol == GLP_MIP) { stat = 0; prim = glp_mip_col_val(prob, j); dual = 0.0; } else xassert(sol != sol); if (fabs(prim) < 1e-9) prim = 0.0; if (fabs(dual) < 1e-9) dual = 0.0; mpl_put_col_soln(tran, j, stat, prim, dual); } ret = mpl_postsolve(tran); if (ret == 3) ret = 0; else if (ret == 4) ret = 1; done: return ret; } void glp_mpl_free_wksp(glp_tran *tran) { /* free the MathProg translator workspace */ mpl_terminate(tran); return; } /* eof */ Rglpk/src/GLPK/glpios12.c0000644000176000001440000001327412245352174014525 0ustar ripleyusers/* glpios12.c (node selection heuristics) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpios.h" /*********************************************************************** * NAME * * ios_choose_node - select subproblem to continue the search * * SYNOPSIS * * #include "glpios.h" * int ios_choose_node(glp_tree *T); * * DESCRIPTION * * The routine ios_choose_node selects a subproblem from the active * list to continue the search. The choice depends on the backtracking * technique option. * * RETURNS * * The routine ios_choose_node return the reference number of the * subproblem selected. */ static int most_feas(glp_tree *T); static int best_proj(glp_tree *T); static int best_node(glp_tree *T); int ios_choose_node(glp_tree *T) { int p; if (T->parm->bt_tech == GLP_BT_DFS) { /* depth first search */ xassert(T->tail != NULL); p = T->tail->p; } else if (T->parm->bt_tech == GLP_BT_BFS) { /* breadth first search */ xassert(T->head != NULL); p = T->head->p; } else if (T->parm->bt_tech == GLP_BT_BLB) { /* select node with best local bound */ p = best_node(T); } else if (T->parm->bt_tech == GLP_BT_BPH) { if (T->mip->mip_stat == GLP_UNDEF) { /* "most integer feasible" subproblem */ p = most_feas(T); } else { /* best projection heuristic */ p = best_proj(T); } } else xassert(T != T); return p; } static int most_feas(glp_tree *T) { /* select subproblem whose parent has minimal sum of integer infeasibilities */ IOSNPD *node; int p; double best; p = 0, best = DBL_MAX; for (node = T->head; node != NULL; node = node->next) { xassert(node->up != NULL); if (best > node->up->ii_sum) p = node->p, best = node->up->ii_sum; } return p; } static int best_proj(glp_tree *T) { /* select subproblem using the best projection heuristic */ IOSNPD *root, *node; int p; double best, deg, obj; /* the global bound must exist */ xassert(T->mip->mip_stat == GLP_FEAS); /* obtain pointer to the root node, which must exist */ root = T->slot[1].node; xassert(root != NULL); /* deg estimates degradation of the objective function per unit of the sum of integer infeasibilities */ xassert(root->ii_sum > 0.0); deg = (T->mip->mip_obj - root->bound) / root->ii_sum; /* nothing has been selected so far */ p = 0, best = DBL_MAX; /* walk through the list of active subproblems */ for (node = T->head; node != NULL; node = node->next) { xassert(node->up != NULL); /* obj estimates optimal objective value if the sum of integer infeasibilities were zero */ obj = node->up->bound + deg * node->up->ii_sum; if (T->mip->dir == GLP_MAX) obj = - obj; /* select the subproblem which has the best estimated optimal objective value */ if (best > obj) p = node->p, best = obj; } return p; } static int best_node(glp_tree *T) { /* select subproblem with best local bound */ IOSNPD *node, *best = NULL; double bound, eps; switch (T->mip->dir) { case GLP_MIN: bound = +DBL_MAX; for (node = T->head; node != NULL; node = node->next) if (bound > node->bound) bound = node->bound; xassert(bound != +DBL_MAX); eps = 1e-10 * (1.0 + fabs(bound)); for (node = T->head; node != NULL; node = node->next) { if (node->bound <= bound + eps) { xassert(node->up != NULL); if (best == NULL || #if 1 best->up->ii_sum > node->up->ii_sum) best = node; #else best->lp_obj > node->lp_obj) best = node; #endif } } break; case GLP_MAX: bound = -DBL_MAX; for (node = T->head; node != NULL; node = node->next) if (bound < node->bound) bound = node->bound; xassert(bound != -DBL_MAX); eps = 1e-10 * (1.0 + fabs(bound)); for (node = T->head; node != NULL; node = node->next) { if (node->bound >= bound - eps) { xassert(node->up != NULL); if (best == NULL || #if 1 best->up->ii_sum > node->up->ii_sum) best = node; #else best->lp_obj < node->lp_obj) best = node; #endif } } break; default: xassert(T != T); } xassert(best != NULL); return best->p; } /* eof */ Rglpk/src/GLPK/glpapi17.c0000644000176000001440000012266612245352174014517 0ustar ripleyusers/* glpapi17.c (flow network problems) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpapi.h" #include "ffalg.h" #include "mc21a.h" #include "okalg.h" #include "relax4.h" /*********************************************************************** * NAME * * glp_mincost_lp - convert minimum cost flow problem to LP * * SYNOPSIS * * void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names, * int v_rhs, int a_low, int a_cap, int a_cost); * * DESCRIPTION * * The routine glp_mincost_lp builds an LP problem, which corresponds * to the minimum cost flow problem on the specified network G. */ void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names, int v_rhs, int a_low, int a_cap, int a_cost) { glp_vertex *v; glp_arc *a; int i, j, type, ind[1+2]; double rhs, low, cap, cost, val[1+2]; if (!(names == GLP_ON || names == GLP_OFF)) xerror("glp_mincost_lp: names = %d; invalid parameter\n", names); if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double)) xerror("glp_mincost_lp: v_rhs = %d; invalid offset\n", v_rhs); if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double)) xerror("glp_mincost_lp: a_low = %d; invalid offset\n", a_low); if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) xerror("glp_mincost_lp: a_cap = %d; invalid offset\n", a_cap); if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) xerror("glp_mincost_lp: a_cost = %d; invalid offset\n", a_cost) ; glp_erase_prob(lp); if (names) glp_set_prob_name(lp, G->name); if (G->nv > 0) glp_add_rows(lp, G->nv); for (i = 1; i <= G->nv; i++) { v = G->v[i]; if (names) glp_set_row_name(lp, i, v->name); if (v_rhs >= 0) memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double)); else rhs = 0.0; glp_set_row_bnds(lp, i, GLP_FX, rhs, rhs); } if (G->na > 0) glp_add_cols(lp, G->na); for (i = 1, j = 0; i <= G->nv; i++) { v = G->v[i]; for (a = v->out; a != NULL; a = a->t_next) { j++; if (names) { char name[50+1]; sprintf(name, "x[%d,%d]", a->tail->i, a->head->i); xassert(strlen(name) < sizeof(name)); glp_set_col_name(lp, j, name); } if (a->tail->i != a->head->i) { ind[1] = a->tail->i, val[1] = +1.0; ind[2] = a->head->i, val[2] = -1.0; glp_set_mat_col(lp, j, 2, ind, val); } if (a_low >= 0) memcpy(&low, (char *)a->data + a_low, sizeof(double)); else low = 0.0; if (a_cap >= 0) memcpy(&cap, (char *)a->data + a_cap, sizeof(double)); else cap = 1.0; if (cap == DBL_MAX) type = GLP_LO; else if (low != cap) type = GLP_DB; else type = GLP_FX; glp_set_col_bnds(lp, j, type, low, cap); if (a_cost >= 0) memcpy(&cost, (char *)a->data + a_cost, sizeof(double)); else cost = 0.0; glp_set_obj_coef(lp, j, cost); } } xassert(j == G->na); return; } /**********************************************************************/ int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low, int a_cap, int a_cost, double *sol, int a_x, int v_pi) { /* find minimum-cost flow with out-of-kilter algorithm */ glp_vertex *v; glp_arc *a; int nv, na, i, k, s, t, *tail, *head, *low, *cap, *cost, *x, *pi, ret; double sum, temp; if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double)) xerror("glp_mincost_okalg: v_rhs = %d; invalid offset\n", v_rhs); if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double)) xerror("glp_mincost_okalg: a_low = %d; invalid offset\n", a_low); if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) xerror("glp_mincost_okalg: a_cap = %d; invalid offset\n", a_cap); if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) xerror("glp_mincost_okalg: a_cost = %d; invalid offset\n", a_cost); if (a_x >= 0 && a_x > G->a_size - (int)sizeof(double)) xerror("glp_mincost_okalg: a_x = %d; invalid offset\n", a_x); if (v_pi >= 0 && v_pi > G->v_size - (int)sizeof(double)) xerror("glp_mincost_okalg: v_pi = %d; invalid offset\n", v_pi); /* s is artificial source node */ s = G->nv + 1; /* t is artificial sink node */ t = s + 1; /* nv is the total number of nodes in the resulting network */ nv = t; /* na is the total number of arcs in the resulting network */ na = G->na + 1; for (i = 1; i <= G->nv; i++) { v = G->v[i]; if (v_rhs >= 0) memcpy(&temp, (char *)v->data + v_rhs, sizeof(double)); else temp = 0.0; if (temp != 0.0) na++; } /* allocate working arrays */ tail = xcalloc(1+na, sizeof(int)); head = xcalloc(1+na, sizeof(int)); low = xcalloc(1+na, sizeof(int)); cap = xcalloc(1+na, sizeof(int)); cost = xcalloc(1+na, sizeof(int)); x = xcalloc(1+na, sizeof(int)); pi = xcalloc(1+nv, sizeof(int)); /* construct the resulting network */ k = 0; /* (original arcs) */ for (i = 1; i <= G->nv; i++) { v = G->v[i]; for (a = v->out; a != NULL; a = a->t_next) { k++; tail[k] = a->tail->i; head[k] = a->head->i; if (tail[k] == head[k]) { ret = GLP_EDATA; goto done; } if (a_low >= 0) memcpy(&temp, (char *)a->data + a_low, sizeof(double)); else temp = 0.0; if (!(0.0 <= temp && temp <= (double)INT_MAX && temp == floor(temp))) { ret = GLP_EDATA; goto done; } low[k] = (int)temp; if (a_cap >= 0) memcpy(&temp, (char *)a->data + a_cap, sizeof(double)); else temp = 1.0; if (!((double)low[k] <= temp && temp <= (double)INT_MAX && temp == floor(temp))) { ret = GLP_EDATA; goto done; } cap[k] = (int)temp; if (a_cost >= 0) memcpy(&temp, (char *)a->data + a_cost, sizeof(double)); else temp = 0.0; if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp))) { ret = GLP_EDATA; goto done; } cost[k] = (int)temp; } } /* (artificial arcs) */ sum = 0.0; for (i = 1; i <= G->nv; i++) { v = G->v[i]; if (v_rhs >= 0) memcpy(&temp, (char *)v->data + v_rhs, sizeof(double)); else temp = 0.0; if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp))) { ret = GLP_EDATA; goto done; } if (temp > 0.0) { /* artificial arc from s to original source i */ k++; tail[k] = s; head[k] = i; low[k] = cap[k] = (int)(+temp); /* supply */ cost[k] = 0; sum += (double)temp; } else if (temp < 0.0) { /* artificial arc from original sink i to t */ k++; tail[k] = i; head[k] = t; low[k] = cap[k] = (int)(-temp); /* demand */ cost[k] = 0; } } /* (feedback arc from t to s) */ k++; xassert(k == na); tail[k] = t; head[k] = s; if (sum > (double)INT_MAX) { ret = GLP_EDATA; goto done; } low[k] = cap[k] = (int)sum; /* total supply/demand */ cost[k] = 0; /* find minimal-cost circulation in the resulting network */ ret = okalg(nv, na, tail, head, low, cap, cost, x, pi); switch (ret) { case 0: /* optimal circulation found */ ret = 0; break; case 1: /* no feasible circulation exists */ ret = GLP_ENOPFS; break; case 2: /* integer overflow occured */ ret = GLP_ERANGE; goto done; case 3: /* optimality test failed (logic error) */ ret = GLP_EFAIL; goto done; default: xassert(ret != ret); } /* store solution components */ /* (objective function = the total cost) */ if (sol != NULL) { temp = 0.0; for (k = 1; k <= na; k++) temp += (double)cost[k] * (double)x[k]; *sol = temp; } /* (arc flows) */ if (a_x >= 0) { k = 0; for (i = 1; i <= G->nv; i++) { v = G->v[i]; for (a = v->out; a != NULL; a = a->t_next) { temp = (double)x[++k]; memcpy((char *)a->data + a_x, &temp, sizeof(double)); } } } /* (node potentials = Lagrange multipliers) */ if (v_pi >= 0) { for (i = 1; i <= G->nv; i++) { v = G->v[i]; temp = - (double)pi[i]; memcpy((char *)v->data + v_pi, &temp, sizeof(double)); } } done: /* free working arrays */ xfree(tail); xfree(head); xfree(low); xfree(cap); xfree(cost); xfree(x); xfree(pi); return ret; } /**********************************************************************/ static int overflow(int u, int v) { /* check for integer overflow on computing u + v */ if (u > 0 && v > 0 && u + v < 0) return 1; if (u < 0 && v < 0 && u + v > 0) return 1; return 0; } int glp_mincost_relax4(glp_graph *G, int v_rhs, int a_low, int a_cap, int a_cost, int crash, double *sol, int a_x, int a_rc) { /* find minimum-cost flow with Bertsekas-Tseng relaxation method (RELAX-IV) */ glp_vertex *v; glp_arc *a; struct relax4_csa csa; int i, k, large, n, na, ret; double cap, cost, low, rc, rhs, sum, x; if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double)) xerror("glp_mincost_relax4: v_rhs = %d; invalid offset\n", v_rhs); if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double)) xerror("glp_mincost_relax4: a_low = %d; invalid offset\n", a_low); if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) xerror("glp_mincost_relax4: a_cap = %d; invalid offset\n", a_cap); if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) xerror("glp_mincost_relax4: a_cost = %d; invalid offset\n", a_cost); if (a_x >= 0 && a_x > G->a_size - (int)sizeof(double)) xerror("glp_mincost_relax4: a_x = %d; invalid offset\n", a_x); if (a_rc >= 0 && a_rc > G->a_size - (int)sizeof(double)) xerror("glp_mincost_relax4: a_rc = %d; invalid offset\n", a_rc); csa.n = n = G->nv; /* number of nodes */ csa.na = na = G->na; /* number of arcs */ csa.large = large = INT_MAX / 4; csa.repeat = 0; csa.crash = crash; /* allocate working arrays */ csa.startn = xcalloc(1+na, sizeof(int)); csa.endn = xcalloc(1+na, sizeof(int)); csa.fou = xcalloc(1+n, sizeof(int)); csa.nxtou = xcalloc(1+na, sizeof(int)); csa.fin = xcalloc(1+n, sizeof(int)); csa.nxtin = xcalloc(1+na, sizeof(int)); csa.rc = xcalloc(1+na, sizeof(int)); csa.u = xcalloc(1+na, sizeof(int)); csa.dfct = xcalloc(1+n, sizeof(int)); csa.x = xcalloc(1+na, sizeof(int)); csa.label = xcalloc(1+n, sizeof(int)); csa.prdcsr = xcalloc(1+n, sizeof(int)); csa.save = xcalloc(1+na, sizeof(int)); csa.tfstou = xcalloc(1+n, sizeof(int)); csa.tnxtou = xcalloc(1+na, sizeof(int)); csa.tfstin = xcalloc(1+n, sizeof(int)); csa.tnxtin = xcalloc(1+na, sizeof(int)); csa.nxtqueue = xcalloc(1+n, sizeof(int)); csa.scan = xcalloc(1+n, sizeof(char)); csa.mark = xcalloc(1+n, sizeof(char)); if (crash) { csa.extend_arc = xcalloc(1+n, sizeof(int)); csa.sb_level = xcalloc(1+n, sizeof(int)); csa.sb_arc = xcalloc(1+n, sizeof(int)); } else { csa.extend_arc = NULL; csa.sb_level = NULL; csa.sb_arc = NULL; } /* scan nodes */ for (i = 1; i <= n; i++) { v = G->v[i]; /* get supply at i-th node */ if (v_rhs >= 0) memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double)); else rhs = 0.0; if (!(fabs(rhs) <= (double)large && rhs == floor(rhs))) { ret = GLP_EDATA; goto done; } /* set demand at i-th node */ csa.dfct[i] = -(int)rhs; } /* scan arcs */ k = 0; for (i = 1; i <= n; i++) { v = G->v[i]; for (a = v->out; a != NULL; a = a->t_next) { k++; /* set endpoints of k-th arc */ if (a->tail->i == a->head->i) { /* self-loops not allowed */ ret = GLP_EDATA; goto done; } csa.startn[k] = a->tail->i; csa.endn[k] = a->head->i; /* set per-unit cost for k-th arc flow */ if (a_cost >= 0) memcpy(&cost, (char *)a->data + a_cost, sizeof(double)); else cost = 0.0; if (!(fabs(cost) <= (double)large && cost == floor(cost))) { ret = GLP_EDATA; goto done; } csa.rc[k] = (int)cost; /* get lower bound for k-th arc flow */ if (a_low >= 0) memcpy(&low, (char *)a->data + a_low, sizeof(double)); else low = 0.0; if (!(0.0 <= low && low <= (double)large && low == floor(low))) { ret = GLP_EDATA; goto done; } /* get upper bound for k-th arc flow */ if (a_cap >= 0) memcpy(&cap, (char *)a->data + a_cap, sizeof(double)); else cap = 1.0; if (!(low <= cap && cap <= (double)large && cap == floor(cap))) { ret = GLP_EDATA; goto done; } /* substitute x = x' + low, where 0 <= x' <= cap - low */ csa.u[k] = (int)(cap - low); /* correct demands at endpoints of k-th arc */ if (overflow(csa.dfct[a->tail->i], +low)) { ret = GLP_ERANGE; goto done; } csa.dfct[a->tail->i] += low; if (overflow(csa.dfct[a->head->i], -low)) { ret = GLP_ERANGE; goto done; } csa.dfct[a->head->i] -= low; } } /* construct linked list for network topology */ relax4_inidat(&csa); /* find minimum-cost flow */ ret = relax4(&csa); if (ret != 0) { /* problem is found to be infeasible */ xassert(1 <= ret && ret <= 8); ret = GLP_ENOPFS; goto done; } /* store solution */ sum = 0.0; k = 0; for (i = 1; i <= n; i++) { v = G->v[i]; for (a = v->out; a != NULL; a = a->t_next) { k++; /* get lower bound for k-th arc flow */ if (a_low >= 0) memcpy(&low, (char *)a->data + a_low, sizeof(double)); else low = 0.0; /* store original flow x = x' + low thru k-th arc */ x = (double)csa.x[k] + low; if (a_x >= 0) memcpy((char *)a->data + a_x, &x, sizeof(double)); /* store reduced cost for k-th arc flow */ rc = (double)csa.rc[k]; if (a_rc >= 0) memcpy((char *)a->data + a_rc, &rc, sizeof(double)); /* get per-unit cost for k-th arc flow */ if (a_cost >= 0) memcpy(&cost, (char *)a->data + a_cost, sizeof(double)); else cost = 0.0; /* compute the total cost */ sum += cost * x; } } /* store the total cost */ if (sol != NULL) *sol = sum; done: /* free working arrays */ xfree(csa.startn); xfree(csa.endn); xfree(csa.fou); xfree(csa.nxtou); xfree(csa.fin); xfree(csa.nxtin); xfree(csa.rc); xfree(csa.u); xfree(csa.dfct); xfree(csa.x); xfree(csa.label); xfree(csa.prdcsr); xfree(csa.save); xfree(csa.tfstou); xfree(csa.tnxtou); xfree(csa.tfstin); xfree(csa.tnxtin); xfree(csa.nxtqueue); xfree(csa.scan); xfree(csa.mark); if (crash) { xfree(csa.extend_arc); xfree(csa.sb_level); xfree(csa.sb_arc); } return ret; } /*********************************************************************** * NAME * * glp_maxflow_lp - convert maximum flow problem to LP * * SYNOPSIS * * void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names, int s, * int t, int a_cap); * * DESCRIPTION * * The routine glp_maxflow_lp builds an LP problem, which corresponds * to the maximum flow problem on the specified network G. */ void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names, int s, int t, int a_cap) { glp_vertex *v; glp_arc *a; int i, j, type, ind[1+2]; double cap, val[1+2]; if (!(names == GLP_ON || names == GLP_OFF)) xerror("glp_maxflow_lp: names = %d; invalid parameter\n", names); if (!(1 <= s && s <= G->nv)) xerror("glp_maxflow_lp: s = %d; source node number out of rang" "e\n", s); if (!(1 <= t && t <= G->nv)) xerror("glp_maxflow_lp: t = %d: sink node number out of range " "\n", t); if (s == t) xerror("glp_maxflow_lp: s = t = %d; source and sink nodes must" " be distinct\n", s); if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) xerror("glp_maxflow_lp: a_cap = %d; invalid offset\n", a_cap); glp_erase_prob(lp); if (names) glp_set_prob_name(lp, G->name); glp_set_obj_dir(lp, GLP_MAX); glp_add_rows(lp, G->nv); for (i = 1; i <= G->nv; i++) { v = G->v[i]; if (names) glp_set_row_name(lp, i, v->name); if (i == s) type = GLP_LO; else if (i == t) type = GLP_UP; else type = GLP_FX; glp_set_row_bnds(lp, i, type, 0.0, 0.0); } if (G->na > 0) glp_add_cols(lp, G->na); for (i = 1, j = 0; i <= G->nv; i++) { v = G->v[i]; for (a = v->out; a != NULL; a = a->t_next) { j++; if (names) { char name[50+1]; sprintf(name, "x[%d,%d]", a->tail->i, a->head->i); xassert(strlen(name) < sizeof(name)); glp_set_col_name(lp, j, name); } if (a->tail->i != a->head->i) { ind[1] = a->tail->i, val[1] = +1.0; ind[2] = a->head->i, val[2] = -1.0; glp_set_mat_col(lp, j, 2, ind, val); } if (a_cap >= 0) memcpy(&cap, (char *)a->data + a_cap, sizeof(double)); else cap = 1.0; if (cap == DBL_MAX) type = GLP_LO; else if (cap != 0.0) type = GLP_DB; else type = GLP_FX; glp_set_col_bnds(lp, j, type, 0.0, cap); if (a->tail->i == s) glp_set_obj_coef(lp, j, +1.0); else if (a->head->i == s) glp_set_obj_coef(lp, j, -1.0); } } xassert(j == G->na); return; } int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap, double *sol, int a_x, int v_cut) { /* find maximal flow with Ford-Fulkerson algorithm */ glp_vertex *v; glp_arc *a; int nv, na, i, k, flag, *tail, *head, *cap, *x, ret; char *cut; double temp; if (!(1 <= s && s <= G->nv)) xerror("glp_maxflow_ffalg: s = %d; source node number out of r" "ange\n", s); if (!(1 <= t && t <= G->nv)) xerror("glp_maxflow_ffalg: t = %d: sink node number out of ran" "ge\n", t); if (s == t) xerror("glp_maxflow_ffalg: s = t = %d; source and sink nodes m" "ust be distinct\n", s); if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) xerror("glp_maxflow_ffalg: a_cap = %d; invalid offset\n", a_cap); if (v_cut >= 0 && v_cut > G->v_size - (int)sizeof(int)) xerror("glp_maxflow_ffalg: v_cut = %d; invalid offset\n", v_cut); /* allocate working arrays */ nv = G->nv; na = G->na; tail = xcalloc(1+na, sizeof(int)); head = xcalloc(1+na, sizeof(int)); cap = xcalloc(1+na, sizeof(int)); x = xcalloc(1+na, sizeof(int)); if (v_cut < 0) cut = NULL; else cut = xcalloc(1+nv, sizeof(char)); /* copy the flow network */ k = 0; for (i = 1; i <= G->nv; i++) { v = G->v[i]; for (a = v->out; a != NULL; a = a->t_next) { k++; tail[k] = a->tail->i; head[k] = a->head->i; if (tail[k] == head[k]) { ret = GLP_EDATA; goto done; } if (a_cap >= 0) memcpy(&temp, (char *)a->data + a_cap, sizeof(double)); else temp = 1.0; if (!(0.0 <= temp && temp <= (double)INT_MAX && temp == floor(temp))) { ret = GLP_EDATA; goto done; } cap[k] = (int)temp; } } xassert(k == na); /* find maximal flow in the flow network */ ffalg(nv, na, tail, head, s, t, cap, x, cut); ret = 0; /* store solution components */ /* (objective function = total flow through the network) */ if (sol != NULL) { temp = 0.0; for (k = 1; k <= na; k++) { if (tail[k] == s) temp += (double)x[k]; else if (head[k] == s) temp -= (double)x[k]; } *sol = temp; } /* (arc flows) */ if (a_x >= 0) { k = 0; for (i = 1; i <= G->nv; i++) { v = G->v[i]; for (a = v->out; a != NULL; a = a->t_next) { temp = (double)x[++k]; memcpy((char *)a->data + a_x, &temp, sizeof(double)); } } } /* (node flags) */ if (v_cut >= 0) { for (i = 1; i <= G->nv; i++) { v = G->v[i]; flag = cut[i]; memcpy((char *)v->data + v_cut, &flag, sizeof(int)); } } done: /* free working arrays */ xfree(tail); xfree(head); xfree(cap); xfree(x); if (cut != NULL) xfree(cut); return ret; } /*********************************************************************** * NAME * * glp_check_asnprob - check correctness of assignment problem data * * SYNOPSIS * * int glp_check_asnprob(glp_graph *G, int v_set); * * RETURNS * * If the specified assignment problem data are correct, the routine * glp_check_asnprob returns zero, otherwise, non-zero. */ int glp_check_asnprob(glp_graph *G, int v_set) { glp_vertex *v; int i, k, ret = 0; if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) xerror("glp_check_asnprob: v_set = %d; invalid offset\n", v_set); for (i = 1; i <= G->nv; i++) { v = G->v[i]; if (v_set >= 0) { memcpy(&k, (char *)v->data + v_set, sizeof(int)); if (k == 0) { if (v->in != NULL) { ret = 1; break; } } else if (k == 1) { if (v->out != NULL) { ret = 2; break; } } else { ret = 3; break; } } else { if (v->in != NULL && v->out != NULL) { ret = 4; break; } } } return ret; } /*********************************************************************** * NAME * * glp_asnprob_lp - convert assignment problem to LP * * SYNOPSIS * * int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names, * int v_set, int a_cost); * * DESCRIPTION * * The routine glp_asnprob_lp builds an LP problem, which corresponds * to the assignment problem on the specified graph G. * * RETURNS * * If the LP problem has been successfully built, the routine returns * zero, otherwise, non-zero. */ int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names, int v_set, int a_cost) { glp_vertex *v; glp_arc *a; int i, j, ret, ind[1+2]; double cost, val[1+2]; if (!(form == GLP_ASN_MIN || form == GLP_ASN_MAX || form == GLP_ASN_MMP)) xerror("glp_asnprob_lp: form = %d; invalid parameter\n", form); if (!(names == GLP_ON || names == GLP_OFF)) xerror("glp_asnprob_lp: names = %d; invalid parameter\n", names); if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) xerror("glp_asnprob_lp: v_set = %d; invalid offset\n", v_set); if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) xerror("glp_asnprob_lp: a_cost = %d; invalid offset\n", a_cost); ret = glp_check_asnprob(G, v_set); if (ret != 0) goto done; glp_erase_prob(P); if (names) glp_set_prob_name(P, G->name); glp_set_obj_dir(P, form == GLP_ASN_MIN ? GLP_MIN : GLP_MAX); if (G->nv > 0) glp_add_rows(P, G->nv); for (i = 1; i <= G->nv; i++) { v = G->v[i]; if (names) glp_set_row_name(P, i, v->name); glp_set_row_bnds(P, i, form == GLP_ASN_MMP ? GLP_UP : GLP_FX, 1.0, 1.0); } if (G->na > 0) glp_add_cols(P, G->na); for (i = 1, j = 0; i <= G->nv; i++) { v = G->v[i]; for (a = v->out; a != NULL; a = a->t_next) { j++; if (names) { char name[50+1]; sprintf(name, "x[%d,%d]", a->tail->i, a->head->i); xassert(strlen(name) < sizeof(name)); glp_set_col_name(P, j, name); } ind[1] = a->tail->i, val[1] = +1.0; ind[2] = a->head->i, val[2] = +1.0; glp_set_mat_col(P, j, 2, ind, val); glp_set_col_bnds(P, j, GLP_DB, 0.0, 1.0); if (a_cost >= 0) memcpy(&cost, (char *)a->data + a_cost, sizeof(double)); else cost = 1.0; glp_set_obj_coef(P, j, cost); } } xassert(j == G->na); done: return ret; } /**********************************************************************/ int glp_asnprob_okalg(int form, glp_graph *G, int v_set, int a_cost, double *sol, int a_x) { /* solve assignment problem with out-of-kilter algorithm */ glp_vertex *v; glp_arc *a; int nv, na, i, k, *tail, *head, *low, *cap, *cost, *x, *pi, ret; double temp; if (!(form == GLP_ASN_MIN || form == GLP_ASN_MAX || form == GLP_ASN_MMP)) xerror("glp_asnprob_okalg: form = %d; invalid parameter\n", form); if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) xerror("glp_asnprob_okalg: v_set = %d; invalid offset\n", v_set); if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) xerror("glp_asnprob_okalg: a_cost = %d; invalid offset\n", a_cost); if (a_x >= 0 && a_x > G->a_size - (int)sizeof(int)) xerror("glp_asnprob_okalg: a_x = %d; invalid offset\n", a_x); if (glp_check_asnprob(G, v_set)) return GLP_EDATA; /* nv is the total number of nodes in the resulting network */ nv = G->nv + 1; /* na is the total number of arcs in the resulting network */ na = G->na + G->nv; /* allocate working arrays */ tail = xcalloc(1+na, sizeof(int)); head = xcalloc(1+na, sizeof(int)); low = xcalloc(1+na, sizeof(int)); cap = xcalloc(1+na, sizeof(int)); cost = xcalloc(1+na, sizeof(int)); x = xcalloc(1+na, sizeof(int)); pi = xcalloc(1+nv, sizeof(int)); /* construct the resulting network */ k = 0; /* (original arcs) */ for (i = 1; i <= G->nv; i++) { v = G->v[i]; for (a = v->out; a != NULL; a = a->t_next) { k++; tail[k] = a->tail->i; head[k] = a->head->i; low[k] = 0; cap[k] = 1; if (a_cost >= 0) memcpy(&temp, (char *)a->data + a_cost, sizeof(double)); else temp = 1.0; if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp))) { ret = GLP_EDATA; goto done; } cost[k] = (int)temp; if (form != GLP_ASN_MIN) cost[k] = - cost[k]; } } /* (artificial arcs) */ for (i = 1; i <= G->nv; i++) { v = G->v[i]; k++; if (v->out == NULL) tail[k] = i, head[k] = nv; else if (v->in == NULL) tail[k] = nv, head[k] = i; else xassert(v != v); low[k] = (form == GLP_ASN_MMP ? 0 : 1); cap[k] = 1; cost[k] = 0; } xassert(k == na); /* find minimal-cost circulation in the resulting network */ ret = okalg(nv, na, tail, head, low, cap, cost, x, pi); switch (ret) { case 0: /* optimal circulation found */ ret = 0; break; case 1: /* no feasible circulation exists */ ret = GLP_ENOPFS; break; case 2: /* integer overflow occured */ ret = GLP_ERANGE; goto done; case 3: /* optimality test failed (logic error) */ ret = GLP_EFAIL; goto done; default: xassert(ret != ret); } /* store solution components */ /* (objective function = the total cost) */ if (sol != NULL) { temp = 0.0; for (k = 1; k <= na; k++) temp += (double)cost[k] * (double)x[k]; if (form != GLP_ASN_MIN) temp = - temp; *sol = temp; } /* (arc flows) */ if (a_x >= 0) { k = 0; for (i = 1; i <= G->nv; i++) { v = G->v[i]; for (a = v->out; a != NULL; a = a->t_next) { k++; if (ret == 0) xassert(x[k] == 0 || x[k] == 1); memcpy((char *)a->data + a_x, &x[k], sizeof(int)); } } } done: /* free working arrays */ xfree(tail); xfree(head); xfree(low); xfree(cap); xfree(cost); xfree(x); xfree(pi); return ret; } /*********************************************************************** * NAME * * glp_asnprob_hall - find bipartite matching of maximum cardinality * * SYNOPSIS * * int glp_asnprob_hall(glp_graph *G, int v_set, int a_x); * * DESCRIPTION * * The routine glp_asnprob_hall finds a matching of maximal cardinality * in the specified bipartite graph G. It uses a version of the Fortran * routine MC21A developed by I.S.Duff [1], which implements Hall's * algorithm [2]. * * RETURNS * * The routine glp_asnprob_hall returns the cardinality of the matching * found. However, if the specified graph is incorrect (as detected by * the routine glp_check_asnprob), the routine returns negative value. * * REFERENCES * * 1. I.S.Duff, Algorithm 575: Permutations for zero-free diagonal, ACM * Trans. on Math. Softw. 7 (1981), 387-390. * * 2. M.Hall, "An Algorithm for distinct representatives," Amer. Math. * Monthly 63 (1956), 716-717. */ int glp_asnprob_hall(glp_graph *G, int v_set, int a_x) { glp_vertex *v; glp_arc *a; int card, i, k, loc, n, n1, n2, xij; int *num, *icn, *ip, *lenr, *iperm, *pr, *arp, *cv, *out; if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) xerror("glp_asnprob_hall: v_set = %d; invalid offset\n", v_set); if (a_x >= 0 && a_x > G->a_size - (int)sizeof(int)) xerror("glp_asnprob_hall: a_x = %d; invalid offset\n", a_x); if (glp_check_asnprob(G, v_set)) return -1; /* determine the number of vertices in sets R and S and renumber vertices in S which correspond to columns of the matrix; skip all isolated vertices */ num = xcalloc(1+G->nv, sizeof(int)); n1 = n2 = 0; for (i = 1; i <= G->nv; i++) { v = G->v[i]; if (v->in == NULL && v->out != NULL) n1++, num[i] = 0; /* vertex in R */ else if (v->in != NULL && v->out == NULL) n2++, num[i] = n2; /* vertex in S */ else { xassert(v->in == NULL && v->out == NULL); num[i] = -1; /* isolated vertex */ } } /* the matrix must be square, thus, if it has more columns than rows, extra rows will be just empty, and vice versa */ n = (n1 >= n2 ? n1 : n2); /* allocate working arrays */ icn = xcalloc(1+G->na, sizeof(int)); ip = xcalloc(1+n, sizeof(int)); lenr = xcalloc(1+n, sizeof(int)); iperm = xcalloc(1+n, sizeof(int)); pr = xcalloc(1+n, sizeof(int)); arp = xcalloc(1+n, sizeof(int)); cv = xcalloc(1+n, sizeof(int)); out = xcalloc(1+n, sizeof(int)); /* build the adjacency matrix of the bipartite graph in row-wise format (rows are vertices in R, columns are vertices in S) */ k = 0, loc = 1; for (i = 1; i <= G->nv; i++) { if (num[i] != 0) continue; /* vertex i in R */ ip[++k] = loc; v = G->v[i]; for (a = v->out; a != NULL; a = a->t_next) { xassert(num[a->head->i] != 0); icn[loc++] = num[a->head->i]; } lenr[k] = loc - ip[k]; } xassert(loc-1 == G->na); /* make all extra rows empty (all extra columns are empty due to the row-wise format used) */ for (k++; k <= n; k++) ip[k] = loc, lenr[k] = 0; /* find a row permutation that maximizes the number of non-zeros on the main diagonal */ card = mc21a(n, icn, ip, lenr, iperm, pr, arp, cv, out); #if 1 /* 18/II-2010 */ /* FIXED: if card = n, arp remains clobbered on exit */ for (i = 1; i <= n; i++) arp[i] = 0; for (i = 1; i <= card; i++) { k = iperm[i]; xassert(1 <= k && k <= n); xassert(arp[k] == 0); arp[k] = i; } #endif /* store solution, if necessary */ if (a_x < 0) goto skip; k = 0; for (i = 1; i <= G->nv; i++) { if (num[i] != 0) continue; /* vertex i in R */ k++; v = G->v[i]; for (a = v->out; a != NULL; a = a->t_next) { /* arp[k] is the number of matched column or zero */ if (arp[k] == num[a->head->i]) { xassert(arp[k] != 0); xij = 1; } else xij = 0; memcpy((char *)a->data + a_x, &xij, sizeof(int)); } } skip: /* free working arrays */ xfree(num); xfree(icn); xfree(ip); xfree(lenr); xfree(iperm); xfree(pr); xfree(arp); xfree(cv); xfree(out); return card; } /*********************************************************************** * NAME * * glp_cpp - solve critical path problem * * SYNOPSIS * * double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls); * * DESCRIPTION * * The routine glp_cpp solves the critical path problem represented in * the form of the project network. * * The parameter G is a pointer to the graph object, which specifies * the project network. This graph must be acyclic. Multiple arcs are * allowed being considered as single arcs. * * The parameter v_t specifies an offset of the field of type double * in the vertex data block, which contains time t[i] >= 0 needed to * perform corresponding job j. If v_t < 0, it is assumed that t[i] = 1 * for all jobs. * * The parameter v_es specifies an offset of the field of type double * in the vertex data block, to which the routine stores earliest start * time for corresponding job. If v_es < 0, this time is not stored. * * The parameter v_ls specifies an offset of the field of type double * in the vertex data block, to which the routine stores latest start * time for corresponding job. If v_ls < 0, this time is not stored. * * RETURNS * * The routine glp_cpp returns the minimal project duration, that is, * minimal time needed to perform all jobs in the project. */ static void sorting(glp_graph *G, int list[]); double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls) { glp_vertex *v; glp_arc *a; int i, j, k, nv, *list; double temp, total, *t, *es, *ls; if (v_t >= 0 && v_t > G->v_size - (int)sizeof(double)) xerror("glp_cpp: v_t = %d; invalid offset\n", v_t); if (v_es >= 0 && v_es > G->v_size - (int)sizeof(double)) xerror("glp_cpp: v_es = %d; invalid offset\n", v_es); if (v_ls >= 0 && v_ls > G->v_size - (int)sizeof(double)) xerror("glp_cpp: v_ls = %d; invalid offset\n", v_ls); nv = G->nv; if (nv == 0) { total = 0.0; goto done; } /* allocate working arrays */ t = xcalloc(1+nv, sizeof(double)); es = xcalloc(1+nv, sizeof(double)); ls = xcalloc(1+nv, sizeof(double)); list = xcalloc(1+nv, sizeof(int)); /* retrieve job times */ for (i = 1; i <= nv; i++) { v = G->v[i]; if (v_t >= 0) { memcpy(&t[i], (char *)v->data + v_t, sizeof(double)); if (t[i] < 0.0) xerror("glp_cpp: t[%d] = %g; invalid time\n", i, t[i]); } else t[i] = 1.0; } /* perform topological sorting to determine the list of nodes (jobs) such that if list[k] = i and list[kk] = j and there exists arc (i->j), then k < kk */ sorting(G, list); /* FORWARD PASS */ /* determine earliest start times */ for (k = 1; k <= nv; k++) { j = list[k]; es[j] = 0.0; for (a = G->v[j]->in; a != NULL; a = a->h_next) { i = a->tail->i; /* there exists arc (i->j) in the project network */ temp = es[i] + t[i]; if (es[j] < temp) es[j] = temp; } } /* determine the minimal project duration */ total = 0.0; for (i = 1; i <= nv; i++) { temp = es[i] + t[i]; if (total < temp) total = temp; } /* BACKWARD PASS */ /* determine latest start times */ for (k = nv; k >= 1; k--) { i = list[k]; ls[i] = total - t[i]; for (a = G->v[i]->out; a != NULL; a = a->t_next) { j = a->head->i; /* there exists arc (i->j) in the project network */ temp = ls[j] - t[i]; if (ls[i] > temp) ls[i] = temp; } /* avoid possible round-off errors */ if (ls[i] < es[i]) ls[i] = es[i]; } /* store results, if necessary */ if (v_es >= 0) { for (i = 1; i <= nv; i++) { v = G->v[i]; memcpy((char *)v->data + v_es, &es[i], sizeof(double)); } } if (v_ls >= 0) { for (i = 1; i <= nv; i++) { v = G->v[i]; memcpy((char *)v->data + v_ls, &ls[i], sizeof(double)); } } /* free working arrays */ xfree(t); xfree(es); xfree(ls); xfree(list); done: return total; } static void sorting(glp_graph *G, int list[]) { /* perform topological sorting to determine the list of nodes (jobs) such that if list[k] = i and list[kk] = j and there exists arc (i->j), then k < kk */ int i, k, nv, v_size, *num; void **save; nv = G->nv; v_size = G->v_size; save = xcalloc(1+nv, sizeof(void *)); num = xcalloc(1+nv, sizeof(int)); G->v_size = sizeof(int); for (i = 1; i <= nv; i++) { save[i] = G->v[i]->data; G->v[i]->data = &num[i]; list[i] = 0; } if (glp_top_sort(G, 0) != 0) xerror("glp_cpp: project network is not acyclic\n"); G->v_size = v_size; for (i = 1; i <= nv; i++) { G->v[i]->data = save[i]; k = num[i]; xassert(1 <= k && k <= nv); xassert(list[k] == 0); list[k] = i; } xfree(save); xfree(num); return; } /* eof */ Rglpk/src/GLPK/glpnpp03.c0000644000176000001440000030076312245352174014532 0ustar ripleyusers/* glpnpp03.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpnpp.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 */ Rglpk/src/GLPK/glpini01.c0000644000176000001440000001161612245352174014506 0ustar ripleyusers/* glpini01.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #include "glpapi.h" #include "triang.h" /*********************************************************************** * NAME * * glp_adv_basis - construct advanced initial LP basis * * SYNOPSIS * * void glp_adv_basis(glp_prob *P, int flags); * * DESCRIPTION * * The routine glp_adv_basis constructs an advanced initial LP basis * for the specified problem object. * * The parameter flag is reserved for use in the future and should be * specified as zero. * * NOTE * * The routine glp_adv_basis should be called after the constraint * matrix has been scaled (if scaling is used). */ static int mat(void *info, int k, int ind[], double val[]) { glp_prob *P = info; int m = P->m; int n = P->n; GLPROW **row = P->row; GLPCOL **col = P->col; GLPAIJ *aij; int i, j, len; if (k > 0) { /* retrieve scaled row of constraint matrix */ i = +k; xassert(1 <= i && i <= m); len = 0; if (row[i]->type == GLP_FX) { for (aij = row[i]->ptr; aij != NULL; aij = aij->r_next) { j = aij->col->j; if (col[j]->type != GLP_FX) { len++; ind[len] = j; val[len] = aij->row->rii * aij->val * aij->col->sjj; } } } } else { /* retrieve scaled column of constraint matrix */ j = -k; xassert(1 <= j && j <= n); len = 0; if (col[j]->type != GLP_FX) { for (aij = col[j]->ptr; aij != NULL; aij = aij->c_next) { i = aij->row->i; if (row[i]->type == GLP_FX) { len++; ind[len] = i; val[len] = aij->row->rii * aij->val * aij->col->sjj; } } } } return len; } void glp_adv_basis(glp_prob *P, int flags) { int i, j, k, m, n, min_mn, size, *rn, *cn; char *flag; if (flags != 0) xerror("glp_adv_basis: flags = %d; invalid flags\n", flags); m = P->m; /* number of rows */ n = P->n; /* number of columns */ if (m == 0 || n == 0) { /* trivial case */ glp_std_basis(P); goto done; } xprintf("Constructing initial basis...\n"); /* allocate working arrays */ min_mn = (m < n ? m : n); rn = talloc(1+min_mn, int); cn = talloc(1+min_mn, int); flag = talloc(1+m, char); /* make the basis empty */ for (i = 1; i <= m; i++) { flag[i] = 0; glp_set_row_stat(P, i, GLP_NS); } for (j = 1; j <= n; j++) glp_set_col_stat(P, j, GLP_NS); /* find maximal triangular part of the constraint matrix; to prevent including non-fixed rows and fixed columns in the triangular part, such rows and columns are temporarily made empty by the routine mat */ #if 1 /* FIXME: tolerance */ size = triang(m, n, mat, P, 0.001, rn, cn); #endif xassert(0 <= size && size <= min_mn); /* include in the basis non-fixed structural variables, whose columns constitute the triangular part */ for (k = 1; k <= size; k++) { i = rn[k]; xassert(1 <= i && i <= m); flag[i] = 1; j = cn[k]; xassert(1 <= j && j <= n); glp_set_col_stat(P, j, GLP_BS); } /* include in the basis appropriate auxiliary variables, whose unity columns preserve triangular form of the basis matrix */ for (i = 1; i <= m; i++) { if (flag[i] == 0) { glp_set_row_stat(P, i, GLP_BS); if (P->row[i]->type != GLP_FX) size++; } } /* size of triangular part = (number of rows) - (number of basic fixed auxiliary variables) */ xprintf("Size of triangular part is %d\n", size); /* deallocate working arrays */ tfree(rn); tfree(cn); tfree(flag); done: return; } /* eof */ Rglpk/src/GLPK/glpios06.c0000644000176000001440000013751412245352174014534 0ustar ripleyusers/* glpios06.c (MIR cut generator) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpios.h" #define _MIR_DEBUG 0 #define MAXAGGR 5 /* maximal number of rows which can be aggregated */ struct MIR { /* MIR cut generator working area */ /*--------------------------------------------------------------*/ /* global information valid for the root subproblem */ int m; /* number of rows (in the root subproblem) */ int n; /* number of columns */ char *skip; /* char skip[1+m]; */ /* skip[i], 1 <= i <= m, is a flag that means that row i should not be used because (1) it is not suitable, or (2) because it has been used in the aggregated constraint */ char *isint; /* char isint[1+m+n]; */ /* isint[k], 1 <= k <= m+n, is a flag that means that variable x[k] is integer (otherwise, continuous) */ double *lb; /* double lb[1+m+n]; */ /* lb[k], 1 <= k <= m+n, is lower bound of x[k]; -DBL_MAX means that x[k] has no lower bound */ int *vlb; /* int vlb[1+m+n]; */ /* vlb[k] = k', 1 <= k <= m+n, is the number of integer variable, which defines variable lower bound x[k] >= lb[k] * x[k']; zero means that x[k] has simple lower bound */ double *ub; /* double ub[1+m+n]; */ /* ub[k], 1 <= k <= m+n, is upper bound of x[k]; +DBL_MAX means that x[k] has no upper bound */ int *vub; /* int vub[1+m+n]; */ /* vub[k] = k', 1 <= k <= m+n, is the number of integer variable, which defines variable upper bound x[k] <= ub[k] * x[k']; zero means that x[k] has simple upper bound */ /*--------------------------------------------------------------*/ /* current (fractional) point to be separated */ double *x; /* double x[1+m+n]; */ /* x[k] is current value of auxiliary (1 <= k <= m) or structural (m+1 <= k <= m+n) variable */ /*--------------------------------------------------------------*/ /* aggregated constraint sum a[k] * x[k] = b, which is a linear combination of original constraints transformed to equalities by introducing auxiliary variables */ int agg_cnt; /* number of rows (original constraints) used to build aggregated constraint, 1 <= agg_cnt <= MAXAGGR */ int *agg_row; /* int agg_row[1+MAXAGGR]; */ /* agg_row[k], 1 <= k <= agg_cnt, is the row number used to build aggregated constraint */ IOSVEC *agg_vec; /* IOSVEC agg_vec[1:m+n]; */ /* sparse vector of aggregated constraint coefficients, a[k] */ double agg_rhs; /* right-hand side of the aggregated constraint, b */ /*--------------------------------------------------------------*/ /* bound substitution flags for modified constraint */ char *subst; /* char subst[1+m+n]; */ /* subst[k], 1 <= k <= m+n, is a bound substitution flag used for variable x[k]: '?' - x[k] is missing in modified constraint 'L' - x[k] = (lower bound) + x'[k] 'U' - x[k] = (upper bound) - x'[k] */ /*--------------------------------------------------------------*/ /* modified constraint sum a'[k] * x'[k] = b', where x'[k] >= 0, derived from aggregated constraint by substituting bounds; note that due to substitution of variable bounds there may be additional terms in the modified constraint */ IOSVEC *mod_vec; /* IOSVEC mod_vec[1:m+n]; */ /* sparse vector of modified constraint coefficients, a'[k] */ double mod_rhs; /* right-hand side of the modified constraint, b' */ /*--------------------------------------------------------------*/ /* cutting plane sum alpha[k] * x[k] <= beta */ IOSVEC *cut_vec; /* IOSVEC cut_vec[1:m+n]; */ /* sparse vector of cutting plane coefficients, alpha[k] */ double cut_rhs; /* right-hand size of the cutting plane, beta */ }; /*********************************************************************** * NAME * * ios_mir_init - initialize MIR cut generator * * SYNOPSIS * * #include "glpios.h" * void *ios_mir_init(glp_tree *tree); * * DESCRIPTION * * The routine ios_mir_init initializes the MIR cut generator assuming * that the current subproblem is the root subproblem. * * RETURNS * * The routine ios_mir_init returns a pointer to the MIR cut generator * working area. */ static void set_row_attrib(glp_tree *tree, struct MIR *mir) { /* set global row attributes */ glp_prob *mip = tree->mip; int m = mir->m; int k; for (k = 1; k <= m; k++) { GLPROW *row = mip->row[k]; mir->skip[k] = 0; mir->isint[k] = 0; switch (row->type) { case GLP_FR: mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break; case GLP_LO: mir->lb[k] = row->lb, mir->ub[k] = +DBL_MAX; break; case GLP_UP: mir->lb[k] = -DBL_MAX, mir->ub[k] = row->ub; break; case GLP_DB: mir->lb[k] = row->lb, mir->ub[k] = row->ub; break; case GLP_FX: mir->lb[k] = mir->ub[k] = row->lb; break; default: xassert(row != row); } mir->vlb[k] = mir->vub[k] = 0; } return; } static void set_col_attrib(glp_tree *tree, struct MIR *mir) { /* set global column attributes */ glp_prob *mip = tree->mip; int m = mir->m; int n = mir->n; int k; for (k = m+1; k <= m+n; k++) { GLPCOL *col = mip->col[k-m]; switch (col->kind) { case GLP_CV: mir->isint[k] = 0; break; case GLP_IV: mir->isint[k] = 1; break; default: xassert(col != col); } switch (col->type) { case GLP_FR: mir->lb[k] = -DBL_MAX, mir->ub[k] = +DBL_MAX; break; case GLP_LO: mir->lb[k] = col->lb, mir->ub[k] = +DBL_MAX; break; case GLP_UP: mir->lb[k] = -DBL_MAX, mir->ub[k] = col->ub; break; case GLP_DB: mir->lb[k] = col->lb, mir->ub[k] = col->ub; break; case GLP_FX: mir->lb[k] = mir->ub[k] = col->lb; break; default: xassert(col != col); } mir->vlb[k] = mir->vub[k] = 0; } return; } static void set_var_bounds(glp_tree *tree, struct MIR *mir) { /* set variable bounds */ glp_prob *mip = tree->mip; int m = mir->m; GLPAIJ *aij; int i, k1, k2; double a1, a2; for (i = 1; i <= m; i++) { /* we need the row to be '>= 0' or '<= 0' */ if (!(mir->lb[i] == 0.0 && mir->ub[i] == +DBL_MAX || mir->lb[i] == -DBL_MAX && mir->ub[i] == 0.0)) continue; /* take first term */ aij = mip->row[i]->ptr; if (aij == NULL) continue; k1 = m + aij->col->j, a1 = aij->val; /* take second term */ aij = aij->r_next; if (aij == NULL) continue; k2 = m + aij->col->j, a2 = aij->val; /* there must be only two terms */ if (aij->r_next != NULL) continue; /* interchange terms, if needed */ if (!mir->isint[k1] && mir->isint[k2]) ; else if (mir->isint[k1] && !mir->isint[k2]) { k2 = k1, a2 = a1; k1 = m + aij->col->j, a1 = aij->val; } else { /* both terms are either continuous or integer */ continue; } /* x[k2] should be double-bounded */ if (mir->lb[k2] == -DBL_MAX || mir->ub[k2] == +DBL_MAX || mir->lb[k2] == mir->ub[k2]) continue; /* change signs, if necessary */ if (mir->ub[i] == 0.0) a1 = - a1, a2 = - a2; /* now the row has the form a1 * x1 + a2 * x2 >= 0, where x1 is continuous, x2 is integer */ if (a1 > 0.0) { /* x1 >= - (a2 / a1) * x2 */ if (mir->vlb[k1] == 0) { /* set variable lower bound for x1 */ mir->lb[k1] = - a2 / a1; mir->vlb[k1] = k2; /* the row should not be used */ mir->skip[i] = 1; } } else /* a1 < 0.0 */ { /* x1 <= - (a2 / a1) * x2 */ if (mir->vub[k1] == 0) { /* set variable upper bound for x1 */ mir->ub[k1] = - a2 / a1; mir->vub[k1] = k2; /* the row should not be used */ mir->skip[i] = 1; } } } return; } static void mark_useless_rows(glp_tree *tree, struct MIR *mir) { /* mark rows which should not be used */ glp_prob *mip = tree->mip; int m = mir->m; GLPAIJ *aij; int i, k, nv; for (i = 1; i <= m; i++) { /* free rows should not be used */ if (mir->lb[i] == -DBL_MAX && mir->ub[i] == +DBL_MAX) { mir->skip[i] = 1; continue; } nv = 0; for (aij = mip->row[i]->ptr; aij != NULL; aij = aij->r_next) { k = m + aij->col->j; /* rows with free variables should not be used */ if (mir->lb[k] == -DBL_MAX && mir->ub[k] == +DBL_MAX) { mir->skip[i] = 1; break; } /* rows with integer variables having infinite (lower or upper) bound should not be used */ if (mir->isint[k] && mir->lb[k] == -DBL_MAX || mir->isint[k] && mir->ub[k] == +DBL_MAX) { mir->skip[i] = 1; break; } /* count non-fixed variables */ if (!(mir->vlb[k] == 0 && mir->vub[k] == 0 && mir->lb[k] == mir->ub[k])) nv++; } /* rows with all variables fixed should not be used */ if (nv == 0) { mir->skip[i] = 1; continue; } } return; } void *ios_mir_init(glp_tree *tree) { /* initialize MIR cut generator */ glp_prob *mip = tree->mip; int m = mip->m; int n = mip->n; struct MIR *mir; #if _MIR_DEBUG xprintf("ios_mir_init: warning: debug mode enabled\n"); #endif /* allocate working area */ mir = xmalloc(sizeof(struct MIR)); mir->m = m; mir->n = n; mir->skip = xcalloc(1+m, sizeof(char)); mir->isint = xcalloc(1+m+n, sizeof(char)); mir->lb = xcalloc(1+m+n, sizeof(double)); mir->vlb = xcalloc(1+m+n, sizeof(int)); mir->ub = xcalloc(1+m+n, sizeof(double)); mir->vub = xcalloc(1+m+n, sizeof(int)); mir->x = xcalloc(1+m+n, sizeof(double)); mir->agg_row = xcalloc(1+MAXAGGR, sizeof(int)); mir->agg_vec = ios_create_vec(m+n); mir->subst = xcalloc(1+m+n, sizeof(char)); mir->mod_vec = ios_create_vec(m+n); mir->cut_vec = ios_create_vec(m+n); /* set global row attributes */ set_row_attrib(tree, mir); /* set global column attributes */ set_col_attrib(tree, mir); /* set variable bounds */ set_var_bounds(tree, mir); /* mark rows which should not be used */ mark_useless_rows(tree, mir); return mir; } /*********************************************************************** * NAME * * ios_mir_gen - generate MIR cuts * * SYNOPSIS * * #include "glpios.h" * void ios_mir_gen(glp_tree *tree, void *gen, IOSPOOL *pool); * * DESCRIPTION * * The routine ios_mir_gen generates MIR cuts for the current point and * adds them to the cut pool. */ static void get_current_point(glp_tree *tree, struct MIR *mir) { /* obtain current point */ glp_prob *mip = tree->mip; int m = mir->m; int n = mir->n; int k; for (k = 1; k <= m; k++) mir->x[k] = mip->row[k]->prim; for (k = m+1; k <= m+n; k++) mir->x[k] = mip->col[k-m]->prim; return; } #if _MIR_DEBUG static void check_current_point(struct MIR *mir) { /* check current point */ int m = mir->m; int n = mir->n; int k, kk; double lb, ub, eps; for (k = 1; k <= m+n; k++) { /* determine lower bound */ lb = mir->lb[k]; kk = mir->vlb[k]; if (kk != 0) { xassert(lb != -DBL_MAX); xassert(!mir->isint[k]); xassert(mir->isint[kk]); lb *= mir->x[kk]; } /* check lower bound */ if (lb != -DBL_MAX) { eps = 1e-6 * (1.0 + fabs(lb)); xassert(mir->x[k] >= lb - eps); } /* determine upper bound */ ub = mir->ub[k]; kk = mir->vub[k]; if (kk != 0) { xassert(ub != +DBL_MAX); xassert(!mir->isint[k]); xassert(mir->isint[kk]); ub *= mir->x[kk]; } /* check upper bound */ if (ub != +DBL_MAX) { eps = 1e-6 * (1.0 + fabs(ub)); xassert(mir->x[k] <= ub + eps); } } return; } #endif static void initial_agg_row(glp_tree *tree, struct MIR *mir, int i) { /* use original i-th row as initial aggregated constraint */ glp_prob *mip = tree->mip; int m = mir->m; GLPAIJ *aij; xassert(1 <= i && i <= m); xassert(!mir->skip[i]); /* mark i-th row in order not to use it in the same aggregated constraint */ mir->skip[i] = 2; mir->agg_cnt = 1; mir->agg_row[1] = i; /* use x[i] - sum a[i,j] * x[m+j] = 0, where x[i] is auxiliary variable of row i, x[m+j] are structural variables */ ios_clear_vec(mir->agg_vec); ios_set_vj(mir->agg_vec, i, 1.0); for (aij = mip->row[i]->ptr; aij != NULL; aij = aij->r_next) ios_set_vj(mir->agg_vec, m + aij->col->j, - aij->val); mir->agg_rhs = 0.0; #if _MIR_DEBUG ios_check_vec(mir->agg_vec); #endif return; } #if _MIR_DEBUG static void check_agg_row(struct MIR *mir) { /* check aggregated constraint */ int m = mir->m; int n = mir->n; int j, k; double r, big; /* compute the residual r = sum a[k] * x[k] - b and determine big = max(1, |a[k]|, |b|) */ r = 0.0, big = 1.0; for (j = 1; j <= mir->agg_vec->nnz; j++) { k = mir->agg_vec->ind[j]; xassert(1 <= k && k <= m+n); r += mir->agg_vec->val[j] * mir->x[k]; if (big < fabs(mir->agg_vec->val[j])) big = fabs(mir->agg_vec->val[j]); } r -= mir->agg_rhs; if (big < fabs(mir->agg_rhs)) big = fabs(mir->agg_rhs); /* the residual must be close to zero */ xassert(fabs(r) <= 1e-6 * big); return; } #endif static void subst_fixed_vars(struct MIR *mir) { /* substitute fixed variables into aggregated constraint */ int m = mir->m; int n = mir->n; int j, k; for (j = 1; j <= mir->agg_vec->nnz; j++) { k = mir->agg_vec->ind[j]; xassert(1 <= k && k <= m+n); if (mir->vlb[k] == 0 && mir->vub[k] == 0 && mir->lb[k] == mir->ub[k]) { /* x[k] is fixed */ mir->agg_rhs -= mir->agg_vec->val[j] * mir->lb[k]; mir->agg_vec->val[j] = 0.0; } } /* remove terms corresponding to fixed variables */ ios_clean_vec(mir->agg_vec, DBL_EPSILON); #if _MIR_DEBUG ios_check_vec(mir->agg_vec); #endif return; } static void bound_subst_heur(struct MIR *mir) { /* bound substitution heuristic */ int m = mir->m; int n = mir->n; int j, k, kk; double d1, d2; for (j = 1; j <= mir->agg_vec->nnz; j++) { k = mir->agg_vec->ind[j]; xassert(1 <= k && k <= m+n); if (mir->isint[k]) continue; /* skip integer variable */ /* compute distance from x[k] to its lower bound */ kk = mir->vlb[k]; if (kk == 0) { if (mir->lb[k] == -DBL_MAX) d1 = DBL_MAX; else d1 = mir->x[k] - mir->lb[k]; } else { xassert(1 <= kk && kk <= m+n); xassert(mir->isint[kk]); xassert(mir->lb[k] != -DBL_MAX); d1 = mir->x[k] - mir->lb[k] * mir->x[kk]; } /* compute distance from x[k] to its upper bound */ kk = mir->vub[k]; if (kk == 0) { if (mir->vub[k] == +DBL_MAX) d2 = DBL_MAX; else d2 = mir->ub[k] - mir->x[k]; } else { xassert(1 <= kk && kk <= m+n); xassert(mir->isint[kk]); xassert(mir->ub[k] != +DBL_MAX); d2 = mir->ub[k] * mir->x[kk] - mir->x[k]; } /* x[k] cannot be free */ xassert(d1 != DBL_MAX || d2 != DBL_MAX); /* choose the bound which is closer to x[k] */ xassert(mir->subst[k] == '?'); if (d1 <= d2) mir->subst[k] = 'L'; else mir->subst[k] = 'U'; } return; } static void build_mod_row(struct MIR *mir) { /* substitute bounds and build modified constraint */ int m = mir->m; int n = mir->n; int j, jj, k, kk; /* initially modified constraint is aggregated constraint */ ios_copy_vec(mir->mod_vec, mir->agg_vec); mir->mod_rhs = mir->agg_rhs; #if _MIR_DEBUG ios_check_vec(mir->mod_vec); #endif /* substitute bounds for continuous variables; note that due to substitution of variable bounds additional terms may appear in modified constraint */ for (j = mir->mod_vec->nnz; j >= 1; j--) { k = mir->mod_vec->ind[j]; xassert(1 <= k && k <= m+n); if (mir->isint[k]) continue; /* skip integer variable */ if (mir->subst[k] == 'L') { /* x[k] = (lower bound) + x'[k] */ xassert(mir->lb[k] != -DBL_MAX); kk = mir->vlb[k]; if (kk == 0) { /* x[k] = lb[k] + x'[k] */ mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k]; } else { /* x[k] = lb[k] * x[kk] + x'[k] */ xassert(mir->isint[kk]); jj = mir->mod_vec->pos[kk]; if (jj == 0) { ios_set_vj(mir->mod_vec, kk, 1.0); jj = mir->mod_vec->pos[kk]; mir->mod_vec->val[jj] = 0.0; } mir->mod_vec->val[jj] += mir->mod_vec->val[j] * mir->lb[k]; } } else if (mir->subst[k] == 'U') { /* x[k] = (upper bound) - x'[k] */ xassert(mir->ub[k] != +DBL_MAX); kk = mir->vub[k]; if (kk == 0) { /* x[k] = ub[k] - x'[k] */ mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k]; } else { /* x[k] = ub[k] * x[kk] - x'[k] */ xassert(mir->isint[kk]); jj = mir->mod_vec->pos[kk]; if (jj == 0) { ios_set_vj(mir->mod_vec, kk, 1.0); jj = mir->mod_vec->pos[kk]; mir->mod_vec->val[jj] = 0.0; } mir->mod_vec->val[jj] += mir->mod_vec->val[j] * mir->ub[k]; } mir->mod_vec->val[j] = - mir->mod_vec->val[j]; } else xassert(k != k); } #if _MIR_DEBUG ios_check_vec(mir->mod_vec); #endif /* substitute bounds for integer variables */ for (j = 1; j <= mir->mod_vec->nnz; j++) { k = mir->mod_vec->ind[j]; xassert(1 <= k && k <= m+n); if (!mir->isint[k]) continue; /* skip continuous variable */ xassert(mir->subst[k] == '?'); xassert(mir->vlb[k] == 0 && mir->vub[k] == 0); xassert(mir->lb[k] != -DBL_MAX && mir->ub[k] != +DBL_MAX); if (fabs(mir->lb[k]) <= fabs(mir->ub[k])) { /* x[k] = lb[k] + x'[k] */ mir->subst[k] = 'L'; mir->mod_rhs -= mir->mod_vec->val[j] * mir->lb[k]; } else { /* x[k] = ub[k] - x'[k] */ mir->subst[k] = 'U'; mir->mod_rhs -= mir->mod_vec->val[j] * mir->ub[k]; mir->mod_vec->val[j] = - mir->mod_vec->val[j]; } } #if _MIR_DEBUG ios_check_vec(mir->mod_vec); #endif return; } #if _MIR_DEBUG static void check_mod_row(struct MIR *mir) { /* check modified constraint */ int m = mir->m; int n = mir->n; int j, k, kk; double r, big, x; /* compute the residual r = sum a'[k] * x'[k] - b' and determine big = max(1, |a[k]|, |b|) */ r = 0.0, big = 1.0; for (j = 1; j <= mir->mod_vec->nnz; j++) { k = mir->mod_vec->ind[j]; xassert(1 <= k && k <= m+n); if (mir->subst[k] == 'L') { /* x'[k] = x[k] - (lower bound) */ xassert(mir->lb[k] != -DBL_MAX); kk = mir->vlb[k]; if (kk == 0) x = mir->x[k] - mir->lb[k]; else x = mir->x[k] - mir->lb[k] * mir->x[kk]; } else if (mir->subst[k] == 'U') { /* x'[k] = (upper bound) - x[k] */ xassert(mir->ub[k] != +DBL_MAX); kk = mir->vub[k]; if (kk == 0) x = mir->ub[k] - mir->x[k]; else x = mir->ub[k] * mir->x[kk] - mir->x[k]; } else xassert(k != k); r += mir->mod_vec->val[j] * x; if (big < fabs(mir->mod_vec->val[j])) big = fabs(mir->mod_vec->val[j]); } r -= mir->mod_rhs; if (big < fabs(mir->mod_rhs)) big = fabs(mir->mod_rhs); /* the residual must be close to zero */ xassert(fabs(r) <= 1e-6 * big); return; } #endif /*********************************************************************** * mir_ineq - construct MIR inequality * * Given the single constraint mixed integer set * * |N| * X = {(x,s) in Z x R : sum a[j] * x[j] <= b + s}, * + + j in N * * this routine constructs the mixed integer rounding (MIR) inequality * * sum alpha[j] * x[j] <= beta + gamma * s, * j in N * * which is valid for X. * * If the MIR inequality has been successfully constructed, the routine * returns zero. Otherwise, if b is close to nearest integer, there may * be numeric difficulties due to big coefficients; so in this case the * routine returns non-zero. */ static int mir_ineq(const int n, const double a[], const double b, double alpha[], double *beta, double *gamma) { int j; double f, t; if (fabs(b - floor(b + .5)) < 0.01) return 1; f = b - floor(b); for (j = 1; j <= n; j++) { t = (a[j] - floor(a[j])) - f; if (t <= 0.0) alpha[j] = floor(a[j]); else alpha[j] = floor(a[j]) + t / (1.0 - f); } *beta = floor(b); *gamma = 1.0 / (1.0 - f); return 0; } /*********************************************************************** * cmir_ineq - construct c-MIR inequality * * Given the mixed knapsack set * * MK |N| * X = {(x,s) in Z x R : sum a[j] * x[j] <= b + s, * + + j in N * * x[j] <= u[j]}, * * a subset C of variables to be complemented, and a divisor delta > 0, * this routine constructs the complemented MIR (c-MIR) inequality * * sum alpha[j] * x[j] <= beta + gamma * s, * j in N * MK * which is valid for X . * * If the c-MIR inequality has been successfully constructed, the * routine returns zero. Otherwise, if there is a risk of numerical * difficulties due to big coefficients (see comments to the routine * mir_ineq), the routine cmir_ineq returns non-zero. */ static int cmir_ineq(const int n, const double a[], const double b, const double u[], const char cset[], const double delta, double alpha[], double *beta, double *gamma) { int j; double *aa, bb; aa = alpha, bb = b; for (j = 1; j <= n; j++) { aa[j] = a[j] / delta; if (cset[j]) aa[j] = - aa[j], bb -= a[j] * u[j]; } bb /= delta; if (mir_ineq(n, aa, bb, alpha, beta, gamma)) return 1; for (j = 1; j <= n; j++) { if (cset[j]) alpha[j] = - alpha[j], *beta += alpha[j] * u[j]; } *gamma /= delta; return 0; } /*********************************************************************** * cmir_sep - c-MIR separation heuristic * * Given the mixed knapsack set * * MK |N| * X = {(x,s) in Z x R : sum a[j] * x[j] <= b + s, * + + j in N * * x[j] <= u[j]} * * * * * and a fractional point (x , s ), this routine tries to construct * c-MIR inequality * * sum alpha[j] * x[j] <= beta + gamma * s, * j in N * MK * which is valid for X and has (desirably maximal) violation at the * fractional point given. This is attained by choosing an appropriate * set C of variables to be complemented and a divisor delta > 0, which * together define corresponding c-MIR inequality. * * If a violated c-MIR inequality has been successfully constructed, * the routine returns its violation: * * * * * sum alpha[j] * x [j] - beta - gamma * s , * j in N * * which is positive. In case of failure the routine returns zero. */ struct vset { int j; double v; }; static int cmir_cmp(const void *p1, const void *p2) { const struct vset *v1 = p1, *v2 = p2; if (v1->v < v2->v) return -1; if (v1->v > v2->v) return +1; return 0; } static double cmir_sep(const int n, const double a[], const double b, const double u[], const double x[], const double s, double alpha[], double *beta, double *gamma) { int fail, j, k, nv, v; double delta, eps, d_try[1+3], r, r_best; char *cset; struct vset *vset; /* allocate working arrays */ cset = xcalloc(1+n, sizeof(char)); vset = xcalloc(1+n, sizeof(struct vset)); /* choose initial C */ for (j = 1; j <= n; j++) cset[j] = (char)(x[j] >= 0.5 * u[j]); /* choose initial delta */ r_best = delta = 0.0; for (j = 1; j <= n; j++) { xassert(a[j] != 0.0); /* if x[j] is close to its bounds, skip it */ eps = 1e-9 * (1.0 + fabs(u[j])); if (x[j] < eps || x[j] > u[j] - eps) continue; /* try delta = |a[j]| to construct c-MIR inequality */ fail = cmir_ineq(n, a, b, u, cset, fabs(a[j]), alpha, beta, gamma); if (fail) continue; /* compute violation */ r = - (*beta) - (*gamma) * s; for (k = 1; k <= n; k++) r += alpha[k] * x[k]; if (r_best < r) r_best = r, delta = fabs(a[j]); } if (r_best < 0.001) r_best = 0.0; if (r_best == 0.0) goto done; xassert(delta > 0.0); /* try to increase violation by dividing delta by 2, 4, and 8, respectively */ d_try[1] = delta / 2.0; d_try[2] = delta / 4.0; d_try[3] = delta / 8.0; for (j = 1; j <= 3; j++) { /* construct c-MIR inequality */ fail = cmir_ineq(n, a, b, u, cset, d_try[j], alpha, beta, gamma); if (fail) continue; /* compute violation */ r = - (*beta) - (*gamma) * s; for (k = 1; k <= n; k++) r += alpha[k] * x[k]; if (r_best < r) r_best = r, delta = d_try[j]; } /* build subset of variables lying strictly between their bounds and order it by nondecreasing values of |x[j] - u[j]/2| */ nv = 0; for (j = 1; j <= n; j++) { /* if x[j] is close to its bounds, skip it */ eps = 1e-9 * (1.0 + fabs(u[j])); if (x[j] < eps || x[j] > u[j] - eps) continue; /* add x[j] to the subset */ nv++; vset[nv].j = j; vset[nv].v = fabs(x[j] - 0.5 * u[j]); } qsort(&vset[1], nv, sizeof(struct vset), cmir_cmp); /* try to increase violation by successively complementing each variable in the subset */ for (v = 1; v <= nv; v++) { j = vset[v].j; /* replace x[j] by its complement or vice versa */ cset[j] = (char)!cset[j]; /* construct c-MIR inequality */ fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma); /* restore the variable */ cset[j] = (char)!cset[j]; /* do not replace the variable in case of failure */ if (fail) continue; /* compute violation */ r = - (*beta) - (*gamma) * s; for (k = 1; k <= n; k++) r += alpha[k] * x[k]; if (r_best < r) r_best = r, cset[j] = (char)!cset[j]; } /* construct the best c-MIR inequality chosen */ fail = cmir_ineq(n, a, b, u, cset, delta, alpha, beta, gamma); xassert(!fail); done: /* free working arrays */ xfree(cset); xfree(vset); /* return to the calling routine */ return r_best; } static double generate(struct MIR *mir) { /* try to generate violated c-MIR cut for modified constraint */ int m = mir->m; int n = mir->n; int j, k, kk, nint; double s, *u, *x, *alpha, r_best = 0.0, b, beta, gamma; ios_copy_vec(mir->cut_vec, mir->mod_vec); mir->cut_rhs = mir->mod_rhs; /* remove small terms, which can appear due to substitution of variable bounds */ ios_clean_vec(mir->cut_vec, DBL_EPSILON); #if _MIR_DEBUG ios_check_vec(mir->cut_vec); #endif /* remove positive continuous terms to obtain MK relaxation */ for (j = 1; j <= mir->cut_vec->nnz; j++) { k = mir->cut_vec->ind[j]; xassert(1 <= k && k <= m+n); if (!mir->isint[k] && mir->cut_vec->val[j] > 0.0) mir->cut_vec->val[j] = 0.0; } ios_clean_vec(mir->cut_vec, 0.0); #if _MIR_DEBUG ios_check_vec(mir->cut_vec); #endif /* move integer terms to the beginning of the sparse vector and determine the number of integer variables */ nint = 0; for (j = 1; j <= mir->cut_vec->nnz; j++) { k = mir->cut_vec->ind[j]; xassert(1 <= k && k <= m+n); if (mir->isint[k]) { double temp; nint++; /* interchange elements [nint] and [j] */ kk = mir->cut_vec->ind[nint]; mir->cut_vec->pos[k] = nint; mir->cut_vec->pos[kk] = j; mir->cut_vec->ind[nint] = k; mir->cut_vec->ind[j] = kk; temp = mir->cut_vec->val[nint]; mir->cut_vec->val[nint] = mir->cut_vec->val[j]; mir->cut_vec->val[j] = temp; } } #if _MIR_DEBUG ios_check_vec(mir->cut_vec); #endif /* if there is no integer variable, nothing to generate */ if (nint == 0) goto done; /* allocate working arrays */ u = xcalloc(1+nint, sizeof(double)); x = xcalloc(1+nint, sizeof(double)); alpha = xcalloc(1+nint, sizeof(double)); /* determine u and x */ for (j = 1; j <= nint; j++) { k = mir->cut_vec->ind[j]; xassert(m+1 <= k && k <= m+n); xassert(mir->isint[k]); u[j] = mir->ub[k] - mir->lb[k]; xassert(u[j] >= 1.0); if (mir->subst[k] == 'L') x[j] = mir->x[k] - mir->lb[k]; else if (mir->subst[k] == 'U') x[j] = mir->ub[k] - mir->x[k]; else xassert(k != k); xassert(x[j] >= -0.001); if (x[j] < 0.0) x[j] = 0.0; } /* compute s = - sum of continuous terms */ s = 0.0; for (j = nint+1; j <= mir->cut_vec->nnz; j++) { double x; k = mir->cut_vec->ind[j]; xassert(1 <= k && k <= m+n); /* must be continuous */ xassert(!mir->isint[k]); if (mir->subst[k] == 'L') { xassert(mir->lb[k] != -DBL_MAX); kk = mir->vlb[k]; if (kk == 0) x = mir->x[k] - mir->lb[k]; else x = mir->x[k] - mir->lb[k] * mir->x[kk]; } else if (mir->subst[k] == 'U') { xassert(mir->ub[k] != +DBL_MAX); kk = mir->vub[k]; if (kk == 0) x = mir->ub[k] - mir->x[k]; else x = mir->ub[k] * mir->x[kk] - mir->x[k]; } else xassert(k != k); xassert(x >= -0.001); if (x < 0.0) x = 0.0; s -= mir->cut_vec->val[j] * x; } xassert(s >= 0.0); /* apply heuristic to obtain most violated c-MIR inequality */ b = mir->cut_rhs; r_best = cmir_sep(nint, mir->cut_vec->val, b, u, x, s, alpha, &beta, &gamma); if (r_best == 0.0) goto skip; xassert(r_best > 0.0); /* convert to raw cut */ /* sum alpha[j] * x[j] <= beta + gamma * s */ for (j = 1; j <= nint; j++) mir->cut_vec->val[j] = alpha[j]; for (j = nint+1; j <= mir->cut_vec->nnz; j++) { k = mir->cut_vec->ind[j]; if (k <= m+n) mir->cut_vec->val[j] *= gamma; } mir->cut_rhs = beta; #if _MIR_DEBUG ios_check_vec(mir->cut_vec); #endif skip: /* free working arrays */ xfree(u); xfree(x); xfree(alpha); done: return r_best; } #if _MIR_DEBUG static void check_raw_cut(struct MIR *mir, double r_best) { /* check raw cut before back bound substitution */ int m = mir->m; int n = mir->n; int j, k, kk; double r, big, x; /* compute the residual r = sum a[k] * x[k] - b and determine big = max(1, |a[k]|, |b|) */ r = 0.0, big = 1.0; for (j = 1; j <= mir->cut_vec->nnz; j++) { k = mir->cut_vec->ind[j]; xassert(1 <= k && k <= m+n); if (mir->subst[k] == 'L') { xassert(mir->lb[k] != -DBL_MAX); kk = mir->vlb[k]; if (kk == 0) x = mir->x[k] - mir->lb[k]; else x = mir->x[k] - mir->lb[k] * mir->x[kk]; } else if (mir->subst[k] == 'U') { xassert(mir->ub[k] != +DBL_MAX); kk = mir->vub[k]; if (kk == 0) x = mir->ub[k] - mir->x[k]; else x = mir->ub[k] * mir->x[kk] - mir->x[k]; } else xassert(k != k); r += mir->cut_vec->val[j] * x; if (big < fabs(mir->cut_vec->val[j])) big = fabs(mir->cut_vec->val[j]); } r -= mir->cut_rhs; if (big < fabs(mir->cut_rhs)) big = fabs(mir->cut_rhs); /* the residual must be close to r_best */ xassert(fabs(r - r_best) <= 1e-6 * big); return; } #endif static void back_subst(struct MIR *mir) { /* back substitution of original bounds */ int m = mir->m; int n = mir->n; int j, jj, k, kk; /* at first, restore bounds of integer variables (because on restoring variable bounds of continuous variables we need original, not shifted, bounds of integer variables) */ for (j = 1; j <= mir->cut_vec->nnz; j++) { k = mir->cut_vec->ind[j]; xassert(1 <= k && k <= m+n); if (!mir->isint[k]) continue; /* skip continuous */ if (mir->subst[k] == 'L') { /* x'[k] = x[k] - lb[k] */ xassert(mir->lb[k] != -DBL_MAX); xassert(mir->vlb[k] == 0); mir->cut_rhs += mir->cut_vec->val[j] * mir->lb[k]; } else if (mir->subst[k] == 'U') { /* x'[k] = ub[k] - x[k] */ xassert(mir->ub[k] != +DBL_MAX); xassert(mir->vub[k] == 0); mir->cut_rhs -= mir->cut_vec->val[j] * mir->ub[k]; mir->cut_vec->val[j] = - mir->cut_vec->val[j]; } else xassert(k != k); } /* now restore bounds of continuous variables */ for (j = 1; j <= mir->cut_vec->nnz; j++) { k = mir->cut_vec->ind[j]; xassert(1 <= k && k <= m+n); if (mir->isint[k]) continue; /* skip integer */ if (mir->subst[k] == 'L') { /* x'[k] = x[k] - (lower bound) */ xassert(mir->lb[k] != -DBL_MAX); kk = mir->vlb[k]; if (kk == 0) { /* x'[k] = x[k] - lb[k] */ mir->cut_rhs += mir->cut_vec->val[j] * mir->lb[k]; } else { /* x'[k] = x[k] - lb[k] * x[kk] */ jj = mir->cut_vec->pos[kk]; #if 0 xassert(jj != 0); #else if (jj == 0) { ios_set_vj(mir->cut_vec, kk, 1.0); jj = mir->cut_vec->pos[kk]; xassert(jj != 0); mir->cut_vec->val[jj] = 0.0; } #endif mir->cut_vec->val[jj] -= mir->cut_vec->val[j] * mir->lb[k]; } } else if (mir->subst[k] == 'U') { /* x'[k] = (upper bound) - x[k] */ xassert(mir->ub[k] != +DBL_MAX); kk = mir->vub[k]; if (kk == 0) { /* x'[k] = ub[k] - x[k] */ mir->cut_rhs -= mir->cut_vec->val[j] * mir->ub[k]; } else { /* x'[k] = ub[k] * x[kk] - x[k] */ jj = mir->cut_vec->pos[kk]; if (jj == 0) { ios_set_vj(mir->cut_vec, kk, 1.0); jj = mir->cut_vec->pos[kk]; xassert(jj != 0); mir->cut_vec->val[jj] = 0.0; } mir->cut_vec->val[jj] += mir->cut_vec->val[j] * mir->ub[k]; } mir->cut_vec->val[j] = - mir->cut_vec->val[j]; } else xassert(k != k); } #if _MIR_DEBUG ios_check_vec(mir->cut_vec); #endif return; } #if _MIR_DEBUG static void check_cut_row(struct MIR *mir, double r_best) { /* check the cut after back bound substitution or elimination of auxiliary variables */ int m = mir->m; int n = mir->n; int j, k; double r, big; /* compute the residual r = sum a[k] * x[k] - b and determine big = max(1, |a[k]|, |b|) */ r = 0.0, big = 1.0; for (j = 1; j <= mir->cut_vec->nnz; j++) { k = mir->cut_vec->ind[j]; xassert(1 <= k && k <= m+n); r += mir->cut_vec->val[j] * mir->x[k]; if (big < fabs(mir->cut_vec->val[j])) big = fabs(mir->cut_vec->val[j]); } r -= mir->cut_rhs; if (big < fabs(mir->cut_rhs)) big = fabs(mir->cut_rhs); /* the residual must be close to r_best */ xassert(fabs(r - r_best) <= 1e-6 * big); return; } #endif static void subst_aux_vars(glp_tree *tree, struct MIR *mir) { /* final substitution to eliminate auxiliary variables */ glp_prob *mip = tree->mip; int m = mir->m; int n = mir->n; GLPAIJ *aij; int j, k, kk, jj; for (j = mir->cut_vec->nnz; j >= 1; j--) { k = mir->cut_vec->ind[j]; xassert(1 <= k && k <= m+n); if (k > m) continue; /* skip structurals */ for (aij = mip->row[k]->ptr; aij != NULL; aij = aij->r_next) { kk = m + aij->col->j; /* structural */ jj = mir->cut_vec->pos[kk]; if (jj == 0) { ios_set_vj(mir->cut_vec, kk, 1.0); jj = mir->cut_vec->pos[kk]; mir->cut_vec->val[jj] = 0.0; } mir->cut_vec->val[jj] += mir->cut_vec->val[j] * aij->val; } mir->cut_vec->val[j] = 0.0; } ios_clean_vec(mir->cut_vec, 0.0); return; } static void add_cut(glp_tree *tree, struct MIR *mir) { /* add constructed cut inequality to the cut pool */ int m = mir->m; int n = mir->n; int j, k, len; int *ind = xcalloc(1+n, sizeof(int)); double *val = xcalloc(1+n, sizeof(double)); len = 0; for (j = mir->cut_vec->nnz; j >= 1; j--) { k = mir->cut_vec->ind[j]; xassert(m+1 <= k && k <= m+n); len++, ind[len] = k - m, val[len] = mir->cut_vec->val[j]; } #if 0 ios_add_cut_row(tree, pool, GLP_RF_MIR, len, ind, val, GLP_UP, mir->cut_rhs); #else glp_ios_add_row(tree, NULL, GLP_RF_MIR, 0, len, ind, val, GLP_UP, mir->cut_rhs); #endif xfree(ind); xfree(val); return; } static int aggregate_row(glp_tree *tree, struct MIR *mir) { /* try to aggregate another row */ glp_prob *mip = tree->mip; int m = mir->m; int n = mir->n; GLPAIJ *aij; IOSVEC *v; int ii, j, jj, k, kk, kappa = 0, ret = 0; double d1, d2, d, d_max = 0.0; /* choose appropriate structural variable in the aggregated row to be substituted */ for (j = 1; j <= mir->agg_vec->nnz; j++) { k = mir->agg_vec->ind[j]; xassert(1 <= k && k <= m+n); if (k <= m) continue; /* skip auxiliary var */ if (mir->isint[k]) continue; /* skip integer var */ if (fabs(mir->agg_vec->val[j]) < 0.001) continue; /* compute distance from x[k] to its lower bound */ kk = mir->vlb[k]; if (kk == 0) { if (mir->lb[k] == -DBL_MAX) d1 = DBL_MAX; else d1 = mir->x[k] - mir->lb[k]; } else { xassert(1 <= kk && kk <= m+n); xassert(mir->isint[kk]); xassert(mir->lb[k] != -DBL_MAX); d1 = mir->x[k] - mir->lb[k] * mir->x[kk]; } /* compute distance from x[k] to its upper bound */ kk = mir->vub[k]; if (kk == 0) { if (mir->vub[k] == +DBL_MAX) d2 = DBL_MAX; else d2 = mir->ub[k] - mir->x[k]; } else { xassert(1 <= kk && kk <= m+n); xassert(mir->isint[kk]); xassert(mir->ub[k] != +DBL_MAX); d2 = mir->ub[k] * mir->x[kk] - mir->x[k]; } /* x[k] cannot be free */ xassert(d1 != DBL_MAX || d2 != DBL_MAX); /* d = min(d1, d2) */ d = (d1 <= d2 ? d1 : d2); xassert(d != DBL_MAX); /* should not be close to corresponding bound */ if (d < 0.001) continue; if (d_max < d) d_max = d, kappa = k; } if (kappa == 0) { /* nothing chosen */ ret = 1; goto done; } /* x[kappa] has been chosen */ xassert(m+1 <= kappa && kappa <= m+n); xassert(!mir->isint[kappa]); /* find another row, which have not been used yet, to eliminate x[kappa] from the aggregated row */ for (ii = 1; ii <= m; ii++) { if (mir->skip[ii]) continue; for (aij = mip->row[ii]->ptr; aij != NULL; aij = aij->r_next) if (aij->col->j == kappa - m) break; if (aij != NULL && fabs(aij->val) >= 0.001) break; } if (ii > m) { /* nothing found */ ret = 2; goto done; } /* row ii has been found; include it in the aggregated list */ mir->agg_cnt++; xassert(mir->agg_cnt <= MAXAGGR); mir->agg_row[mir->agg_cnt] = ii; mir->skip[ii] = 2; /* v := new row */ v = ios_create_vec(m+n); ios_set_vj(v, ii, 1.0); for (aij = mip->row[ii]->ptr; aij != NULL; aij = aij->r_next) ios_set_vj(v, m + aij->col->j, - aij->val); #if _MIR_DEBUG ios_check_vec(v); #endif /* perform gaussian elimination to remove x[kappa] */ j = mir->agg_vec->pos[kappa]; xassert(j != 0); jj = v->pos[kappa]; xassert(jj != 0); ios_linear_comb(mir->agg_vec, - mir->agg_vec->val[j] / v->val[jj], v); ios_delete_vec(v); ios_set_vj(mir->agg_vec, kappa, 0.0); #if _MIR_DEBUG ios_check_vec(mir->agg_vec); #endif done: return ret; } void ios_mir_gen(glp_tree *tree, void *gen) { /* main routine to generate MIR cuts */ glp_prob *mip = tree->mip; struct MIR *mir = gen; int m = mir->m; int n = mir->n; int i; double r_best; xassert(mip->m >= m); xassert(mip->n == n); /* obtain current point */ get_current_point(tree, mir); #if _MIR_DEBUG /* check current point */ check_current_point(mir); #endif /* reset bound substitution flags */ memset(&mir->subst[1], '?', m+n); /* try to generate a set of violated MIR cuts */ for (i = 1; i <= m; i++) { if (mir->skip[i]) continue; /* use original i-th row as initial aggregated constraint */ initial_agg_row(tree, mir, i); loop: ; #if _MIR_DEBUG /* check aggregated row */ check_agg_row(mir); #endif /* substitute fixed variables into aggregated constraint */ subst_fixed_vars(mir); #if _MIR_DEBUG /* check aggregated row */ check_agg_row(mir); #endif #if _MIR_DEBUG /* check bound substitution flags */ { int k; for (k = 1; k <= m+n; k++) xassert(mir->subst[k] == '?'); } #endif /* apply bound substitution heuristic */ bound_subst_heur(mir); /* substitute bounds and build modified constraint */ build_mod_row(mir); #if _MIR_DEBUG /* check modified row */ check_mod_row(mir); #endif /* try to generate violated c-MIR cut for modified row */ r_best = generate(mir); if (r_best > 0.0) { /* success */ #if _MIR_DEBUG /* check raw cut before back bound substitution */ check_raw_cut(mir, r_best); #endif /* back substitution of original bounds */ back_subst(mir); #if _MIR_DEBUG /* check the cut after back bound substitution */ check_cut_row(mir, r_best); #endif /* final substitution to eliminate auxiliary variables */ subst_aux_vars(tree, mir); #if _MIR_DEBUG /* check the cut after elimination of auxiliaries */ check_cut_row(mir, r_best); #endif /* add constructed cut inequality to the cut pool */ add_cut(tree, mir); } /* reset bound substitution flags */ { int j, k; for (j = 1; j <= mir->mod_vec->nnz; j++) { k = mir->mod_vec->ind[j]; xassert(1 <= k && k <= m+n); xassert(mir->subst[k] != '?'); mir->subst[k] = '?'; } } if (r_best == 0.0) { /* failure */ if (mir->agg_cnt < MAXAGGR) { /* try to aggregate another row */ if (aggregate_row(tree, mir) == 0) goto loop; } } /* unmark rows used in the aggregated constraint */ { int k, ii; for (k = 1; k <= mir->agg_cnt; k++) { ii = mir->agg_row[k]; xassert(1 <= ii && ii <= m); xassert(mir->skip[ii] == 2); mir->skip[ii] = 0; } } } return; } /*********************************************************************** * NAME * * ios_mir_term - terminate MIR cut generator * * SYNOPSIS * * #include "glpios.h" * void ios_mir_term(void *gen); * * DESCRIPTION * * The routine ios_mir_term deletes the MIR cut generator working area * freeing all the memory allocated to it. */ void ios_mir_term(void *gen) { struct MIR *mir = gen; xfree(mir->skip); xfree(mir->isint); xfree(mir->lb); xfree(mir->vlb); xfree(mir->ub); xfree(mir->vub); xfree(mir->x); xfree(mir->agg_row); ios_delete_vec(mir->agg_vec); xfree(mir->subst); ios_delete_vec(mir->mod_vec); ios_delete_vec(mir->cut_vec); xfree(mir); return; } /* eof */ Rglpk/src/GLPK/glpgmp.h0000644000176000001440000001433112245352174014353 0ustar ripleyusers/* glpgmp.h (bignum arithmetic) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPGMP_H #define GLPGMP_H #ifdef HAVE_CONFIG_H #include #endif #ifdef HAVE_GMP /* use GNU MP bignum library */ #include #define gmp_pool_count _glp_gmp_pool_count #define gmp_free_mem _glp_gmp_free_mem int gmp_pool_count(void); void gmp_free_mem(void); #else /* use GLPK bignum module */ /*---------------------------------------------------------------------- // INTEGER NUMBERS // // Depending on its magnitude an integer number of arbitrary precision // is represented either in short format or in long format. // // Short format corresponds to the int type and allows representing // integer numbers in the range [-(2^31-1), +(2^31-1)]. Note that for // the most negative number of int type the short format is not used. // // In long format integer numbers are represented using the positional // system with the base (radix) 2^16 = 65536: // // x = (-1)^s sum{j in 0..n-1} d[j] * 65536^j, // // where x is the integer to be represented, s is its sign (+1 or -1), // d[j] are its digits (0 <= d[j] <= 65535). // // RATIONAL NUMBERS // // A rational number is represented as an irreducible fraction: // // p / q, // // where p (numerator) and q (denominator) are integer numbers (q > 0) // having no common divisors. */ struct mpz { /* integer number */ int val; /* if ptr is a null pointer, the number is in short format, and val is its value; otherwise, the number is in long format, and val is its sign (+1 or -1) */ struct mpz_seg *ptr; /* pointer to the linked list of the number segments ordered in ascending of powers of the base */ }; struct mpz_seg { /* integer number segment */ unsigned short d[6]; /* six digits of the number ordered in ascending of powers of the base */ struct mpz_seg *next; /* pointer to the next number segment */ }; struct mpq { /* rational number (p / q) */ struct mpz p; /* numerator */ struct mpz q; /* denominator */ }; typedef struct mpz *mpz_t; typedef struct mpq *mpq_t; #define gmp_get_atom _glp_gmp_get_atom #define gmp_free_atom _glp_gmp_free_atom #define gmp_pool_count _glp_gmp_pool_count #define gmp_get_work _glp_gmp_get_work #define gmp_free_mem _glp_gmp_free_mem #define _mpz_init _glp_mpz_init #define mpz_clear _glp_mpz_clear #define mpz_set _glp_mpz_set #define mpz_set_si _glp_mpz_set_si #define mpz_get_d _glp_mpz_get_d #define mpz_get_d_2exp _glp_mpz_get_d_2exp #define mpz_swap _glp_mpz_swap #define mpz_add _glp_mpz_add #define mpz_sub _glp_mpz_sub #define mpz_mul _glp_mpz_mul #define mpz_neg _glp_mpz_neg #define mpz_abs _glp_mpz_abs #define mpz_div _glp_mpz_div #define mpz_gcd _glp_mpz_gcd #define mpz_cmp _glp_mpz_cmp #define mpz_sgn _glp_mpz_sgn #define mpz_out_str _glp_mpz_out_str #define _mpq_init _glp_mpq_init #define mpq_clear _glp_mpq_clear #define mpq_canonicalize _glp_mpq_canonicalize #define mpq_set _glp_mpq_set #define mpq_set_si _glp_mpq_set_si #define mpq_get_d _glp_mpq_get_d #define mpq_set_d _glp_mpq_set_d #define mpq_add _glp_mpq_add #define mpq_sub _glp_mpq_sub #define mpq_mul _glp_mpq_mul #define mpq_div _glp_mpq_div #define mpq_neg _glp_mpq_neg #define mpq_abs _glp_mpq_abs #define mpq_cmp _glp_mpq_cmp #define mpq_sgn _glp_mpq_sgn #define mpq_out_str _glp_mpq_out_str void *gmp_get_atom(int size); void gmp_free_atom(void *ptr, int size); int gmp_pool_count(void); unsigned short *gmp_get_work(int size); void gmp_free_mem(void); mpz_t _mpz_init(void); #define mpz_init(x) (void)((x) = _mpz_init()) void mpz_clear(mpz_t x); void mpz_set(mpz_t z, mpz_t x); void mpz_set_si(mpz_t x, int val); double mpz_get_d(mpz_t x); double mpz_get_d_2exp(int *exp, mpz_t x); void mpz_swap(mpz_t x, mpz_t y); void mpz_add(mpz_t, mpz_t, mpz_t); void mpz_sub(mpz_t, mpz_t, mpz_t); void mpz_mul(mpz_t, mpz_t, mpz_t); void mpz_neg(mpz_t z, mpz_t x); void mpz_abs(mpz_t z, mpz_t x); void mpz_div(mpz_t q, mpz_t r, mpz_t x, mpz_t y); void mpz_gcd(mpz_t z, mpz_t x, mpz_t y); int mpz_cmp(mpz_t x, mpz_t y); int mpz_sgn(mpz_t x); int mpz_out_str(void *fp, int base, mpz_t x); mpq_t _mpq_init(void); #define mpq_init(x) (void)((x) = _mpq_init()) void mpq_clear(mpq_t x); void mpq_canonicalize(mpq_t x); void mpq_set(mpq_t z, mpq_t x); void mpq_set_si(mpq_t x, int p, unsigned int q); double mpq_get_d(mpq_t x); void mpq_set_d(mpq_t x, double val); void mpq_add(mpq_t z, mpq_t x, mpq_t y); void mpq_sub(mpq_t z, mpq_t x, mpq_t y); void mpq_mul(mpq_t z, mpq_t x, mpq_t y); void mpq_div(mpq_t z, mpq_t x, mpq_t y); void mpq_neg(mpq_t z, mpq_t x); void mpq_abs(mpq_t z, mpq_t x); int mpq_cmp(mpq_t x, mpq_t y); int mpq_sgn(mpq_t x); int mpq_out_str(void *fp, int base, mpq_t x); #endif #endif /* eof */ Rglpk/src/GLPK/jd.c0000644000176000001440000001006712245352174013457 0ustar ripleyusers/* jd.c (conversions between calendar date and Julian day number) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include #include "jd.h" /*********************************************************************** * NAME * * jday - convert calendar date to Julian day number * * SYNOPSIS * * #include "jd.h" * int jday(int d, int m, int y); * * DESCRIPTION * * The routine jday converts a calendar date, Gregorian calendar, to * corresponding Julian day number j. * * From the given day d, month m, and year y, the Julian day number j * is computed without using tables. * * The routine is valid for 1 <= y <= 4000. * * RETURNS * * The routine jday returns the Julian day number, or negative value if * the specified date is incorrect. * * REFERENCES * * R. G. Tantzen, Algorithm 199: conversions between calendar date and * Julian day number, Communications of the ACM, vol. 6, no. 8, p. 444, * Aug. 1963. */ int jday(int d, int m, int y) { int c, ya, j, dd; if (!(1 <= d && d <= 31 && 1 <= m && m <= 12 && 1 <= y && y <= 4000)) return -1; if (m >= 3) m -= 3; else m += 9, y--; c = y / 100; ya = y - 100 * c; j = (146097 * c) / 4 + (1461 * ya) / 4 + (153 * m + 2) / 5 + d + 1721119; jdate(j, &dd, NULL, NULL); if (d != dd) return -1; return j; } /*********************************************************************** * NAME * * jdate - convert Julian day number to calendar date * * SYNOPSIS * * #include "jd.h" * int jdate(int j, int *d, int *m, int *y); * * DESCRIPTION * * The routine jdate converts a Julian day number j to corresponding * calendar date, Gregorian calendar. * * The day d, month m, and year y are computed without using tables and * stored in corresponding locations. * * The routine is valid for 1721426 <= j <= 3182395. * * RETURNS * * If the conversion is successful, the routine returns zero, otherwise * non-zero. * * REFERENCES * * R. G. Tantzen, Algorithm 199: conversions between calendar date and * Julian day number, Communications of the ACM, vol. 6, no. 8, p. 444, * Aug. 1963. */ int jdate(int j, int *d_, int *m_, int *y_) { int d, m, y; if (!(1721426 <= j && j <= 3182395)) return 1; j -= 1721119; y = (4 * j - 1) / 146097; j = (4 * j - 1) % 146097; d = j / 4; j = (4 * d + 3) / 1461; d = (4 * d + 3) % 1461; d = (d + 4) / 4; m = (5 * d - 3) / 153; d = (5 * d - 3) % 153; d = (d + 5) / 5; y = 100 * y + j; if (m <= 9) m += 3; else m -= 9, y++; if (d_ != NULL) *d_ = d; if (m_ != NULL) *m_ = m; if (y_ != NULL) *y_ = y; return 0; } #ifdef GLP_TEST #include #include #include int main(void) { int jbeg, jend, j, d, m, y; jbeg = jday(1, 1, 1); jend = jday(31, 12, 4000); for (j = jbeg; j <= jend; j++) { assert(jdate(j, &d, &m, &y) == 0); assert(jday(d, m, y) == j); } printf("Routines jday and jdate work correctly.\n"); return 0; } #endif /* eof */ Rglpk/src/GLPK/glpenv08.c0000644000176000001440000000744412245352174014532 0ustar ripleyusers/* glpenv08.c (shared library support) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include "env2.h" /* GNU version ********************************************************/ #if defined(HAVE_LTDL) #include void *xdlopen(const char *module) { void *h = NULL; if (lt_dlinit() != 0) { lib_err_msg(lt_dlerror()); goto done; } h = lt_dlopen(module); if (h == NULL) { lib_err_msg(lt_dlerror()); if (lt_dlexit() != 0) xerror("xdlopen: %s\n", lt_dlerror()); } done: return h; } void *xdlsym(void *h, const char *symbol) { void *ptr; xassert(h != NULL); ptr = lt_dlsym(h, symbol); if (ptr == NULL) xerror("xdlsym: %s: %s\n", symbol, lt_dlerror()); return ptr; } void xdlclose(void *h) { xassert(h != NULL); if (lt_dlclose(h) != 0) xerror("xdlclose: %s\n", lt_dlerror()); if (lt_dlexit() != 0) xerror("xdlclose: %s\n", lt_dlerror()); return; } /* POSIX version ******************************************************/ #elif defined(HAVE_DLFCN) #include void *xdlopen(const char *module) { void *h; h = dlopen(module, RTLD_NOW); if (h == NULL) lib_err_msg(dlerror()); return h; } void *xdlsym(void *h, const char *symbol) { void *ptr; xassert(h != NULL); ptr = dlsym(h, symbol); if (ptr == NULL) xerror("xdlsym: %s: %s\n", symbol, dlerror()); return ptr; } void xdlclose(void *h) { xassert(h != NULL); if (dlclose(h) != 0) xerror("xdlclose: %s\n", dlerror()); return; } /* MS Windows version *************************************************/ #elif defined(__WOE__) #include void *xdlopen(const char *module) { void *h; h = LoadLibrary(module); if (h == NULL) { char msg[20]; sprintf(msg, "Error %d", GetLastError()); lib_err_msg(msg); } return h; } void *xdlsym(void *h, const char *symbol) { void *ptr; xassert(h != NULL); ptr = GetProcAddress(h, symbol); if (ptr == NULL) xerror("xdlsym: %s: Error %d\n", symbol, GetLastError()); return ptr; } void xdlclose(void *h) { xassert(h != NULL); if (!FreeLibrary(h)) xerror("xdlclose: Error %d\n", GetLastError()); return; } /* NULL version *******************************************************/ #else void *xdlopen(const char *module) { xassert(module == module); lib_err_msg("Shared libraries not supported"); return NULL; } void *xdlsym(void *h, const char *symbol) { xassert(h != h); xassert(symbol != symbol); return NULL; } void xdlclose(void *h) { xassert(h != h); return; } #endif /* eof */ Rglpk/src/GLPK/glpapi06.c0000644000176000001440000006375612245352174014521 0ustar ripleyusers/* glpapi06.c (simplex method routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpios.h" #include "glpnpp.h" #include "glpspx.h" /*********************************************************************** * NAME * * glp_simplex - solve LP problem with the simplex method * * SYNOPSIS * * int glp_simplex(glp_prob *P, const glp_smcp *parm); * * DESCRIPTION * * The routine glp_simplex is a driver to the LP solver based on the * simplex method. This routine retrieves problem data from the * specified problem object, calls the solver to solve the problem * instance, and stores results of computations back into the problem * object. * * The simplex solver has a set of control parameters. Values of the * control parameters can be passed in a structure glp_smcp, which the * parameter parm points to. * * The parameter parm can be specified as NULL, in which case the LP * solver uses default settings. * * RETURNS * * 0 The LP problem instance has been successfully solved. This code * does not necessarily mean that the solver has found optimal * solution. It only means that the solution process was successful. * * GLP_EBADB * Unable to start the search, because the initial basis specified * in the problem object is invalid--the number of basic (auxiliary * and structural) variables is not the same as the number of rows in * the problem object. * * GLP_ESING * Unable to start the search, because the basis matrix correspodning * to the initial basis is singular within the working precision. * * GLP_ECOND * Unable to start the search, because the basis matrix correspodning * to the initial basis is ill-conditioned, i.e. its condition number * is too large. * * GLP_EBOUND * Unable to start the search, because some double-bounded variables * have incorrect bounds. * * GLP_EFAIL * The search was prematurely terminated due to the solver failure. * * GLP_EOBJLL * The search was prematurely terminated, because the objective * function being maximized has reached its lower limit and continues * decreasing (dual simplex only). * * GLP_EOBJUL * The search was prematurely terminated, because the objective * function being minimized has reached its upper limit and continues * increasing (dual simplex only). * * GLP_EITLIM * The search was prematurely terminated, because the simplex * iteration limit has been exceeded. * * GLP_ETMLIM * The search was prematurely terminated, because the time limit has * been exceeded. * * GLP_ENOPFS * The LP problem instance has no primal feasible solution (only if * the LP presolver is used). * * GLP_ENODFS * The LP problem instance has no dual feasible solution (only if the * LP presolver is used). */ static void trivial_lp(glp_prob *P, const glp_smcp *parm) { /* solve trivial LP which has empty constraint matrix */ GLPROW *row; GLPCOL *col; int i, j; double p_infeas, d_infeas, zeta; P->valid = 0; P->pbs_stat = P->dbs_stat = GLP_FEAS; P->obj_val = P->c0; P->some = 0; p_infeas = d_infeas = 0.0; /* make all auxiliary variables basic */ for (i = 1; i <= P->m; i++) { row = P->row[i]; row->stat = GLP_BS; row->prim = row->dual = 0.0; /* check primal feasibility */ if (row->type == GLP_LO || row->type == GLP_DB || row->type == GLP_FX) { /* row has lower bound */ if (row->lb > + parm->tol_bnd) { P->pbs_stat = GLP_NOFEAS; if (P->some == 0 && parm->meth != GLP_PRIMAL) P->some = i; } if (p_infeas < + row->lb) p_infeas = + row->lb; } if (row->type == GLP_UP || row->type == GLP_DB || row->type == GLP_FX) { /* row has upper bound */ if (row->ub < - parm->tol_bnd) { P->pbs_stat = GLP_NOFEAS; if (P->some == 0 && parm->meth != GLP_PRIMAL) P->some = i; } if (p_infeas < - row->ub) p_infeas = - row->ub; } } /* determine scale factor for the objective row */ zeta = 1.0; for (j = 1; j <= P->n; j++) { col = P->col[j]; if (zeta < fabs(col->coef)) zeta = fabs(col->coef); } zeta = (P->dir == GLP_MIN ? +1.0 : -1.0) / zeta; /* make all structural variables non-basic */ for (j = 1; j <= P->n; j++) { col = P->col[j]; if (col->type == GLP_FR) col->stat = GLP_NF, col->prim = 0.0; else if (col->type == GLP_LO) lo: col->stat = GLP_NL, col->prim = col->lb; else if (col->type == GLP_UP) up: col->stat = GLP_NU, col->prim = col->ub; else if (col->type == GLP_DB) { if (zeta * col->coef > 0.0) goto lo; else if (zeta * col->coef < 0.0) goto up; else if (fabs(col->lb) <= fabs(col->ub)) goto lo; else goto up; } else if (col->type == GLP_FX) col->stat = GLP_NS, col->prim = col->lb; col->dual = col->coef; P->obj_val += col->coef * col->prim; /* check dual feasibility */ if (col->type == GLP_FR || col->type == GLP_LO) { /* column has no upper bound */ if (zeta * col->dual < - parm->tol_dj) { P->dbs_stat = GLP_NOFEAS; if (P->some == 0 && parm->meth == GLP_PRIMAL) P->some = P->m + j; } if (d_infeas < - zeta * col->dual) d_infeas = - zeta * col->dual; } if (col->type == GLP_FR || col->type == GLP_UP) { /* column has no lower bound */ if (zeta * col->dual > + parm->tol_dj) { P->dbs_stat = GLP_NOFEAS; if (P->some == 0 && parm->meth == GLP_PRIMAL) P->some = P->m + j; } if (d_infeas < + zeta * col->dual) d_infeas = + zeta * col->dual; } } /* simulate the simplex solver output */ if (parm->msg_lev >= GLP_MSG_ON && parm->out_dly == 0) { xprintf("~%6d: obj = %17.9e infeas = %10.3e\n", P->it_cnt, P->obj_val, parm->meth == GLP_PRIMAL ? p_infeas : d_infeas); } if (parm->msg_lev >= GLP_MSG_ALL && parm->out_dly == 0) { if (P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS) xprintf("OPTIMAL SOLUTION FOUND\n"); else if (P->pbs_stat == GLP_NOFEAS) xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n"); else if (parm->meth == GLP_PRIMAL) xprintf("PROBLEM HAS UNBOUNDED SOLUTION\n"); else xprintf("PROBLEM HAS NO DUAL FEASIBLE SOLUTION\n"); } return; } static int solve_lp(glp_prob *P, const glp_smcp *parm) { /* solve LP directly without using the preprocessor */ int ret; if (!glp_bf_exists(P)) { ret = glp_factorize(P); if (ret == 0) ; else if (ret == GLP_EBADB) { if (parm->msg_lev >= GLP_MSG_ERR) xprintf("glp_simplex: initial basis is invalid\n"); } else if (ret == GLP_ESING) { if (parm->msg_lev >= GLP_MSG_ERR) xprintf("glp_simplex: initial basis is singular\n"); } else if (ret == GLP_ECOND) { if (parm->msg_lev >= GLP_MSG_ERR) xprintf( "glp_simplex: initial basis is ill-conditioned\n"); } else xassert(ret != ret); if (ret != 0) goto done; } if (parm->meth == GLP_PRIMAL) ret = spx_primal(P, parm); else if (parm->meth == GLP_DUALP) { ret = spx_dual(P, parm); if (ret == GLP_EFAIL && P->valid) ret = spx_primal(P, parm); } else if (parm->meth == GLP_DUAL) ret = spx_dual(P, parm); else xassert(parm != parm); done: return ret; } static int preprocess_and_solve_lp(glp_prob *P, const glp_smcp *parm) { /* solve LP using the preprocessor */ NPP *npp; glp_prob *lp = NULL; glp_bfcp bfcp; int ret; if (parm->msg_lev >= GLP_MSG_ALL) xprintf("Preprocessing...\n"); /* create preprocessor workspace */ npp = npp_create_wksp(); /* load original problem into the preprocessor workspace */ npp_load_prob(npp, P, GLP_OFF, GLP_SOL, GLP_OFF); /* process LP prior to applying primal/dual simplex method */ ret = npp_simplex(npp, parm); if (ret == 0) ; else if (ret == GLP_ENOPFS) { if (parm->msg_lev >= GLP_MSG_ALL) xprintf("PROBLEM HAS NO PRIMAL FEASIBLE SOLUTION\n"); } else if (ret == GLP_ENODFS) { if (parm->msg_lev >= GLP_MSG_ALL) xprintf("PROBLEM HAS NO DUAL FEASIBLE SOLUTION\n"); } else xassert(ret != ret); if (ret != 0) goto done; /* build transformed LP */ lp = glp_create_prob(); npp_build_prob(npp, lp); /* if the transformed LP is empty, it has empty solution, which is optimal */ if (lp->m == 0 && lp->n == 0) { lp->pbs_stat = lp->dbs_stat = GLP_FEAS; lp->obj_val = lp->c0; if (parm->msg_lev >= GLP_MSG_ON && parm->out_dly == 0) { xprintf("~%6d: obj = %17.9e infeas = %10.3e\n", P->it_cnt, lp->obj_val, 0.0); } if (parm->msg_lev >= GLP_MSG_ALL) xprintf("OPTIMAL SOLUTION FOUND BY LP PREPROCESSOR\n"); goto post; } if (parm->msg_lev >= GLP_MSG_ALL) { xprintf("%d row%s, %d column%s, %d non-zero%s\n", lp->m, lp->m == 1 ? "" : "s", lp->n, lp->n == 1 ? "" : "s", lp->nnz, lp->nnz == 1 ? "" : "s"); } /* inherit basis factorization control parameters */ glp_get_bfcp(P, &bfcp); glp_set_bfcp(lp, &bfcp); /* scale the transformed problem */ { ENV *env = get_env_ptr(); int term_out = env->term_out; if (!term_out || parm->msg_lev < GLP_MSG_ALL) env->term_out = GLP_OFF; else env->term_out = GLP_ON; glp_scale_prob(lp, GLP_SF_AUTO); env->term_out = term_out; } /* build advanced initial basis */ { ENV *env = get_env_ptr(); int term_out = env->term_out; if (!term_out || parm->msg_lev < GLP_MSG_ALL) env->term_out = GLP_OFF; else env->term_out = GLP_ON; glp_adv_basis(lp, 0); env->term_out = term_out; } /* solve the transformed LP */ lp->it_cnt = P->it_cnt; ret = solve_lp(lp, parm); P->it_cnt = lp->it_cnt; /* only optimal solution can be postprocessed */ if (!(ret == 0 && lp->pbs_stat == GLP_FEAS && lp->dbs_stat == GLP_FEAS)) { if (parm->msg_lev >= GLP_MSG_ERR) xprintf("glp_simplex: unable to recover undefined or non-op" "timal solution\n"); if (ret == 0) { if (lp->pbs_stat == GLP_NOFEAS) ret = GLP_ENOPFS; else if (lp->dbs_stat == GLP_NOFEAS) ret = GLP_ENODFS; else xassert(lp != lp); } goto done; } post: /* postprocess solution from the transformed LP */ npp_postprocess(npp, lp); /* the transformed LP is no longer needed */ glp_delete_prob(lp), lp = NULL; /* store solution to the original problem */ npp_unload_sol(npp, P); /* the original LP has been successfully solved */ ret = 0; done: /* delete the transformed LP, if it exists */ if (lp != NULL) glp_delete_prob(lp); /* delete preprocessor workspace */ npp_delete_wksp(npp); return ret; } int glp_simplex(glp_prob *P, const glp_smcp *parm) { /* solve LP problem with the simplex method */ glp_smcp _parm; int i, j, ret; /* check problem object */ if (P == NULL || P->magic != GLP_PROB_MAGIC) xerror("glp_simplex: P = %p; invalid problem object\n", P); if (P->tree != NULL && P->tree->reason != 0) xerror("glp_simplex: operation not allowed\n"); /* check control parameters */ if (parm == NULL) parm = &_parm, glp_init_smcp((glp_smcp *)parm); if (!(parm->msg_lev == GLP_MSG_OFF || parm->msg_lev == GLP_MSG_ERR || parm->msg_lev == GLP_MSG_ON || parm->msg_lev == GLP_MSG_ALL || parm->msg_lev == GLP_MSG_DBG)) xerror("glp_simplex: msg_lev = %d; invalid parameter\n", parm->msg_lev); if (!(parm->meth == GLP_PRIMAL || parm->meth == GLP_DUALP || parm->meth == GLP_DUAL)) xerror("glp_simplex: meth = %d; invalid parameter\n", parm->meth); if (!(parm->pricing == GLP_PT_STD || parm->pricing == GLP_PT_PSE)) xerror("glp_simplex: pricing = %d; invalid parameter\n", parm->pricing); if (!(parm->r_test == GLP_RT_STD || parm->r_test == GLP_RT_HAR)) xerror("glp_simplex: r_test = %d; invalid parameter\n", parm->r_test); if (!(0.0 < parm->tol_bnd && parm->tol_bnd < 1.0)) xerror("glp_simplex: tol_bnd = %g; invalid parameter\n", parm->tol_bnd); if (!(0.0 < parm->tol_dj && parm->tol_dj < 1.0)) xerror("glp_simplex: tol_dj = %g; invalid parameter\n", parm->tol_dj); if (!(0.0 < parm->tol_piv && parm->tol_piv < 1.0)) xerror("glp_simplex: tol_piv = %g; invalid parameter\n", parm->tol_piv); if (parm->it_lim < 0) xerror("glp_simplex: it_lim = %d; invalid parameter\n", parm->it_lim); if (parm->tm_lim < 0) xerror("glp_simplex: tm_lim = %d; invalid parameter\n", parm->tm_lim); if (parm->out_frq < 1) xerror("glp_simplex: out_frq = %d; invalid parameter\n", parm->out_frq); if (parm->out_dly < 0) xerror("glp_simplex: out_dly = %d; invalid parameter\n", parm->out_dly); if (!(parm->presolve == GLP_ON || parm->presolve == GLP_OFF)) xerror("glp_simplex: presolve = %d; invalid parameter\n", parm->presolve); /* basic solution is currently undefined */ P->pbs_stat = P->dbs_stat = GLP_UNDEF; P->obj_val = 0.0; P->some = 0; /* check bounds of double-bounded variables */ for (i = 1; i <= P->m; i++) { GLPROW *row = P->row[i]; if (row->type == GLP_DB && row->lb >= row->ub) { if (parm->msg_lev >= GLP_MSG_ERR) xprintf("glp_simplex: row %d: lb = %g, ub = %g; incorrec" "t bounds\n", i, row->lb, row->ub); ret = GLP_EBOUND; goto done; } } for (j = 1; j <= P->n; j++) { GLPCOL *col = P->col[j]; if (col->type == GLP_DB && col->lb >= col->ub) { if (parm->msg_lev >= GLP_MSG_ERR) xprintf("glp_simplex: column %d: lb = %g, ub = %g; incor" "rect bounds\n", j, col->lb, col->ub); ret = GLP_EBOUND; goto done; } } /* solve LP problem */ if (parm->msg_lev >= GLP_MSG_ALL) { xprintf("GLPK Simplex Optimizer, v%s\n", glp_version()); xprintf("%d row%s, %d column%s, %d non-zero%s\n", P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s", P->nnz, P->nnz == 1 ? "" : "s"); } if (P->nnz == 0) trivial_lp(P, parm), ret = 0; else if (!parm->presolve) ret = solve_lp(P, parm); else ret = preprocess_and_solve_lp(P, parm); done: /* return to the application program */ return ret; } /*********************************************************************** * NAME * * glp_init_smcp - initialize simplex method control parameters * * SYNOPSIS * * void glp_init_smcp(glp_smcp *parm); * * DESCRIPTION * * The routine glp_init_smcp initializes control parameters, which are * used by the simplex solver, with default values. * * Default values of the control parameters are stored in a glp_smcp * structure, which the parameter parm points to. */ void glp_init_smcp(glp_smcp *parm) { parm->msg_lev = GLP_MSG_ALL; parm->meth = GLP_PRIMAL; parm->pricing = GLP_PT_PSE; parm->r_test = GLP_RT_HAR; parm->tol_bnd = 1e-7; parm->tol_dj = 1e-7; parm->tol_piv = 1e-10; parm->obj_ll = -DBL_MAX; parm->obj_ul = +DBL_MAX; parm->it_lim = INT_MAX; parm->tm_lim = INT_MAX; parm->out_frq = 500; parm->out_dly = 0; parm->presolve = GLP_OFF; return; } /*********************************************************************** * NAME * * glp_get_status - retrieve generic status of basic solution * * SYNOPSIS * * int glp_get_status(glp_prob *lp); * * RETURNS * * The routine glp_get_status reports the generic status of the basic * solution for the specified problem object as follows: * * GLP_OPT - solution is optimal; * GLP_FEAS - solution is feasible; * GLP_INFEAS - solution is infeasible; * GLP_NOFEAS - problem has no feasible solution; * GLP_UNBND - problem has unbounded solution; * GLP_UNDEF - solution is undefined. */ int glp_get_status(glp_prob *lp) { int status; status = glp_get_prim_stat(lp); switch (status) { case GLP_FEAS: switch (glp_get_dual_stat(lp)) { case GLP_FEAS: status = GLP_OPT; break; case GLP_NOFEAS: status = GLP_UNBND; break; case GLP_UNDEF: case GLP_INFEAS: status = status; break; default: xassert(lp != lp); } break; case GLP_UNDEF: case GLP_INFEAS: case GLP_NOFEAS: status = status; break; default: xassert(lp != lp); } return status; } /*********************************************************************** * NAME * * glp_get_prim_stat - retrieve status of primal basic solution * * SYNOPSIS * * int glp_get_prim_stat(glp_prob *lp); * * RETURNS * * The routine glp_get_prim_stat reports the status of the primal basic * solution for the specified problem object as follows: * * 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 glp_get_prim_stat(glp_prob *lp) { int pbs_stat = lp->pbs_stat; return pbs_stat; } /*********************************************************************** * NAME * * glp_get_dual_stat - retrieve status of dual basic solution * * SYNOPSIS * * int glp_get_dual_stat(glp_prob *lp); * * RETURNS * * The routine glp_get_dual_stat reports the status of the dual basic * solution for the specified problem object as follows: * * 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 glp_get_dual_stat(glp_prob *lp) { int dbs_stat = lp->dbs_stat; return dbs_stat; } /*********************************************************************** * NAME * * glp_get_obj_val - retrieve objective value (basic solution) * * SYNOPSIS * * double glp_get_obj_val(glp_prob *lp); * * RETURNS * * The routine glp_get_obj_val returns value of the objective function * for basic solution. */ double glp_get_obj_val(glp_prob *lp) { /*struct LPXCPS *cps = lp->cps;*/ double z; z = lp->obj_val; /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/ return z; } /*********************************************************************** * NAME * * glp_get_row_stat - retrieve row status * * SYNOPSIS * * int glp_get_row_stat(glp_prob *lp, int i); * * RETURNS * * The routine glp_get_row_stat returns current status assigned to the * auxiliary variable associated with i-th row as follows: * * GLP_BS - basic variable; * GLP_NL - non-basic variable on its lower bound; * GLP_NU - non-basic variable on its upper bound; * GLP_NF - non-basic free (unbounded) variable; * GLP_NS - non-basic fixed variable. */ int glp_get_row_stat(glp_prob *lp, int i) { if (!(1 <= i && i <= lp->m)) xerror("glp_get_row_stat: i = %d; row number out of range\n", i); return lp->row[i]->stat; } /*********************************************************************** * NAME * * glp_get_row_prim - retrieve row primal value (basic solution) * * SYNOPSIS * * double glp_get_row_prim(glp_prob *lp, int i); * * RETURNS * * The routine glp_get_row_prim returns primal value of the auxiliary * variable associated with i-th row. */ double glp_get_row_prim(glp_prob *lp, int i) { /*struct LPXCPS *cps = lp->cps;*/ double prim; if (!(1 <= i && i <= lp->m)) xerror("glp_get_row_prim: i = %d; row number out of range\n", i); prim = lp->row[i]->prim; /*if (cps->round && fabs(prim) < 1e-9) prim = 0.0;*/ return prim; } /*********************************************************************** * NAME * * glp_get_row_dual - retrieve row dual value (basic solution) * * SYNOPSIS * * double glp_get_row_dual(glp_prob *lp, int i); * * RETURNS * * The routine glp_get_row_dual returns dual value (i.e. reduced cost) * of the auxiliary variable associated with i-th row. */ double glp_get_row_dual(glp_prob *lp, int i) { /*struct LPXCPS *cps = lp->cps;*/ double dual; if (!(1 <= i && i <= lp->m)) xerror("glp_get_row_dual: i = %d; row number out of range\n", i); dual = lp->row[i]->dual; /*if (cps->round && fabs(dual) < 1e-9) dual = 0.0;*/ return dual; } /*********************************************************************** * NAME * * glp_get_col_stat - retrieve column status * * SYNOPSIS * * int glp_get_col_stat(glp_prob *lp, int j); * * RETURNS * * The routine glp_get_col_stat returns current status assigned to the * structural variable associated with j-th column as follows: * * GLP_BS - basic variable; * GLP_NL - non-basic variable on its lower bound; * GLP_NU - non-basic variable on its upper bound; * GLP_NF - non-basic free (unbounded) variable; * GLP_NS - non-basic fixed variable. */ int glp_get_col_stat(glp_prob *lp, int j) { if (!(1 <= j && j <= lp->n)) xerror("glp_get_col_stat: j = %d; column number out of range\n" , j); return lp->col[j]->stat; } /*********************************************************************** * NAME * * glp_get_col_prim - retrieve column primal value (basic solution) * * SYNOPSIS * * double glp_get_col_prim(glp_prob *lp, int j); * * RETURNS * * The routine glp_get_col_prim returns primal value of the structural * variable associated with j-th column. */ double glp_get_col_prim(glp_prob *lp, int j) { /*struct LPXCPS *cps = lp->cps;*/ double prim; if (!(1 <= j && j <= lp->n)) xerror("glp_get_col_prim: j = %d; column number out of range\n" , j); prim = lp->col[j]->prim; /*if (cps->round && fabs(prim) < 1e-9) prim = 0.0;*/ return prim; } /*********************************************************************** * NAME * * glp_get_col_dual - retrieve column dual value (basic solution) * * SYNOPSIS * * double glp_get_col_dual(glp_prob *lp, int j); * * RETURNS * * The routine glp_get_col_dual returns dual value (i.e. reduced cost) * of the structural variable associated with j-th column. */ double glp_get_col_dual(glp_prob *lp, int j) { /*struct LPXCPS *cps = lp->cps;*/ double dual; if (!(1 <= j && j <= lp->n)) xerror("glp_get_col_dual: j = %d; column number out of range\n" , j); dual = lp->col[j]->dual; /*if (cps->round && fabs(dual) < 1e-9) dual = 0.0;*/ return dual; } /*********************************************************************** * NAME * * glp_get_unbnd_ray - determine variable causing unboundedness * * SYNOPSIS * * int glp_get_unbnd_ray(glp_prob *lp); * * RETURNS * * The routine glp_get_unbnd_ray returns the number k of a variable, * which causes primal or dual unboundedness. If 1 <= k <= m, it is * k-th auxiliary variable, and if m+1 <= k <= m+n, it is (k-m)-th * structural variable, where m is the number of rows, n is the number * of columns in the problem object. If such variable is not defined, * the routine returns 0. * * COMMENTS * * If it is not exactly known which version of the simplex solver * detected unboundedness, i.e. whether the unboundedness is primal or * dual, it is sufficient to check the status of the variable reported * with the routine glp_get_row_stat or glp_get_col_stat. If the * variable is non-basic, the unboundedness is primal, otherwise, if * the variable is basic, the unboundedness is dual (the latter case * means that the problem has no primal feasible dolution). */ int glp_get_unbnd_ray(glp_prob *lp) { int k; k = lp->some; xassert(k >= 0); if (k > lp->m + lp->n) k = 0; return k; } /* eof */ Rglpk/src/GLPK/time.c0000644000176000001440000001040412245352174014013 0ustar ripleyusers/* time.c (standard time) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include "env.h" #include "jd.h" /*********************************************************************** * NAME * * glp_time - determine current universal time * * SYNOPSIS * * double glp_time(void); * * RETURNS * * The routine glp_time returns the current universal time (UTC), in * milliseconds, elapsed since 00:00:00 GMT January 1, 1970. */ #define EPOCH 2440588 /* jday(1, 1, 1970) */ /* POSIX version ******************************************************/ #if defined(HAVE_SYS_TIME_H) && defined(HAVE_GETTIMEOFDAY) #include #include double glp_time(void) { struct timeval tv; struct tm *tm; int j; double t; gettimeofday(&tv, NULL); tm = gmtime(&tv.tv_sec); j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year); xassert(j >= 0); t = ((((double)(j - EPOCH) * 24.0 + (double)tm->tm_hour) * 60.0 + (double)tm->tm_min) * 60.0 + (double)tm->tm_sec) * 1000.0 + (double)(tv.tv_usec / 1000); return t; } /* MS Windows version *************************************************/ #elif defined(__WOE__) #include double glp_time(void) { SYSTEMTIME st; int j; double t; GetSystemTime(&st); j = jday(st.wDay, st.wMonth, st.wYear); xassert(j >= 0); t = ((((double)(j - EPOCH) * 24.0 + (double)st.wHour) * 60.0 + (double)st.wMinute) * 60.0 + (double)st.wSecond) * 1000.0 + (double)st.wMilliseconds; return t; } /* portable ANSI C version ********************************************/ #else #include double glp_time(void) { time_t timer; struct tm *tm; int j; double t; timer = time(NULL); tm = gmtime(&timer); j = jday(tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year); xassert(j >= 0); t = ((((double)(j - EPOCH) * 24.0 + (double)tm->tm_hour) * 60.0 + (double)tm->tm_min) * 60.0 + (double)tm->tm_sec) * 1000.0; return t; } #endif /*********************************************************************** * NAME * * glp_difftime - compute difference between two time values * * SYNOPSIS * * double glp_difftime(double t1, double t0); * * RETURNS * * The routine glp_difftime returns the difference between two time * values t1 and t0, expressed in seconds. */ double glp_difftime(double t1, double t0) { return (t1 - t0) / 1000.0; } /**********************************************************************/ #ifdef GLP_TEST #include int main(void) { int ttt, ss, mm, hh, day, month, year; double t; t = glp_time(); xprintf("t = %.f\n", t); assert(floor(t) == t); ttt = (int)fmod(t, 1000.0); t = (t - (double)ttt) / 1000.0; assert(floor(t) == t); ss = (int)fmod(t, 60.0); t = (t - (double)ss) / 60.0; assert(floor(t) == t); mm = (int)fmod(t, 60.0); t = (t - (double)mm) / 60.0; assert(floor(t) == t); hh = (int)fmod(t, 24.0); t = (t - (double)hh) / 24.0; assert(floor(t) == t); assert(jdate((int)t + EPOCH, &day, &month, &year) == 0); printf("%04d-%02d-%02d %02d:%02d:%02d.%03d\n", year, month, day, hh, mm, ss, ttt); return 0; } #endif /* eof */ Rglpk/src/GLPK/glplpx01.c0000644000176000001440000013756512245352174014546 0ustar ripleyusers/* glplpx01.c (obsolete API routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpapi.h" struct LPXCPS { /* control parameters and statistics */ int msg_lev; /* level of messages output by the solver: 0 - no output 1 - error messages only 2 - normal output 3 - full output (includes informational messages) */ int scale; /* scaling option: 0 - no scaling 1 - equilibration scaling 2 - geometric mean scaling 3 - geometric mean scaling, then equilibration scaling */ int dual; /* dual simplex option: 0 - use primal simplex 1 - use dual simplex */ int price; /* pricing option (for both primal and dual simplex): 0 - textbook pricing 1 - steepest edge pricing */ double relax; /* relaxation parameter used in the ratio test; if it is zero, the textbook ratio test is used; if it is non-zero (should be positive), Harris' two-pass ratio test is used; in the latter case on the first pass basic variables (in the case of primal simplex) or reduced costs of non-basic variables (in the case of dual simplex) are allowed to slightly violate their bounds, but not more than (relax * tol_bnd) or (relax * tol_dj) (thus, relax is a percentage of tol_bnd or tol_dj) */ double tol_bnd; /* relative tolerance used to check if the current basic solution is primal feasible */ double tol_dj; /* absolute tolerance used to check if the current basic solution is dual feasible */ double tol_piv; /* relative tolerance used to choose eligible pivotal elements of the simplex table in the ratio test */ int round; /* solution rounding option: 0 - report all computed values and reduced costs "as is" 1 - if possible (allowed by the tolerances), replace computed values and reduced costs which are close to zero by exact zeros */ double obj_ll; /* lower limit of the objective function; if on the phase II the objective function reaches this limit and continues decreasing, the solver stops the search */ double obj_ul; /* upper limit of the objective function; if on the phase II the objective function reaches this limit and continues increasing, the solver stops the search */ int it_lim; /* simplex iterations limit; if this value is positive, it is decreased by one each time when one simplex iteration has been performed, and reaching zero value signals the solver to stop the search; negative value means no iterations limit */ double tm_lim; /* searching time limit, in seconds; if this value is positive, it is decreased each time when one simplex iteration has been performed by the amount of time spent for the iteration, and reaching zero value signals the solver to stop the search; negative value means no time limit */ int out_frq; /* output frequency, in iterations; this parameter specifies how frequently the solver sends information about the solution to the standard output */ double out_dly; /* output delay, in seconds; this parameter specifies how long the solver should delay sending information about the solution to the standard output; zero value means no delay */ int branch; /* MIP */ /* branching heuristic: 0 - branch on first variable 1 - branch on last variable 2 - branch using heuristic by Driebeck and Tomlin 3 - branch on most fractional variable */ int btrack; /* MIP */ /* backtracking heuristic: 0 - select most recent node (depth first search) 1 - select earliest node (breadth first search) 2 - select node using the best projection heuristic 3 - select node with best local bound */ double tol_int; /* MIP */ /* absolute tolerance used to check if the current basic solution is integer feasible */ double tol_obj; /* MIP */ /* relative tolerance used to check if the value of the objective function is not better than in the best known integer feasible solution */ int mps_info; /* lpx_write_mps */ /* if this flag is set, the routine lpx_write_mps outputs several comment cards that contains some information about the problem; otherwise the routine outputs no comment cards */ int mps_obj; /* lpx_write_mps */ /* this parameter tells the routine lpx_write_mps how to output the objective function row: 0 - never output objective function row 1 - always output objective function row 2 - output objective function row if and only if the problem has no free rows */ int mps_orig; /* lpx_write_mps */ /* if this flag is set, the routine lpx_write_mps uses original row and column symbolic names; otherwise the routine generates plain names using ordinal numbers of rows and columns */ int mps_wide; /* lpx_write_mps */ /* if this flag is set, the routine lpx_write_mps uses all data fields; otherwise the routine keeps fields 5 and 6 empty */ int mps_free; /* lpx_write_mps */ /* if this flag is set, the routine lpx_write_mps omits column and vector names everytime if possible (free style); otherwise the routine never omits these names (pedantic style) */ int mps_skip; /* lpx_write_mps */ /* if this flag is set, the routine lpx_write_mps skips empty columns (i.e. which has no constraint coefficients); otherwise the routine outputs all columns */ int lpt_orig; /* lpx_write_lpt */ /* if this flag is set, the routine lpx_write_lpt uses original row and column symbolic names; otherwise the routine generates plain names using ordinal numbers of rows and columns */ int presol; /* lpx_simplex */ /* LP presolver option: 0 - do not use LP presolver 1 - use LP presolver */ int binarize; /* lpx_intopt */ /* if this flag is set, the routine lpx_intopt replaces integer columns by binary ones */ int use_cuts; /* lpx_intopt */ /* if this flag is set, the routine lpx_intopt tries generating cutting planes: LPX_C_COVER - mixed cover cuts LPX_C_CLIQUE - clique cuts LPX_C_GOMORY - Gomory's mixed integer cuts LPX_C_ALL - all cuts */ double mip_gap; /* MIP */ /* relative MIP gap tolerance */ }; LPX *lpx_create_prob(void) { /* create problem object */ return glp_create_prob(); } void lpx_set_prob_name(LPX *lp, const char *name) { /* assign (change) problem name */ glp_set_prob_name(lp, name); return; } void lpx_set_obj_name(LPX *lp, const char *name) { /* assign (change) objective function name */ glp_set_obj_name(lp, name); return; } void lpx_set_obj_dir(LPX *lp, int dir) { /* set (change) optimization direction flag */ glp_set_obj_dir(lp, dir - LPX_MIN + GLP_MIN); return; } int lpx_add_rows(LPX *lp, int nrs) { /* add new rows to problem object */ return glp_add_rows(lp, nrs); } int lpx_add_cols(LPX *lp, int ncs) { /* add new columns to problem object */ return glp_add_cols(lp, ncs); } void lpx_set_row_name(LPX *lp, int i, const char *name) { /* assign (change) row name */ glp_set_row_name(lp, i, name); return; } void lpx_set_col_name(LPX *lp, int j, const char *name) { /* assign (change) column name */ glp_set_col_name(lp, j, name); return; } void lpx_set_row_bnds(LPX *lp, int i, int type, double lb, double ub) { /* set (change) row bounds */ glp_set_row_bnds(lp, i, type - LPX_FR + GLP_FR, lb, ub); return; } void lpx_set_col_bnds(LPX *lp, int j, int type, double lb, double ub) { /* set (change) column bounds */ glp_set_col_bnds(lp, j, type - LPX_FR + GLP_FR, lb, ub); return; } void lpx_set_obj_coef(glp_prob *lp, int j, double coef) { /* set (change) obj. coefficient or constant term */ glp_set_obj_coef(lp, j, coef); return; } void lpx_set_mat_row(LPX *lp, int i, int len, const int ind[], const double val[]) { /* set (replace) row of the constraint matrix */ glp_set_mat_row(lp, i, len, ind, val); return; } void lpx_set_mat_col(LPX *lp, int j, int len, const int ind[], const double val[]) { /* set (replace) column of the constraint matrix */ glp_set_mat_col(lp, j, len, ind, val); return; } void lpx_load_matrix(LPX *lp, int ne, const int ia[], const int ja[], const double ar[]) { /* load (replace) the whole constraint matrix */ glp_load_matrix(lp, ne, ia, ja, ar); return; } void lpx_del_rows(LPX *lp, int nrs, const int num[]) { /* delete specified rows from problem object */ glp_del_rows(lp, nrs, num); return; } void lpx_del_cols(LPX *lp, int ncs, const int num[]) { /* delete specified columns from problem object */ glp_del_cols(lp, ncs, num); return; } void lpx_delete_prob(LPX *lp) { /* delete problem object */ glp_delete_prob(lp); return; } const char *lpx_get_prob_name(LPX *lp) { /* retrieve problem name */ return glp_get_prob_name(lp); } const char *lpx_get_obj_name(LPX *lp) { /* retrieve objective function name */ return glp_get_obj_name(lp); } int lpx_get_obj_dir(LPX *lp) { /* retrieve optimization direction flag */ return glp_get_obj_dir(lp) - GLP_MIN + LPX_MIN; } int lpx_get_num_rows(LPX *lp) { /* retrieve number of rows */ return glp_get_num_rows(lp); } int lpx_get_num_cols(LPX *lp) { /* retrieve number of columns */ return glp_get_num_cols(lp); } const char *lpx_get_row_name(LPX *lp, int i) { /* retrieve row name */ return glp_get_row_name(lp, i); } const char *lpx_get_col_name(LPX *lp, int j) { /* retrieve column name */ return glp_get_col_name(lp, j); } int lpx_get_row_type(LPX *lp, int i) { /* retrieve row type */ return glp_get_row_type(lp, i) - GLP_FR + LPX_FR; } double lpx_get_row_lb(glp_prob *lp, int i) { /* retrieve row lower bound */ double lb; lb = glp_get_row_lb(lp, i); if (lb == -DBL_MAX) lb = 0.0; return lb; } double lpx_get_row_ub(glp_prob *lp, int i) { /* retrieve row upper bound */ double ub; ub = glp_get_row_ub(lp, i); if (ub == +DBL_MAX) ub = 0.0; return ub; } void lpx_get_row_bnds(glp_prob *lp, int i, int *typx, double *lb, double *ub) { /* retrieve row bounds */ if (typx != NULL) *typx = lpx_get_row_type(lp, i); if (lb != NULL) *lb = lpx_get_row_lb(lp, i); if (ub != NULL) *ub = lpx_get_row_ub(lp, i); return; } int lpx_get_col_type(LPX *lp, int j) { /* retrieve column type */ return glp_get_col_type(lp, j) - GLP_FR + LPX_FR; } double lpx_get_col_lb(glp_prob *lp, int j) { /* retrieve column lower bound */ double lb; lb = glp_get_col_lb(lp, j); if (lb == -DBL_MAX) lb = 0.0; return lb; } double lpx_get_col_ub(glp_prob *lp, int j) { /* retrieve column upper bound */ double ub; ub = glp_get_col_ub(lp, j); if (ub == +DBL_MAX) ub = 0.0; return ub; } void lpx_get_col_bnds(glp_prob *lp, int j, int *typx, double *lb, double *ub) { /* retrieve column bounds */ if (typx != NULL) *typx = lpx_get_col_type(lp, j); if (lb != NULL) *lb = lpx_get_col_lb(lp, j); if (ub != NULL) *ub = lpx_get_col_ub(lp, j); return; } double lpx_get_obj_coef(LPX *lp, int j) { /* retrieve obj. coefficient or constant term */ return glp_get_obj_coef(lp, j); } int lpx_get_num_nz(LPX *lp) { /* retrieve number of constraint coefficients */ return glp_get_num_nz(lp); } int lpx_get_mat_row(LPX *lp, int i, int ind[], double val[]) { /* retrieve row of the constraint matrix */ return glp_get_mat_row(lp, i, ind, val); } int lpx_get_mat_col(LPX *lp, int j, int ind[], double val[]) { /* retrieve column of the constraint matrix */ return glp_get_mat_col(lp, j, ind, val); } void lpx_create_index(LPX *lp) { /* create the name index */ glp_create_index(lp); return; } int lpx_find_row(LPX *lp, const char *name) { /* find row by its name */ return glp_find_row(lp, name); } int lpx_find_col(LPX *lp, const char *name) { /* find column by its name */ return glp_find_col(lp, name); } void lpx_delete_index(LPX *lp) { /* delete the name index */ glp_delete_index(lp); return; } void lpx_scale_prob(LPX *lp) { /* scale problem data */ switch (lpx_get_int_parm(lp, LPX_K_SCALE)) { case 0: /* no scaling */ glp_unscale_prob(lp); break; case 1: /* equilibration scaling */ glp_scale_prob(lp, GLP_SF_EQ); break; case 2: /* geometric mean scaling */ glp_scale_prob(lp, GLP_SF_GM); break; case 3: /* geometric mean scaling, then equilibration scaling */ glp_scale_prob(lp, GLP_SF_GM | GLP_SF_EQ); break; default: xassert(lp != lp); } return; } void lpx_unscale_prob(LPX *lp) { /* unscale problem data */ glp_unscale_prob(lp); return; } void lpx_set_row_stat(LPX *lp, int i, int stat) { /* set (change) row status */ glp_set_row_stat(lp, i, stat - LPX_BS + GLP_BS); return; } void lpx_set_col_stat(LPX *lp, int j, int stat) { /* set (change) column status */ glp_set_col_stat(lp, j, stat - LPX_BS + GLP_BS); return; } void lpx_std_basis(LPX *lp) { /* construct standard initial LP basis */ glp_std_basis(lp); return; } void lpx_adv_basis(LPX *lp) { /* construct advanced initial LP basis */ glp_adv_basis(lp, 0); return; } void lpx_cpx_basis(LPX *lp) { /* construct Bixby's initial LP basis */ glp_cpx_basis(lp); return; } static void fill_smcp(LPX *lp, glp_smcp *parm) { glp_init_smcp(parm); switch (lpx_get_int_parm(lp, LPX_K_MSGLEV)) { case 0: parm->msg_lev = GLP_MSG_OFF; break; case 1: parm->msg_lev = GLP_MSG_ERR; break; case 2: parm->msg_lev = GLP_MSG_ON; break; case 3: parm->msg_lev = GLP_MSG_ALL; break; default: xassert(lp != lp); } switch (lpx_get_int_parm(lp, LPX_K_DUAL)) { case 0: parm->meth = GLP_PRIMAL; break; case 1: parm->meth = GLP_DUAL; break; default: xassert(lp != lp); } switch (lpx_get_int_parm(lp, LPX_K_PRICE)) { case 0: parm->pricing = GLP_PT_STD; break; case 1: parm->pricing = GLP_PT_PSE; break; default: xassert(lp != lp); } if (lpx_get_real_parm(lp, LPX_K_RELAX) == 0.0) parm->r_test = GLP_RT_STD; else parm->r_test = GLP_RT_HAR; parm->tol_bnd = lpx_get_real_parm(lp, LPX_K_TOLBND); parm->tol_dj = lpx_get_real_parm(lp, LPX_K_TOLDJ); parm->tol_piv = lpx_get_real_parm(lp, LPX_K_TOLPIV); parm->obj_ll = lpx_get_real_parm(lp, LPX_K_OBJLL); parm->obj_ul = lpx_get_real_parm(lp, LPX_K_OBJUL); if (lpx_get_int_parm(lp, LPX_K_ITLIM) < 0) parm->it_lim = INT_MAX; else parm->it_lim = lpx_get_int_parm(lp, LPX_K_ITLIM); if (lpx_get_real_parm(lp, LPX_K_TMLIM) < 0.0) parm->tm_lim = INT_MAX; else parm->tm_lim = (int)(1000.0 * lpx_get_real_parm(lp, LPX_K_TMLIM)); parm->out_frq = lpx_get_int_parm(lp, LPX_K_OUTFRQ); parm->out_dly = (int)(1000.0 * lpx_get_real_parm(lp, LPX_K_OUTDLY)); switch (lpx_get_int_parm(lp, LPX_K_PRESOL)) { case 0: parm->presolve = GLP_OFF; break; case 1: parm->presolve = GLP_ON; break; default: xassert(lp != lp); } return; } int lpx_simplex(LPX *lp) { /* easy-to-use driver to the simplex method */ glp_smcp parm; int ret; fill_smcp(lp, &parm); ret = glp_simplex(lp, &parm); switch (ret) { case 0: ret = LPX_E_OK; break; case GLP_EBADB: case GLP_ESING: case GLP_ECOND: case GLP_EBOUND: ret = LPX_E_FAULT; break; case GLP_EFAIL: ret = LPX_E_SING; break; case GLP_EOBJLL: ret = LPX_E_OBJLL; break; case GLP_EOBJUL: ret = LPX_E_OBJUL; break; case GLP_EITLIM: ret = LPX_E_ITLIM; break; case GLP_ETMLIM: ret = LPX_E_TMLIM; break; case GLP_ENOPFS: ret = LPX_E_NOPFS; break; case GLP_ENODFS: ret = LPX_E_NODFS; break; default: xassert(ret != ret); } return ret; } int lpx_exact(LPX *lp) { /* easy-to-use driver to the exact simplex method */ glp_smcp parm; int ret; fill_smcp(lp, &parm); ret = glp_exact(lp, &parm); switch (ret) { case 0: ret = LPX_E_OK; break; case GLP_EBADB: case GLP_ESING: case GLP_EBOUND: case GLP_EFAIL: ret = LPX_E_FAULT; break; case GLP_EITLIM: ret = LPX_E_ITLIM; break; case GLP_ETMLIM: ret = LPX_E_TMLIM; break; default: xassert(ret != ret); } return ret; } int lpx_get_status(glp_prob *lp) { /* retrieve generic status of basic solution */ int status; switch (glp_get_status(lp)) { case GLP_OPT: status = LPX_OPT; break; case GLP_FEAS: status = LPX_FEAS; break; case GLP_INFEAS: status = LPX_INFEAS; break; case GLP_NOFEAS: status = LPX_NOFEAS; break; case GLP_UNBND: status = LPX_UNBND; break; case GLP_UNDEF: status = LPX_UNDEF; break; default: xassert(lp != lp); } return status; } int lpx_get_prim_stat(glp_prob *lp) { /* retrieve status of primal basic solution */ return glp_get_prim_stat(lp) - GLP_UNDEF + LPX_P_UNDEF; } int lpx_get_dual_stat(glp_prob *lp) { /* retrieve status of dual basic solution */ return glp_get_dual_stat(lp) - GLP_UNDEF + LPX_D_UNDEF; } double lpx_get_obj_val(LPX *lp) { /* retrieve objective value (basic solution) */ return glp_get_obj_val(lp); } int lpx_get_row_stat(LPX *lp, int i) { /* retrieve row status (basic solution) */ return glp_get_row_stat(lp, i) - GLP_BS + LPX_BS; } double lpx_get_row_prim(LPX *lp, int i) { /* retrieve row primal value (basic solution) */ return glp_get_row_prim(lp, i); } double lpx_get_row_dual(LPX *lp, int i) { /* retrieve row dual value (basic solution) */ return glp_get_row_dual(lp, i); } void lpx_get_row_info(glp_prob *lp, int i, int *tagx, double *vx, double *dx) { /* obtain row solution information */ if (tagx != NULL) *tagx = lpx_get_row_stat(lp, i); if (vx != NULL) *vx = lpx_get_row_prim(lp, i); if (dx != NULL) *dx = lpx_get_row_dual(lp, i); return; } int lpx_get_col_stat(LPX *lp, int j) { /* retrieve column status (basic solution) */ return glp_get_col_stat(lp, j) - GLP_BS + LPX_BS; } double lpx_get_col_prim(LPX *lp, int j) { /* retrieve column primal value (basic solution) */ return glp_get_col_prim(lp, j); } double lpx_get_col_dual(glp_prob *lp, int j) { /* retrieve column dual value (basic solution) */ return glp_get_col_dual(lp, j); } void lpx_get_col_info(glp_prob *lp, int j, int *tagx, double *vx, double *dx) { /* obtain column solution information */ if (tagx != NULL) *tagx = lpx_get_col_stat(lp, j); if (vx != NULL) *vx = lpx_get_col_prim(lp, j); if (dx != NULL) *dx = lpx_get_col_dual(lp, j); return; } int lpx_get_ray_info(LPX *lp) { /* determine what causes primal unboundness */ return glp_get_unbnd_ray(lp); } void lpx_check_kkt(LPX *lp, int scaled, LPXKKT *kkt) { /* check Karush-Kuhn-Tucker conditions */ int ae_ind, re_ind; double ae_max, re_max; xassert(scaled == scaled); glp_check_kkt(lp, GLP_SOL, GLP_KKT_PE, &ae_max, &ae_ind, &re_max, &re_ind); kkt->pe_ae_max = ae_max; kkt->pe_ae_row = ae_ind; kkt->pe_re_max = re_max; kkt->pe_re_row = re_ind; if (re_max <= 1e-9) kkt->pe_quality = 'H'; else if (re_max <= 1e-6) kkt->pe_quality = 'M'; else if (re_max <= 1e-3) kkt->pe_quality = 'L'; else kkt->pe_quality = '?'; glp_check_kkt(lp, GLP_SOL, GLP_KKT_PB, &ae_max, &ae_ind, &re_max, &re_ind); kkt->pb_ae_max = ae_max; kkt->pb_ae_ind = ae_ind; kkt->pb_re_max = re_max; kkt->pb_re_ind = re_ind; if (re_max <= 1e-9) kkt->pb_quality = 'H'; else if (re_max <= 1e-6) kkt->pb_quality = 'M'; else if (re_max <= 1e-3) kkt->pb_quality = 'L'; else kkt->pb_quality = '?'; glp_check_kkt(lp, GLP_SOL, GLP_KKT_DE, &ae_max, &ae_ind, &re_max, &re_ind); kkt->de_ae_max = ae_max; if (ae_ind == 0) kkt->de_ae_col = 0; else kkt->de_ae_col = ae_ind - lp->m; kkt->de_re_max = re_max; if (re_ind == 0) kkt->de_re_col = 0; else kkt->de_re_col = ae_ind - lp->m; if (re_max <= 1e-9) kkt->de_quality = 'H'; else if (re_max <= 1e-6) kkt->de_quality = 'M'; else if (re_max <= 1e-3) kkt->de_quality = 'L'; else kkt->de_quality = '?'; glp_check_kkt(lp, GLP_SOL, GLP_KKT_DB, &ae_max, &ae_ind, &re_max, &re_ind); kkt->db_ae_max = ae_max; kkt->db_ae_ind = ae_ind; kkt->db_re_max = re_max; kkt->db_re_ind = re_ind; if (re_max <= 1e-9) kkt->db_quality = 'H'; else if (re_max <= 1e-6) kkt->db_quality = 'M'; else if (re_max <= 1e-3) kkt->db_quality = 'L'; else kkt->db_quality = '?'; kkt->cs_ae_max = 0.0, kkt->cs_ae_ind = 0; kkt->cs_re_max = 0.0, kkt->cs_re_ind = 0; kkt->cs_quality = 'H'; return; } int lpx_warm_up(LPX *lp) { /* "warm up" LP basis */ int ret; ret = glp_warm_up(lp); if (ret == 0) ret = LPX_E_OK; else if (ret == GLP_EBADB) ret = LPX_E_BADB; else if (ret == GLP_ESING) ret = LPX_E_SING; else if (ret == GLP_ECOND) ret = LPX_E_SING; else xassert(ret != ret); return ret; } int lpx_eval_tab_row(LPX *lp, int k, int ind[], double val[]) { /* compute row of the simplex tableau */ return glp_eval_tab_row(lp, k, ind, val); } int lpx_eval_tab_col(LPX *lp, int k, int ind[], double val[]) { /* compute column of the simplex tableau */ return glp_eval_tab_col(lp, k, ind, val); } int lpx_transform_row(LPX *lp, int len, int ind[], double val[]) { /* transform explicitly specified row */ return glp_transform_row(lp, len, ind, val); } int lpx_transform_col(LPX *lp, int len, int ind[], double val[]) { /* transform explicitly specified column */ return glp_transform_col(lp, len, ind, val); } int lpx_prim_ratio_test(LPX *lp, int len, const int ind[], const double val[], int how, double tol) { /* perform primal ratio test */ int piv; piv = glp_prim_rtest(lp, len, ind, val, how, tol); xassert(0 <= piv && piv <= len); return piv == 0 ? 0 : ind[piv]; } int lpx_dual_ratio_test(LPX *lp, int len, const int ind[], const double val[], int how, double tol) { /* perform dual ratio test */ int piv; piv = glp_dual_rtest(lp, len, ind, val, how, tol); xassert(0 <= piv && piv <= len); return piv == 0 ? 0 : ind[piv]; } int lpx_interior(LPX *lp) { /* easy-to-use driver to the interior-point method */ int ret; ret = glp_interior(lp, NULL); switch (ret) { case 0: ret = LPX_E_OK; break; case GLP_EFAIL: ret = LPX_E_FAULT; break; case GLP_ENOFEAS: ret = LPX_E_NOFEAS; break; case GLP_ENOCVG: ret = LPX_E_NOCONV; break; case GLP_EITLIM: ret = LPX_E_ITLIM; break; case GLP_EINSTAB: ret = LPX_E_INSTAB; break; default: xassert(ret != ret); } return ret; } int lpx_ipt_status(glp_prob *lp) { /* retrieve status of interior-point solution */ int status; switch (glp_ipt_status(lp)) { case GLP_UNDEF: status = LPX_T_UNDEF; break; case GLP_OPT: status = LPX_T_OPT; break; default: xassert(lp != lp); } return status; } double lpx_ipt_obj_val(LPX *lp) { /* retrieve objective value (interior point) */ return glp_ipt_obj_val(lp); } double lpx_ipt_row_prim(LPX *lp, int i) { /* retrieve row primal value (interior point) */ return glp_ipt_row_prim(lp, i); } double lpx_ipt_row_dual(LPX *lp, int i) { /* retrieve row dual value (interior point) */ return glp_ipt_row_dual(lp, i); } double lpx_ipt_col_prim(LPX *lp, int j) { /* retrieve column primal value (interior point) */ return glp_ipt_col_prim(lp, j); } double lpx_ipt_col_dual(LPX *lp, int j) { /* retrieve column dual value (interior point) */ return glp_ipt_col_dual(lp, j); } void lpx_set_class(LPX *lp, int klass) { /* set problem class */ xassert(lp == lp); if (!(klass == LPX_LP || klass == LPX_MIP)) xerror("lpx_set_class: invalid problem class\n"); return; } int lpx_get_class(LPX *lp) { /* determine problem klass */ return glp_get_num_int(lp) == 0 ? LPX_LP : LPX_MIP; } void lpx_set_col_kind(LPX *lp, int j, int kind) { /* set (change) column kind */ glp_set_col_kind(lp, j, kind - LPX_CV + GLP_CV); return; } int lpx_get_col_kind(LPX *lp, int j) { /* retrieve column kind */ return glp_get_col_kind(lp, j) == GLP_CV ? LPX_CV : LPX_IV; } int lpx_get_num_int(LPX *lp) { /* retrieve number of integer columns */ return glp_get_num_int(lp); } int lpx_get_num_bin(LPX *lp) { /* retrieve number of binary columns */ return glp_get_num_bin(lp); } static int solve_mip(LPX *lp, int presolve) { glp_iocp parm; int ret; glp_init_iocp(&parm); switch (lpx_get_int_parm(lp, LPX_K_MSGLEV)) { case 0: parm.msg_lev = GLP_MSG_OFF; break; case 1: parm.msg_lev = GLP_MSG_ERR; break; case 2: parm.msg_lev = GLP_MSG_ON; break; case 3: parm.msg_lev = GLP_MSG_ALL; break; default: xassert(lp != lp); } switch (lpx_get_int_parm(lp, LPX_K_BRANCH)) { case 0: parm.br_tech = GLP_BR_FFV; break; case 1: parm.br_tech = GLP_BR_LFV; break; case 2: parm.br_tech = GLP_BR_DTH; break; case 3: parm.br_tech = GLP_BR_MFV; break; default: xassert(lp != lp); } switch (lpx_get_int_parm(lp, LPX_K_BTRACK)) { case 0: parm.bt_tech = GLP_BT_DFS; break; case 1: parm.bt_tech = GLP_BT_BFS; break; case 2: parm.bt_tech = GLP_BT_BPH; break; case 3: parm.bt_tech = GLP_BT_BLB; break; default: xassert(lp != lp); } parm.tol_int = lpx_get_real_parm(lp, LPX_K_TOLINT); parm.tol_obj = lpx_get_real_parm(lp, LPX_K_TOLOBJ); if (lpx_get_real_parm(lp, LPX_K_TMLIM) < 0.0 || lpx_get_real_parm(lp, LPX_K_TMLIM) > 1e6) parm.tm_lim = INT_MAX; else parm.tm_lim = (int)(1000.0 * lpx_get_real_parm(lp, LPX_K_TMLIM)); parm.mip_gap = lpx_get_real_parm(lp, LPX_K_MIPGAP); if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_GOMORY) parm.gmi_cuts = GLP_ON; else parm.gmi_cuts = GLP_OFF; if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_MIR) parm.mir_cuts = GLP_ON; else parm.mir_cuts = GLP_OFF; if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_COVER) parm.cov_cuts = GLP_ON; else parm.cov_cuts = GLP_OFF; if (lpx_get_int_parm(lp, LPX_K_USECUTS) & LPX_C_CLIQUE) parm.clq_cuts = GLP_ON; else parm.clq_cuts = GLP_OFF; parm.presolve = presolve; if (lpx_get_int_parm(lp, LPX_K_BINARIZE)) parm.binarize = GLP_ON; ret = glp_intopt(lp, &parm); switch (ret) { case 0: ret = LPX_E_OK; break; case GLP_ENOPFS: ret = LPX_E_NOPFS; break; case GLP_ENODFS: ret = LPX_E_NODFS; break; case GLP_EBOUND: case GLP_EROOT: ret = LPX_E_FAULT; break; case GLP_EFAIL: ret = LPX_E_SING; break; case GLP_EMIPGAP: ret = LPX_E_MIPGAP; break; case GLP_ETMLIM: ret = LPX_E_TMLIM; break; default: xassert(ret != ret); } return ret; } int lpx_integer(LPX *lp) { /* easy-to-use driver to the branch-and-bound method */ return solve_mip(lp, GLP_OFF); } int lpx_intopt(LPX *lp) { /* easy-to-use driver to the branch-and-bound method */ return solve_mip(lp, GLP_ON); } int lpx_mip_status(glp_prob *lp) { /* retrieve status of MIP solution */ int status; switch (glp_mip_status(lp)) { case GLP_UNDEF: status = LPX_I_UNDEF; break; case GLP_OPT: status = LPX_I_OPT; break; case GLP_FEAS: status = LPX_I_FEAS; break; case GLP_NOFEAS: status = LPX_I_NOFEAS; break; default: xassert(lp != lp); } return status; } double lpx_mip_obj_val(LPX *lp) { /* retrieve objective value (MIP solution) */ return glp_mip_obj_val(lp); } double lpx_mip_row_val(LPX *lp, int i) { /* retrieve row value (MIP solution) */ return glp_mip_row_val(lp, i); } double lpx_mip_col_val(LPX *lp, int j) { /* retrieve column value (MIP solution) */ return glp_mip_col_val(lp, j); } void lpx_check_int(LPX *lp, LPXKKT *kkt) { /* check integer feasibility conditions */ int ae_ind, re_ind; double ae_max, re_max; glp_check_kkt(lp, GLP_MIP, GLP_KKT_PE, &ae_max, &ae_ind, &re_max, &re_ind); kkt->pe_ae_max = ae_max; kkt->pe_ae_row = ae_ind; kkt->pe_re_max = re_max; kkt->pe_re_row = re_ind; if (re_max <= 1e-9) kkt->pe_quality = 'H'; else if (re_max <= 1e-6) kkt->pe_quality = 'M'; else if (re_max <= 1e-3) kkt->pe_quality = 'L'; else kkt->pe_quality = '?'; glp_check_kkt(lp, GLP_MIP, GLP_KKT_PB, &ae_max, &ae_ind, &re_max, &re_ind); kkt->pb_ae_max = ae_max; kkt->pb_ae_ind = ae_ind; kkt->pb_re_max = re_max; kkt->pb_re_ind = re_ind; if (re_max <= 1e-9) kkt->pb_quality = 'H'; else if (re_max <= 1e-6) kkt->pb_quality = 'M'; else if (re_max <= 1e-3) kkt->pb_quality = 'L'; else kkt->pb_quality = '?'; return; } #if 1 /* 17/XI-2009 */ static void reset_parms(LPX *lp) { /* reset control parameters to default values */ struct LPXCPS *cps = lp->parms; xassert(cps != NULL); cps->msg_lev = 3; cps->scale = 1; cps->dual = 0; cps->price = 1; cps->relax = 0.07; cps->tol_bnd = 1e-7; cps->tol_dj = 1e-7; cps->tol_piv = 1e-9; cps->round = 0; cps->obj_ll = -DBL_MAX; cps->obj_ul = +DBL_MAX; cps->it_lim = -1; #if 0 /* 02/XII-2010 */ lp->it_cnt = 0; #endif cps->tm_lim = -1.0; cps->out_frq = 200; cps->out_dly = 0.0; cps->branch = 2; cps->btrack = 3; cps->tol_int = 1e-5; cps->tol_obj = 1e-7; cps->mps_info = 1; cps->mps_obj = 2; cps->mps_orig = 0; cps->mps_wide = 1; cps->mps_free = 0; cps->mps_skip = 0; cps->lpt_orig = 0; cps->presol = 0; cps->binarize = 0; cps->use_cuts = 0; cps->mip_gap = 0.0; return; } #endif #if 1 /* 17/XI-2009 */ static struct LPXCPS *access_parms(LPX *lp) { /* allocate and initialize control parameters, if necessary */ if (lp->parms == NULL) { lp->parms = xmalloc(sizeof(struct LPXCPS)); reset_parms(lp); } return lp->parms; } #endif #if 1 /* 17/XI-2009 */ void lpx_reset_parms(LPX *lp) { /* reset control parameters to default values */ access_parms(lp); reset_parms(lp); return; } #endif void lpx_set_int_parm(LPX *lp, int parm, int val) { /* set (change) integer control parameter */ #if 0 /* 17/XI-2009 */ struct LPXCPS *cps = lp->cps; #else struct LPXCPS *cps = access_parms(lp); #endif switch (parm) { case LPX_K_MSGLEV: if (!(0 <= val && val <= 3)) xerror("lpx_set_int_parm: MSGLEV = %d; invalid value\n", val); cps->msg_lev = val; break; case LPX_K_SCALE: if (!(0 <= val && val <= 3)) xerror("lpx_set_int_parm: SCALE = %d; invalid value\n", val); cps->scale = val; break; case LPX_K_DUAL: if (!(val == 0 || val == 1)) xerror("lpx_set_int_parm: DUAL = %d; invalid value\n", val); cps->dual = val; break; case LPX_K_PRICE: if (!(val == 0 || val == 1)) xerror("lpx_set_int_parm: PRICE = %d; invalid value\n", val); cps->price = val; break; case LPX_K_ROUND: if (!(val == 0 || val == 1)) xerror("lpx_set_int_parm: ROUND = %d; invalid value\n", val); cps->round = val; break; case LPX_K_ITLIM: cps->it_lim = val; break; case LPX_K_ITCNT: lp->it_cnt = val; break; case LPX_K_OUTFRQ: if (!(val > 0)) xerror("lpx_set_int_parm: OUTFRQ = %d; invalid value\n", val); cps->out_frq = val; break; case LPX_K_BRANCH: if (!(val == 0 || val == 1 || val == 2 || val == 3)) xerror("lpx_set_int_parm: BRANCH = %d; invalid value\n", val); cps->branch = val; break; case LPX_K_BTRACK: if (!(val == 0 || val == 1 || val == 2 || val == 3)) xerror("lpx_set_int_parm: BTRACK = %d; invalid value\n", val); cps->btrack = val; break; case LPX_K_MPSINFO: if (!(val == 0 || val == 1)) xerror("lpx_set_int_parm: MPSINFO = %d; invalid value\n", val); cps->mps_info = val; break; case LPX_K_MPSOBJ: if (!(val == 0 || val == 1 || val == 2)) xerror("lpx_set_int_parm: MPSOBJ = %d; invalid value\n", val); cps->mps_obj = val; break; case LPX_K_MPSORIG: if (!(val == 0 || val == 1)) xerror("lpx_set_int_parm: MPSORIG = %d; invalid value\n", val); cps->mps_orig = val; break; case LPX_K_MPSWIDE: if (!(val == 0 || val == 1)) xerror("lpx_set_int_parm: MPSWIDE = %d; invalid value\n", val); cps->mps_wide = val; break; case LPX_K_MPSFREE: if (!(val == 0 || val == 1)) xerror("lpx_set_int_parm: MPSFREE = %d; invalid value\n", val); cps->mps_free = val; break; case LPX_K_MPSSKIP: if (!(val == 0 || val == 1)) xerror("lpx_set_int_parm: MPSSKIP = %d; invalid value\n", val); cps->mps_skip = val; break; case LPX_K_LPTORIG: if (!(val == 0 || val == 1)) xerror("lpx_set_int_parm: LPTORIG = %d; invalid value\n", val); cps->lpt_orig = val; break; case LPX_K_PRESOL: if (!(val == 0 || val == 1)) xerror("lpx_set_int_parm: PRESOL = %d; invalid value\n", val); cps->presol = val; break; case LPX_K_BINARIZE: if (!(val == 0 || val == 1)) xerror("lpx_set_int_parm: BINARIZE = %d; invalid value\n" , val); cps->binarize = val; break; case LPX_K_USECUTS: if (val & ~LPX_C_ALL) xerror("lpx_set_int_parm: USECUTS = 0x%X; invalid value\n", val); cps->use_cuts = val; break; case LPX_K_BFTYPE: #if 0 if (!(1 <= val && val <= 3)) xerror("lpx_set_int_parm: BFTYPE = %d; invalid value\n", val); cps->bf_type = val; #else { glp_bfcp parm; glp_get_bfcp(lp, &parm); switch (val) { case 1: parm.type = GLP_BF_FT; break; case 2: parm.type = GLP_BF_BG; break; case 3: parm.type = GLP_BF_GR; break; default: xerror("lpx_set_int_parm: BFTYPE = %d; invalid val" "ue\n", val); } glp_set_bfcp(lp, &parm); } #endif break; default: xerror("lpx_set_int_parm: parm = %d; invalid parameter\n", parm); } return; } int lpx_get_int_parm(LPX *lp, int parm) { /* query integer control parameter */ #if 0 /* 17/XI-2009 */ struct LPXCPS *cps = lp->cps; #else struct LPXCPS *cps = access_parms(lp); #endif int val = 0; switch (parm) { case LPX_K_MSGLEV: val = cps->msg_lev; break; case LPX_K_SCALE: val = cps->scale; break; case LPX_K_DUAL: val = cps->dual; break; case LPX_K_PRICE: val = cps->price; break; case LPX_K_ROUND: val = cps->round; break; case LPX_K_ITLIM: val = cps->it_lim; break; case LPX_K_ITCNT: val = lp->it_cnt; break; case LPX_K_OUTFRQ: val = cps->out_frq; break; case LPX_K_BRANCH: val = cps->branch; break; case LPX_K_BTRACK: val = cps->btrack; break; case LPX_K_MPSINFO: val = cps->mps_info; break; case LPX_K_MPSOBJ: val = cps->mps_obj; break; case LPX_K_MPSORIG: val = cps->mps_orig; break; case LPX_K_MPSWIDE: val = cps->mps_wide; break; case LPX_K_MPSFREE: val = cps->mps_free; break; case LPX_K_MPSSKIP: val = cps->mps_skip; break; case LPX_K_LPTORIG: val = cps->lpt_orig; break; case LPX_K_PRESOL: val = cps->presol; break; case LPX_K_BINARIZE: val = cps->binarize; break; case LPX_K_USECUTS: val = cps->use_cuts; break; case LPX_K_BFTYPE: #if 0 val = cps->bf_type; break; #else { glp_bfcp parm; glp_get_bfcp(lp, &parm); switch (parm.type) { case GLP_BF_FT: val = 1; break; case GLP_BF_BG: val = 2; break; case GLP_BF_GR: val = 3; break; default: xassert(lp != lp); } } break; #endif default: xerror("lpx_get_int_parm: parm = %d; invalid parameter\n", parm); } return val; } void lpx_set_real_parm(LPX *lp, int parm, double val) { /* set (change) real control parameter */ #if 0 /* 17/XI-2009 */ struct LPXCPS *cps = lp->cps; #else struct LPXCPS *cps = access_parms(lp); #endif switch (parm) { case LPX_K_RELAX: if (!(0.0 <= val && val <= 1.0)) xerror("lpx_set_real_parm: RELAX = %g; invalid value\n", val); cps->relax = val; break; case LPX_K_TOLBND: if (!(DBL_EPSILON <= val && val <= 0.001)) xerror("lpx_set_real_parm: TOLBND = %g; invalid value\n", val); #if 0 if (cps->tol_bnd > val) { /* invalidate the basic solution */ lp->p_stat = LPX_P_UNDEF; lp->d_stat = LPX_D_UNDEF; } #endif cps->tol_bnd = val; break; case LPX_K_TOLDJ: if (!(DBL_EPSILON <= val && val <= 0.001)) xerror("lpx_set_real_parm: TOLDJ = %g; invalid value\n", val); #if 0 if (cps->tol_dj > val) { /* invalidate the basic solution */ lp->p_stat = LPX_P_UNDEF; lp->d_stat = LPX_D_UNDEF; } #endif cps->tol_dj = val; break; case LPX_K_TOLPIV: if (!(DBL_EPSILON <= val && val <= 0.001)) xerror("lpx_set_real_parm: TOLPIV = %g; invalid value\n", val); cps->tol_piv = val; break; case LPX_K_OBJLL: cps->obj_ll = val; break; case LPX_K_OBJUL: cps->obj_ul = val; break; case LPX_K_TMLIM: cps->tm_lim = val; break; case LPX_K_OUTDLY: cps->out_dly = val; break; case LPX_K_TOLINT: if (!(DBL_EPSILON <= val && val <= 0.001)) xerror("lpx_set_real_parm: TOLINT = %g; invalid value\n", val); cps->tol_int = val; break; case LPX_K_TOLOBJ: if (!(DBL_EPSILON <= val && val <= 0.001)) xerror("lpx_set_real_parm: TOLOBJ = %g; invalid value\n", val); cps->tol_obj = val; break; case LPX_K_MIPGAP: if (val < 0.0) xerror("lpx_set_real_parm: MIPGAP = %g; invalid value\n", val); cps->mip_gap = val; break; default: xerror("lpx_set_real_parm: parm = %d; invalid parameter\n", parm); } return; } double lpx_get_real_parm(LPX *lp, int parm) { /* query real control parameter */ #if 0 /* 17/XI-2009 */ struct LPXCPS *cps = lp->cps; #else struct LPXCPS *cps = access_parms(lp); #endif double val = 0.0; switch (parm) { case LPX_K_RELAX: val = cps->relax; break; case LPX_K_TOLBND: val = cps->tol_bnd; break; case LPX_K_TOLDJ: val = cps->tol_dj; break; case LPX_K_TOLPIV: val = cps->tol_piv; break; case LPX_K_OBJLL: val = cps->obj_ll; break; case LPX_K_OBJUL: val = cps->obj_ul; break; case LPX_K_TMLIM: val = cps->tm_lim; break; case LPX_K_OUTDLY: val = cps->out_dly; break; case LPX_K_TOLINT: val = cps->tol_int; break; case LPX_K_TOLOBJ: val = cps->tol_obj; break; case LPX_K_MIPGAP: val = cps->mip_gap; break; default: xerror("lpx_get_real_parm: parm = %d; invalid parameter\n", parm); } return val; } LPX *lpx_read_mps(const char *fname) { /* read problem data in fixed MPS format */ LPX *lp = lpx_create_prob(); if (glp_read_mps(lp, GLP_MPS_DECK, NULL, fname)) lpx_delete_prob(lp), lp = NULL; return lp; } int lpx_write_mps(LPX *lp, const char *fname) { /* write problem data in fixed MPS format */ return glp_write_mps(lp, GLP_MPS_DECK, NULL, fname); } int lpx_read_bas(LPX *lp, const char *fname) { /* read LP basis in fixed MPS format */ #if 0 /* 13/IV-2009 */ return read_bas(lp, fname); #else xassert(lp == lp); xassert(fname == fname); xerror("lpx_read_bas: operation not supported\n"); return 0; #endif } int lpx_write_bas(LPX *lp, const char *fname) { /* write LP basis in fixed MPS format */ #if 0 /* 13/IV-2009 */ return write_bas(lp, fname); #else xassert(lp == lp); xassert(fname == fname); xerror("lpx_write_bas: operation not supported\n"); return 0; #endif } LPX *lpx_read_freemps(const char *fname) { /* read problem data in free MPS format */ LPX *lp = lpx_create_prob(); if (glp_read_mps(lp, GLP_MPS_FILE, NULL, fname)) lpx_delete_prob(lp), lp = NULL; return lp; } int lpx_write_freemps(LPX *lp, const char *fname) { /* write problem data in free MPS format */ return glp_write_mps(lp, GLP_MPS_FILE, NULL, fname); } LPX *lpx_read_cpxlp(const char *fname) { /* read problem data in CPLEX LP format */ LPX *lp; lp = lpx_create_prob(); if (glp_read_lp(lp, NULL, fname)) lpx_delete_prob(lp), lp = NULL; return lp; } int lpx_write_cpxlp(LPX *lp, const char *fname) { /* write problem data in CPLEX LP format */ return glp_write_lp(lp, NULL, fname); } LPX *lpx_read_model(const char *model, const char *data, const char *output) { /* read LP/MIP model written in GNU MathProg language */ LPX *lp = NULL; glp_tran *tran; /* allocate the translator workspace */ tran = glp_mpl_alloc_wksp(); /* read model section and optional data section */ if (glp_mpl_read_model(tran, model, data != NULL)) goto done; /* read separate data section, if required */ if (data != NULL) if (glp_mpl_read_data(tran, data)) goto done; /* generate the model */ if (glp_mpl_generate(tran, output)) goto done; /* build the problem instance from the model */ lp = glp_create_prob(); glp_mpl_build_prob(tran, lp); done: /* free the translator workspace */ glp_mpl_free_wksp(tran); /* bring the problem object to the calling program */ return lp; } int lpx_print_prob(LPX *lp, const char *fname) { /* write problem data in plain text format */ return glp_write_lp(lp, NULL, fname); } int lpx_print_sol(LPX *lp, const char *fname) { /* write LP problem solution in printable format */ return glp_print_sol(lp, fname); } int lpx_print_sens_bnds(LPX *lp, const char *fname) { /* write bounds sensitivity information */ if (glp_get_status(lp) == GLP_OPT && !glp_bf_exists(lp)) glp_factorize(lp); return glp_print_ranges(lp, 0, NULL, 0, fname); } int lpx_print_ips(LPX *lp, const char *fname) { /* write interior point solution in printable format */ return glp_print_ipt(lp, fname); } int lpx_print_mip(LPX *lp, const char *fname) { /* write MIP problem solution in printable format */ return glp_print_mip(lp, fname); } int lpx_is_b_avail(glp_prob *lp) { /* check if LP basis is available */ return glp_bf_exists(lp); } int lpx_main(int argc, const char *argv[]) { /* stand-alone LP/MIP solver */ return glp_main(argc, argv); } /* eof */ Rglpk/src/GLPK/glpmat.c0000644000176000001440000010036412245352174014346 0ustar ripleyusers/* glpmat.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #include "glpmat.h" #include "qmd.h" #include "amd/amd.h" #include "colamd/colamd.h" /*---------------------------------------------------------------------- -- check_fvs - check sparse vector in full-vector storage format. -- -- SYNOPSIS -- -- #include "glpmat.h" -- int check_fvs(int n, int nnz, int ind[], double vec[]); -- -- DESCRIPTION -- -- The routine check_fvs checks if a given vector of dimension n in -- full-vector storage format has correct representation. -- -- RETURNS -- -- The routine returns one of the following codes: -- -- 0 - the vector is correct; -- 1 - the number of elements (n) is negative; -- 2 - the number of non-zero elements (nnz) is negative; -- 3 - some element index is out of range; -- 4 - some element index is duplicate; -- 5 - some non-zero element is out of pattern. */ int check_fvs(int n, int nnz, int ind[], double vec[]) { int i, t, ret, *flag = NULL; /* check the number of elements */ if (n < 0) { ret = 1; goto done; } /* check the number of non-zero elements */ if (nnz < 0) { ret = 2; goto done; } /* check vector indices */ flag = xcalloc(1+n, sizeof(int)); for (i = 1; i <= n; i++) flag[i] = 0; for (t = 1; t <= nnz; t++) { i = ind[t]; if (!(1 <= i && i <= n)) { ret = 3; goto done; } if (flag[i]) { ret = 4; goto done; } flag[i] = 1; } /* check vector elements */ for (i = 1; i <= n; i++) { if (!flag[i] && vec[i] != 0.0) { ret = 5; goto done; } } /* the vector is ok */ ret = 0; done: if (flag != NULL) xfree(flag); return ret; } /*---------------------------------------------------------------------- -- check_pattern - check pattern of sparse matrix. -- -- SYNOPSIS -- -- #include "glpmat.h" -- int check_pattern(int m, int n, int A_ptr[], int A_ind[]); -- -- DESCRIPTION -- -- The routine check_pattern checks the pattern of a given mxn matrix -- in storage-by-rows format. -- -- RETURNS -- -- The routine returns one of the following codes: -- -- 0 - the pattern is correct; -- 1 - the number of rows (m) is negative; -- 2 - the number of columns (n) is negative; -- 3 - A_ptr[1] is not 1; -- 4 - some column index is out of range; -- 5 - some column indices are duplicate. */ int check_pattern(int m, int n, int A_ptr[], int A_ind[]) { int i, j, ptr, ret, *flag = NULL; /* check the number of rows */ if (m < 0) { ret = 1; goto done; } /* check the number of columns */ if (n < 0) { ret = 2; goto done; } /* check location A_ptr[1] */ if (A_ptr[1] != 1) { ret = 3; goto done; } /* check row patterns */ flag = xcalloc(1+n, sizeof(int)); for (j = 1; j <= n; j++) flag[j] = 0; for (i = 1; i <= m; i++) { /* check pattern of row i */ for (ptr = A_ptr[i]; ptr < A_ptr[i+1]; ptr++) { j = A_ind[ptr]; /* check column index */ if (!(1 <= j && j <= n)) { ret = 4; goto done; } /* check for duplication */ if (flag[j]) { ret = 5; goto done; } flag[j] = 1; } /* clear flags */ for (ptr = A_ptr[i]; ptr < A_ptr[i+1]; ptr++) { j = A_ind[ptr]; flag[j] = 0; } } /* the pattern is ok */ ret = 0; done: if (flag != NULL) xfree(flag); return ret; } /*---------------------------------------------------------------------- -- transpose - transpose sparse matrix. -- -- *Synopsis* -- -- #include "glpmat.h" -- void transpose(int m, int n, int A_ptr[], int A_ind[], -- double A_val[], int AT_ptr[], int AT_ind[], double AT_val[]); -- -- *Description* -- -- For a given mxn sparse matrix A the routine transpose builds a nxm -- sparse matrix A' which is a matrix transposed to A. -- -- The arrays A_ptr, A_ind, and A_val specify a given mxn matrix A to -- be transposed in storage-by-rows format. The parameter A_val can be -- NULL, in which case numeric values are not copied. The arrays A_ptr, -- A_ind, and A_val are not changed on exit. -- -- On entry the arrays AT_ptr, AT_ind, and AT_val must be allocated, -- but their content is ignored. On exit the routine stores a resultant -- nxm matrix A' in these arrays in storage-by-rows format. Note that -- if the parameter A_val is NULL, the array AT_val is not used. -- -- The routine transpose has a side effect that elements in rows of the -- resultant matrix A' follow in ascending their column indices. */ void transpose(int m, int n, int A_ptr[], int A_ind[], double A_val[], int AT_ptr[], int AT_ind[], double AT_val[]) { int i, j, t, beg, end, pos, len; /* determine row lengths of resultant matrix */ for (j = 1; j <= n; j++) AT_ptr[j] = 0; for (i = 1; i <= m; i++) { beg = A_ptr[i], end = A_ptr[i+1]; for (t = beg; t < end; t++) AT_ptr[A_ind[t]]++; } /* set up row pointers of resultant matrix */ pos = 1; for (j = 1; j <= n; j++) len = AT_ptr[j], pos += len, AT_ptr[j] = pos; AT_ptr[n+1] = pos; /* build resultant matrix */ for (i = m; i >= 1; i--) { beg = A_ptr[i], end = A_ptr[i+1]; for (t = beg; t < end; t++) { pos = --AT_ptr[A_ind[t]]; AT_ind[pos] = i; if (A_val != NULL) AT_val[pos] = A_val[t]; } } return; } /*---------------------------------------------------------------------- -- adat_symbolic - compute S = P*A*D*A'*P' (symbolic phase). -- -- *Synopsis* -- -- #include "glpmat.h" -- int *adat_symbolic(int m, int n, int P_per[], int A_ptr[], -- int A_ind[], int S_ptr[]); -- -- *Description* -- -- The routine adat_symbolic implements the symbolic phase to compute -- symmetric matrix S = P*A*D*A'*P', where P is a permutation matrix, -- A is a given sparse matrix, D is a diagonal matrix, A' is a matrix -- transposed to A, P' is an inverse of P. -- -- The parameter m is the number of rows in A and the order of P. -- -- The parameter n is the number of columns in A and the order of D. -- -- The array P_per specifies permutation matrix P. It is not changed on -- exit. -- -- The arrays A_ptr and A_ind specify the pattern of matrix A. They are -- not changed on exit. -- -- On exit the routine stores the pattern of upper triangular part of -- matrix S without diagonal elements in the arrays S_ptr and S_ind in -- storage-by-rows format. The array S_ptr should be allocated on entry, -- however, its content is ignored. The array S_ind is allocated by the -- routine itself which returns a pointer to it. -- -- *Returns* -- -- The routine returns a pointer to the array S_ind. */ int *adat_symbolic(int m, int n, int P_per[], int A_ptr[], int A_ind[], int S_ptr[]) { int i, j, t, ii, jj, tt, k, size, len; int *S_ind, *AT_ptr, *AT_ind, *ind, *map, *temp; /* build the pattern of A', which is a matrix transposed to A, to efficiently access A in column-wise manner */ AT_ptr = xcalloc(1+n+1, sizeof(int)); AT_ind = xcalloc(A_ptr[m+1], sizeof(int)); transpose(m, n, A_ptr, A_ind, NULL, AT_ptr, AT_ind, NULL); /* allocate the array S_ind */ size = A_ptr[m+1] - 1; if (size < m) size = m; S_ind = xcalloc(1+size, sizeof(int)); /* allocate and initialize working arrays */ ind = xcalloc(1+m, sizeof(int)); map = xcalloc(1+m, sizeof(int)); for (jj = 1; jj <= m; jj++) map[jj] = 0; /* compute pattern of S; note that symbolically S = B*B', where B = P*A, B' is matrix transposed to B */ S_ptr[1] = 1; for (ii = 1; ii <= m; ii++) { /* compute pattern of ii-th row of S */ len = 0; i = P_per[ii]; /* i-th row of A = ii-th row of B */ for (t = A_ptr[i]; t < A_ptr[i+1]; t++) { k = A_ind[t]; /* walk through k-th column of A */ for (tt = AT_ptr[k]; tt < AT_ptr[k+1]; tt++) { j = AT_ind[tt]; jj = P_per[m+j]; /* j-th row of A = jj-th row of B */ /* a[i,k] != 0 and a[j,k] != 0 ergo s[ii,jj] != 0 */ if (ii < jj && !map[jj]) ind[++len] = jj, map[jj] = 1; } } /* now (ind) is pattern of ii-th row of S */ S_ptr[ii+1] = S_ptr[ii] + len; /* at least (S_ptr[ii+1] - 1) locations should be available in the array S_ind */ if (S_ptr[ii+1] - 1 > size) { temp = S_ind; size += size; S_ind = xcalloc(1+size, sizeof(int)); memcpy(&S_ind[1], &temp[1], (S_ptr[ii] - 1) * sizeof(int)); xfree(temp); } xassert(S_ptr[ii+1] - 1 <= size); /* (ii-th row of S) := (ind) */ memcpy(&S_ind[S_ptr[ii]], &ind[1], len * sizeof(int)); /* clear the row pattern map */ for (t = 1; t <= len; t++) map[ind[t]] = 0; } /* free working arrays */ xfree(AT_ptr); xfree(AT_ind); xfree(ind); xfree(map); /* reallocate the array S_ind to free unused locations */ temp = S_ind; size = S_ptr[m+1] - 1; S_ind = xcalloc(1+size, sizeof(int)); memcpy(&S_ind[1], &temp[1], size * sizeof(int)); xfree(temp); return S_ind; } /*---------------------------------------------------------------------- -- adat_numeric - compute S = P*A*D*A'*P' (numeric phase). -- -- *Synopsis* -- -- #include "glpmat.h" -- void adat_numeric(int m, int n, int P_per[], -- int A_ptr[], int A_ind[], double A_val[], double D_diag[], -- int S_ptr[], int S_ind[], double S_val[], double S_diag[]); -- -- *Description* -- -- The routine adat_numeric implements the numeric phase to compute -- symmetric matrix S = P*A*D*A'*P', where P is a permutation matrix, -- A is a given sparse matrix, D is a diagonal matrix, A' is a matrix -- transposed to A, P' is an inverse of P. -- -- The parameter m is the number of rows in A and the order of P. -- -- The parameter n is the number of columns in A and the order of D. -- -- The matrix P is specified in the array P_per, which is not changed -- on exit. -- -- The matrix A is specified in the arrays A_ptr, A_ind, and A_val in -- storage-by-rows format. These arrays are not changed on exit. -- -- Diagonal elements of the matrix D are specified in the array D_diag, -- where D_diag[0] is not used, D_diag[i] = d[i,i] for i = 1, ..., n. -- The array D_diag is not changed on exit. -- -- The pattern of the upper triangular part of the matrix S without -- diagonal elements (previously computed by the routine adat_symbolic) -- is specified in the arrays S_ptr and S_ind, which are not changed on -- exit. Numeric values of non-diagonal elements of S are stored in -- corresponding locations of the array S_val, and values of diagonal -- elements of S are stored in locations S_diag[1], ..., S_diag[n]. */ void adat_numeric(int m, int n, int P_per[], int A_ptr[], int A_ind[], double A_val[], double D_diag[], int S_ptr[], int S_ind[], double S_val[], double S_diag[]) { int i, j, t, ii, jj, tt, beg, end, beg1, end1, k; double sum, *work; work = xcalloc(1+n, sizeof(double)); for (j = 1; j <= n; j++) work[j] = 0.0; /* compute S = B*D*B', where B = P*A, B' is a matrix transposed to B */ for (ii = 1; ii <= m; ii++) { i = P_per[ii]; /* i-th row of A = ii-th row of B */ /* (work) := (i-th row of A) */ beg = A_ptr[i], end = A_ptr[i+1]; for (t = beg; t < end; t++) work[A_ind[t]] = A_val[t]; /* compute ii-th row of S */ beg = S_ptr[ii], end = S_ptr[ii+1]; for (t = beg; t < end; t++) { jj = S_ind[t]; j = P_per[jj]; /* j-th row of A = jj-th row of B */ /* s[ii,jj] := sum a[i,k] * d[k,k] * a[j,k] */ sum = 0.0; beg1 = A_ptr[j], end1 = A_ptr[j+1]; for (tt = beg1; tt < end1; tt++) { k = A_ind[tt]; sum += work[k] * D_diag[k] * A_val[tt]; } S_val[t] = sum; } /* s[ii,ii] := sum a[i,k] * d[k,k] * a[i,k] */ sum = 0.0; beg = A_ptr[i], end = A_ptr[i+1]; for (t = beg; t < end; t++) { k = A_ind[t]; sum += A_val[t] * D_diag[k] * A_val[t]; work[k] = 0.0; } S_diag[ii] = sum; } xfree(work); return; } /*---------------------------------------------------------------------- -- min_degree - minimum degree ordering. -- -- *Synopsis* -- -- #include "glpmat.h" -- void min_degree(int n, int A_ptr[], int A_ind[], int P_per[]); -- -- *Description* -- -- The routine min_degree uses the minimum degree ordering algorithm -- to find a permutation matrix P for a given sparse symmetric positive -- matrix A which minimizes the number of non-zeros in upper triangular -- factor U for Cholesky factorization P*A*P' = U'*U. -- -- The parameter n is the order of matrices A and P. -- -- The pattern of the given matrix A is specified on entry in the arrays -- A_ptr and A_ind in storage-by-rows format. Only the upper triangular -- part without diagonal elements (which all are assumed to be non-zero) -- should be specified as if A were upper triangular. The arrays A_ptr -- and A_ind are not changed on exit. -- -- The permutation matrix P is stored by the routine in the array P_per -- on exit. -- -- *Algorithm* -- -- The routine min_degree is based on some subroutines from the package -- SPARSPAK (see comments in the module glpqmd). */ void min_degree(int n, int A_ptr[], int A_ind[], int P_per[]) { int i, j, ne, t, pos, len; int *xadj, *adjncy, *deg, *marker, *rchset, *nbrhd, *qsize, *qlink, nofsub; /* determine number of non-zeros in complete pattern */ ne = A_ptr[n+1] - 1; ne += ne; /* allocate working arrays */ xadj = xcalloc(1+n+1, sizeof(int)); adjncy = xcalloc(1+ne, sizeof(int)); deg = xcalloc(1+n, sizeof(int)); marker = xcalloc(1+n, sizeof(int)); rchset = xcalloc(1+n, sizeof(int)); nbrhd = xcalloc(1+n, sizeof(int)); qsize = xcalloc(1+n, sizeof(int)); qlink = xcalloc(1+n, sizeof(int)); /* determine row lengths in complete pattern */ for (i = 1; i <= n; i++) xadj[i] = 0; for (i = 1; i <= n; i++) { for (t = A_ptr[i]; t < A_ptr[i+1]; t++) { j = A_ind[t]; xassert(i < j && j <= n); xadj[i]++, xadj[j]++; } } /* set up row pointers for complete pattern */ pos = 1; for (i = 1; i <= n; i++) len = xadj[i], pos += len, xadj[i] = pos; xadj[n+1] = pos; xassert(pos - 1 == ne); /* construct complete pattern */ for (i = 1; i <= n; i++) { for (t = A_ptr[i]; t < A_ptr[i+1]; t++) { j = A_ind[t]; adjncy[--xadj[i]] = j, adjncy[--xadj[j]] = i; } } /* call the main minimimum degree ordering routine */ genqmd(&n, xadj, adjncy, P_per, P_per + n, deg, marker, rchset, nbrhd, qsize, qlink, &nofsub); /* make sure that permutation matrix P is correct */ for (i = 1; i <= n; i++) { j = P_per[i]; xassert(1 <= j && j <= n); xassert(P_per[n+j] == i); } /* free working arrays */ xfree(xadj); xfree(adjncy); xfree(deg); xfree(marker); xfree(rchset); xfree(nbrhd); xfree(qsize); xfree(qlink); return; } /**********************************************************************/ void amd_order1(int n, int A_ptr[], int A_ind[], int P_per[]) { /* approximate minimum degree ordering (AMD) */ int k, ret; double Control[AMD_CONTROL], Info[AMD_INFO]; /* get the default parameters */ amd_defaults(Control); #if 0 /* and print them */ amd_control(Control); #endif /* make all indices 0-based */ for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]--; for (k = 1; k <= n+1; k++) A_ptr[k]--; /* call the ordering routine */ ret = amd_order(n, &A_ptr[1], &A_ind[1], &P_per[1], Control, Info) ; #if 0 amd_info(Info); #endif xassert(ret == AMD_OK || ret == AMD_OK_BUT_JUMBLED); /* retsore 1-based indices */ for (k = 1; k <= n+1; k++) A_ptr[k]++; for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]++; /* patch up permutation matrix */ memset(&P_per[n+1], 0, n * sizeof(int)); for (k = 1; k <= n; k++) { P_per[k]++; xassert(1 <= P_per[k] && P_per[k] <= n); xassert(P_per[n+P_per[k]] == 0); P_per[n+P_per[k]] = k; } return; } /**********************************************************************/ static void *allocate(size_t n, size_t size) { void *ptr; ptr = xcalloc(n, size); memset(ptr, 0, n * size); return ptr; } static void release(void *ptr) { xfree(ptr); return; } void symamd_ord(int n, int A_ptr[], int A_ind[], int P_per[]) { /* approximate minimum degree ordering (SYMAMD) */ int k, ok; int stats[COLAMD_STATS]; /* make all indices 0-based */ for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]--; for (k = 1; k <= n+1; k++) A_ptr[k]--; /* call the ordering routine */ ok = symamd(n, &A_ind[1], &A_ptr[1], &P_per[1], NULL, stats, allocate, release); #if 0 symamd_report(stats); #endif xassert(ok); /* restore 1-based indices */ for (k = 1; k <= n+1; k++) A_ptr[k]++; for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]++; /* patch up permutation matrix */ memset(&P_per[n+1], 0, n * sizeof(int)); for (k = 1; k <= n; k++) { P_per[k]++; xassert(1 <= P_per[k] && P_per[k] <= n); xassert(P_per[n+P_per[k]] == 0); P_per[n+P_per[k]] = k; } return; } /*---------------------------------------------------------------------- -- chol_symbolic - compute Cholesky factorization (symbolic phase). -- -- *Synopsis* -- -- #include "glpmat.h" -- int *chol_symbolic(int n, int A_ptr[], int A_ind[], int U_ptr[]); -- -- *Description* -- -- The routine chol_symbolic implements the symbolic phase of Cholesky -- factorization A = U'*U, where A is a given sparse symmetric positive -- definite matrix, U is a resultant upper triangular factor, U' is a -- matrix transposed to U. -- -- The parameter n is the order of matrices A and U. -- -- The pattern of the given matrix A is specified on entry in the arrays -- A_ptr and A_ind in storage-by-rows format. Only the upper triangular -- part without diagonal elements (which all are assumed to be non-zero) -- should be specified as if A were upper triangular. The arrays A_ptr -- and A_ind are not changed on exit. -- -- The pattern of the matrix U without diagonal elements (which all are -- assumed to be non-zero) is stored on exit from the routine in the -- arrays U_ptr and U_ind in storage-by-rows format. The array U_ptr -- should be allocated on entry, however, its content is ignored. The -- array U_ind is allocated by the routine which returns a pointer to it -- on exit. -- -- *Returns* -- -- The routine returns a pointer to the array U_ind. -- -- *Method* -- -- The routine chol_symbolic computes the pattern of the matrix U in a -- row-wise manner. No pivoting is used. -- -- It is known that to compute the pattern of row k of the matrix U we -- need to merge the pattern of row k of the matrix A and the patterns -- of each row i of U, where u[i,k] is non-zero (these rows are already -- computed and placed above row k). -- -- However, to reduce the number of rows to be merged the routine uses -- an advanced algorithm proposed in: -- -- D.J.Rose, R.E.Tarjan, and G.S.Lueker. Algorithmic aspects of vertex -- elimination on graphs. SIAM J. Comput. 5, 1976, 266-83. -- -- The authors of the cited paper show that we have the same result if -- we merge row k of the matrix A and such rows of the matrix U (among -- rows 1, ..., k-1) whose leftmost non-diagonal non-zero element is -- placed in k-th column. This feature signficantly reduces the number -- of rows to be merged, especially on the final steps, where rows of -- the matrix U become quite dense. -- -- To determine rows, which should be merged on k-th step, for a fixed -- time the routine uses linked lists of row numbers of the matrix U. -- Location head[k] contains the number of a first row, whose leftmost -- non-diagonal non-zero element is placed in column k, and location -- next[i] contains the number of a next row with the same property as -- row i. */ int *chol_symbolic(int n, int A_ptr[], int A_ind[], int U_ptr[]) { int i, j, k, t, len, size, beg, end, min_j, *U_ind, *head, *next, *ind, *map, *temp; /* initially we assume that on computing the pattern of U fill-in will double the number of non-zeros in A */ size = A_ptr[n+1] - 1; if (size < n) size = n; size += size; U_ind = xcalloc(1+size, sizeof(int)); /* allocate and initialize working arrays */ head = xcalloc(1+n, sizeof(int)); for (i = 1; i <= n; i++) head[i] = 0; next = xcalloc(1+n, sizeof(int)); ind = xcalloc(1+n, sizeof(int)); map = xcalloc(1+n, sizeof(int)); for (j = 1; j <= n; j++) map[j] = 0; /* compute the pattern of matrix U */ U_ptr[1] = 1; for (k = 1; k <= n; k++) { /* compute the pattern of k-th row of U, which is the union of k-th row of A and those rows of U (among 1, ..., k-1) whose leftmost non-diagonal non-zero is placed in k-th column */ /* (ind) := (k-th row of A) */ len = A_ptr[k+1] - A_ptr[k]; memcpy(&ind[1], &A_ind[A_ptr[k]], len * sizeof(int)); for (t = 1; t <= len; t++) { j = ind[t]; xassert(k < j && j <= n); map[j] = 1; } /* walk through rows of U whose leftmost non-diagonal non-zero is placed in k-th column */ for (i = head[k]; i != 0; i = next[i]) { /* (ind) := (ind) union (i-th row of U) */ beg = U_ptr[i], end = U_ptr[i+1]; for (t = beg; t < end; t++) { j = U_ind[t]; if (j > k && !map[j]) ind[++len] = j, map[j] = 1; } } /* now (ind) is the pattern of k-th row of U */ U_ptr[k+1] = U_ptr[k] + len; /* at least (U_ptr[k+1] - 1) locations should be available in the array U_ind */ if (U_ptr[k+1] - 1 > size) { temp = U_ind; size += size; U_ind = xcalloc(1+size, sizeof(int)); memcpy(&U_ind[1], &temp[1], (U_ptr[k] - 1) * sizeof(int)); xfree(temp); } xassert(U_ptr[k+1] - 1 <= size); /* (k-th row of U) := (ind) */ memcpy(&U_ind[U_ptr[k]], &ind[1], len * sizeof(int)); /* determine column index of leftmost non-diagonal non-zero in k-th row of U and clear the row pattern map */ min_j = n + 1; for (t = 1; t <= len; t++) { j = ind[t], map[j] = 0; if (min_j > j) min_j = j; } /* include k-th row into corresponding linked list */ if (min_j <= n) next[k] = head[min_j], head[min_j] = k; } /* free working arrays */ xfree(head); xfree(next); xfree(ind); xfree(map); /* reallocate the array U_ind to free unused locations */ temp = U_ind; size = U_ptr[n+1] - 1; U_ind = xcalloc(1+size, sizeof(int)); memcpy(&U_ind[1], &temp[1], size * sizeof(int)); xfree(temp); return U_ind; } /*---------------------------------------------------------------------- -- chol_numeric - compute Cholesky factorization (numeric phase). -- -- *Synopsis* -- -- #include "glpmat.h" -- int chol_numeric(int n, -- int A_ptr[], int A_ind[], double A_val[], double A_diag[], -- int U_ptr[], int U_ind[], double U_val[], double U_diag[]); -- -- *Description* -- -- The routine chol_symbolic implements the numeric phase of Cholesky -- factorization A = U'*U, where A is a given sparse symmetric positive -- definite matrix, U is a resultant upper triangular factor, U' is a -- matrix transposed to U. -- -- The parameter n is the order of matrices A and U. -- -- Upper triangular part of the matrix A without diagonal elements is -- specified in the arrays A_ptr, A_ind, and A_val in storage-by-rows -- format. Diagonal elements of A are specified in the array A_diag, -- where A_diag[0] is not used, A_diag[i] = a[i,i] for i = 1, ..., n. -- The arrays A_ptr, A_ind, A_val, and A_diag are not changed on exit. -- -- The pattern of the matrix U without diagonal elements (previously -- computed with the routine chol_symbolic) is specified in the arrays -- U_ptr and U_ind, which are not changed on exit. Numeric values of -- non-diagonal elements of U are stored in corresponding locations of -- the array U_val, and values of diagonal elements of U are stored in -- locations U_diag[1], ..., U_diag[n]. -- -- *Returns* -- -- The routine returns the number of non-positive diagonal elements of -- the matrix U which have been replaced by a huge positive number (see -- the method description below). Zero return code means the matrix A -- has been successfully factorized. -- -- *Method* -- -- The routine chol_numeric computes the matrix U in a row-wise manner -- using standard gaussian elimination technique. No pivoting is used. -- -- Initially the routine sets U = A, and before k-th elimination step -- the matrix U is the following: -- -- 1 k n -- 1 x x x x x x x x x x -- . x x x x x x x x x -- . . x x x x x x x x -- . . . x x x x x x x -- k . . . . * * * * * * -- . . . . * * * * * * -- . . . . * * * * * * -- . . . . * * * * * * -- . . . . * * * * * * -- n . . . . * * * * * * -- -- where 'x' are elements of already computed rows, '*' are elements of -- the active submatrix. (Note that the lower triangular part of the -- active submatrix being symmetric is not stored and diagonal elements -- are stored separately in the array U_diag.) -- -- The matrix A is assumed to be positive definite. However, if it is -- close to semi-definite, on some elimination step a pivot u[k,k] may -- happen to be non-positive due to round-off errors. In this case the -- routine uses a technique proposed in: -- -- S.J.Wright. The Cholesky factorization in interior-point and barrier -- methods. Preprint MCS-P600-0596, Mathematics and Computer Science -- Division, Argonne National Laboratory, Argonne, Ill., May 1996. -- -- The routine just replaces non-positive u[k,k] by a huge positive -- number. This involves non-diagonal elements in k-th row of U to be -- close to zero that, in turn, involves k-th component of a solution -- vector to be close to zero. Note, however, that this technique works -- only if the system A*x = b is consistent. */ int chol_numeric(int n, int A_ptr[], int A_ind[], double A_val[], double A_diag[], int U_ptr[], int U_ind[], double U_val[], double U_diag[]) { int i, j, k, t, t1, beg, end, beg1, end1, count = 0; double ukk, uki, *work; work = xcalloc(1+n, sizeof(double)); for (j = 1; j <= n; j++) work[j] = 0.0; /* U := (upper triangle of A) */ /* note that the upper traingle of A is a subset of U */ for (i = 1; i <= n; i++) { beg = A_ptr[i], end = A_ptr[i+1]; for (t = beg; t < end; t++) j = A_ind[t], work[j] = A_val[t]; beg = U_ptr[i], end = U_ptr[i+1]; for (t = beg; t < end; t++) j = U_ind[t], U_val[t] = work[j], work[j] = 0.0; U_diag[i] = A_diag[i]; } /* main elimination loop */ for (k = 1; k <= n; k++) { /* transform k-th row of U */ ukk = U_diag[k]; if (ukk > 0.0) U_diag[k] = ukk = sqrt(ukk); else U_diag[k] = ukk = DBL_MAX, count++; /* (work) := (transformed k-th row) */ beg = U_ptr[k], end = U_ptr[k+1]; for (t = beg; t < end; t++) work[U_ind[t]] = (U_val[t] /= ukk); /* transform other rows of U */ for (t = beg; t < end; t++) { i = U_ind[t]; xassert(i > k); /* (i-th row) := (i-th row) - u[k,i] * (k-th row) */ uki = work[i]; beg1 = U_ptr[i], end1 = U_ptr[i+1]; for (t1 = beg1; t1 < end1; t1++) U_val[t1] -= uki * work[U_ind[t1]]; U_diag[i] -= uki * uki; } /* (work) := 0 */ for (t = beg; t < end; t++) work[U_ind[t]] = 0.0; } xfree(work); return count; } /*---------------------------------------------------------------------- -- u_solve - solve upper triangular system U*x = b. -- -- *Synopsis* -- -- #include "glpmat.h" -- void u_solve(int n, int U_ptr[], int U_ind[], double U_val[], -- double U_diag[], double x[]); -- -- *Description* -- -- The routine u_solve solves an linear system U*x = b, where U is an -- upper triangular matrix. -- -- The parameter n is the order of matrix U. -- -- The matrix U without diagonal elements is specified in the arrays -- U_ptr, U_ind, and U_val in storage-by-rows format. Diagonal elements -- of U are specified in the array U_diag, where U_diag[0] is not used, -- U_diag[i] = u[i,i] for i = 1, ..., n. All these four arrays are not -- changed on exit. -- -- The right-hand side vector b is specified on entry in the array x, -- where x[0] is not used, and x[i] = b[i] for i = 1, ..., n. On exit -- the routine stores computed components of the vector of unknowns x -- in the array x in the same manner. */ void u_solve(int n, int U_ptr[], int U_ind[], double U_val[], double U_diag[], double x[]) { int i, t, beg, end; double temp; for (i = n; i >= 1; i--) { temp = x[i]; beg = U_ptr[i], end = U_ptr[i+1]; for (t = beg; t < end; t++) temp -= U_val[t] * x[U_ind[t]]; xassert(U_diag[i] != 0.0); x[i] = temp / U_diag[i]; } return; } /*---------------------------------------------------------------------- -- ut_solve - solve lower triangular system U'*x = b. -- -- *Synopsis* -- -- #include "glpmat.h" -- void ut_solve(int n, int U_ptr[], int U_ind[], double U_val[], -- double U_diag[], double x[]); -- -- *Description* -- -- The routine ut_solve solves an linear system U'*x = b, where U is a -- matrix transposed to an upper triangular matrix. -- -- The parameter n is the order of matrix U. -- -- The matrix U without diagonal elements is specified in the arrays -- U_ptr, U_ind, and U_val in storage-by-rows format. Diagonal elements -- of U are specified in the array U_diag, where U_diag[0] is not used, -- U_diag[i] = u[i,i] for i = 1, ..., n. All these four arrays are not -- changed on exit. -- -- The right-hand side vector b is specified on entry in the array x, -- where x[0] is not used, and x[i] = b[i] for i = 1, ..., n. On exit -- the routine stores computed components of the vector of unknowns x -- in the array x in the same manner. */ void ut_solve(int n, int U_ptr[], int U_ind[], double U_val[], double U_diag[], double x[]) { int i, t, beg, end; double temp; for (i = 1; i <= n; i++) { xassert(U_diag[i] != 0.0); temp = (x[i] /= U_diag[i]); if (temp == 0.0) continue; beg = U_ptr[i], end = U_ptr[i+1]; for (t = beg; t < end; t++) x[U_ind[t]] -= U_val[t] * temp; } return; } /* eof */ Rglpk/src/GLPK/glpios04.c0000644000176000001440000001665412245352174014533 0ustar ripleyusers/* glpios04.c (operations on sparse vectors) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpios.h" /*********************************************************************** * NAME * * ios_create_vec - create sparse vector * * SYNOPSIS * * #include "glpios.h" * IOSVEC *ios_create_vec(int n); * * DESCRIPTION * * The routine ios_create_vec creates a sparse vector of dimension n, * which initially is a null vector. * * RETURNS * * The routine returns a pointer to the vector created. */ IOSVEC *ios_create_vec(int n) { IOSVEC *v; xassert(n >= 0); v = xmalloc(sizeof(IOSVEC)); v->n = n; v->nnz = 0; v->pos = xcalloc(1+n, sizeof(int)); memset(&v->pos[1], 0, n * sizeof(int)); v->ind = xcalloc(1+n, sizeof(int)); v->val = xcalloc(1+n, sizeof(double)); return v; } /*********************************************************************** * NAME * * ios_check_vec - check that sparse vector has correct representation * * SYNOPSIS * * #include "glpios.h" * void ios_check_vec(IOSVEC *v); * * DESCRIPTION * * The routine ios_check_vec checks that a sparse vector specified by * the parameter v has correct representation. * * NOTE * * Complexity of this operation is O(n). */ void ios_check_vec(IOSVEC *v) { int j, k, nnz; xassert(v->n >= 0); nnz = 0; for (j = v->n; j >= 1; j--) { k = v->pos[j]; xassert(0 <= k && k <= v->nnz); if (k != 0) { xassert(v->ind[k] == j); nnz++; } } xassert(v->nnz == nnz); return; } /*********************************************************************** * NAME * * ios_get_vj - retrieve component of sparse vector * * SYNOPSIS * * #include "glpios.h" * double ios_get_vj(IOSVEC *v, int j); * * RETURNS * * The routine ios_get_vj returns j-th component of a sparse vector * specified by the parameter v. */ double ios_get_vj(IOSVEC *v, int j) { int k; xassert(1 <= j && j <= v->n); k = v->pos[j]; xassert(0 <= k && k <= v->nnz); return (k == 0 ? 0.0 : v->val[k]); } /*********************************************************************** * NAME * * ios_set_vj - set/change component of sparse vector * * SYNOPSIS * * #include "glpios.h" * void ios_set_vj(IOSVEC *v, int j, double val); * * DESCRIPTION * * The routine ios_set_vj assigns val to j-th component of a sparse * vector specified by the parameter v. */ void ios_set_vj(IOSVEC *v, int j, double val) { int k; xassert(1 <= j && j <= v->n); k = v->pos[j]; if (val == 0.0) { if (k != 0) { /* remove j-th component */ v->pos[j] = 0; if (k < v->nnz) { v->pos[v->ind[v->nnz]] = k; v->ind[k] = v->ind[v->nnz]; v->val[k] = v->val[v->nnz]; } v->nnz--; } } else { if (k == 0) { /* create j-th component */ k = ++(v->nnz); v->pos[j] = k; v->ind[k] = j; } v->val[k] = val; } return; } /*********************************************************************** * NAME * * ios_clear_vec - set all components of sparse vector to zero * * SYNOPSIS * * #include "glpios.h" * void ios_clear_vec(IOSVEC *v); * * DESCRIPTION * * The routine ios_clear_vec sets all components of a sparse vector * specified by the parameter v to zero. */ void ios_clear_vec(IOSVEC *v) { int k; for (k = 1; k <= v->nnz; k++) v->pos[v->ind[k]] = 0; v->nnz = 0; return; } /*********************************************************************** * NAME * * ios_clean_vec - remove zero or small components from sparse vector * * SYNOPSIS * * #include "glpios.h" * void ios_clean_vec(IOSVEC *v, double eps); * * DESCRIPTION * * The routine ios_clean_vec removes zero components and components * whose magnitude is less than eps from a sparse vector specified by * the parameter v. If eps is 0.0, only zero components are removed. */ void ios_clean_vec(IOSVEC *v, double eps) { int k, nnz; nnz = 0; for (k = 1; k <= v->nnz; k++) { if (fabs(v->val[k]) == 0.0 || fabs(v->val[k]) < eps) { /* remove component */ v->pos[v->ind[k]] = 0; } else { /* keep component */ nnz++; v->pos[v->ind[k]] = nnz; v->ind[nnz] = v->ind[k]; v->val[nnz] = v->val[k]; } } v->nnz = nnz; return; } /*********************************************************************** * NAME * * ios_copy_vec - copy sparse vector (x := y) * * SYNOPSIS * * #include "glpios.h" * void ios_copy_vec(IOSVEC *x, IOSVEC *y); * * DESCRIPTION * * The routine ios_copy_vec copies a sparse vector specified by the * parameter y to a sparse vector specified by the parameter x. */ void ios_copy_vec(IOSVEC *x, IOSVEC *y) { int j; xassert(x != y); xassert(x->n == y->n); ios_clear_vec(x); x->nnz = y->nnz; memcpy(&x->ind[1], &y->ind[1], x->nnz * sizeof(int)); memcpy(&x->val[1], &y->val[1], x->nnz * sizeof(double)); for (j = 1; j <= x->nnz; j++) x->pos[x->ind[j]] = j; return; } /*********************************************************************** * NAME * * ios_linear_comb - compute linear combination (x := x + a * y) * * SYNOPSIS * * #include "glpios.h" * void ios_linear_comb(IOSVEC *x, double a, IOSVEC *y); * * DESCRIPTION * * The routine ios_linear_comb computes the linear combination * * x := x + a * y, * * where x and y are sparse vectors, a is a scalar. */ void ios_linear_comb(IOSVEC *x, double a, IOSVEC *y) { int j, k; double xj, yj; xassert(x != y); xassert(x->n == y->n); for (k = 1; k <= y->nnz; k++) { j = y->ind[k]; xj = ios_get_vj(x, j); yj = y->val[k]; ios_set_vj(x, j, xj + a * yj); } return; } /*********************************************************************** * NAME * * ios_delete_vec - delete sparse vector * * SYNOPSIS * * #include "glpios.h" * void ios_delete_vec(IOSVEC *v); * * DESCRIPTION * * The routine ios_delete_vec deletes a sparse vector specified by the * parameter v freeing all the memory allocated to this object. */ void ios_delete_vec(IOSVEC *v) { /* delete sparse vector */ xfree(v->pos); xfree(v->ind); xfree(v->val); xfree(v); return; } /* eof */ Rglpk/src/GLPK/glpnet03.c0000644000176000001440000010047012245352174014514 0ustar ripleyusers/* glpnet03.c (Klingman's network problem generator) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * This code is the result of translation of the Fortran program NETGEN * developed by Dr. Darwin Klingman, which is publically available from * NETLIB at . * * The translation was made by Andrew Makhorin . * * 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 . ***********************************************************************/ #include "glpapi.h" /*********************************************************************** * NAME * * glp_netgen - Klingman's network problem generator * * SYNOPSIS * * int glp_netgen(glp_graph *G, int v_rhs, int a_cap, int a_cost, * const int parm[1+15]); * * DESCRIPTION * * The routine glp_netgen is a network problem generator developed by * Dr. Darwin Klingman. It can create capacitated and uncapacitated * minimum cost flow (or transshipment), transportation, and assignment * problems. * * The parameter G specifies the graph object, to which the generated * problem data have to be stored. Note that on entry the graph object * is erased with the routine glp_erase_graph. * * The parameter v_rhs specifies an offset of the field of type double * in the vertex data block, to which the routine stores the supply or * demand value. If v_rhs < 0, the value is not stored. * * The parameter a_cap specifies an offset of the field of type double * in the arc data block, to which the routine stores the arc capacity. * If a_cap < 0, the capacity is not stored. * * The parameter a_cost specifies an offset of the field of type double * in the arc data block, to which the routine stores the per-unit cost * if the arc flow. If a_cost < 0, the cost is not stored. * * The array parm contains description of the network to be generated: * * parm[0] not used * parm[1] (iseed) 8-digit positive random number seed * parm[2] (nprob) 8-digit problem id number * parm[3] (nodes) total number of nodes * parm[4] (nsorc) total number of source nodes (including * transshipment nodes) * parm[5] (nsink) total number of sink nodes (including * transshipment nodes) * parm[6] (iarcs) number of arcs * parm[7] (mincst) minimum cost for arcs * parm[8] (maxcst) maximum cost for arcs * parm[9] (itsup) total supply * parm[10] (ntsorc) number of transshipment source nodes * parm[11] (ntsink) number of transshipment sink nodes * parm[12] (iphic) percentage of skeleton arcs to be given * the maximum cost * parm[13] (ipcap) percentage of arcs to be capacitated * parm[14] (mincap) minimum upper bound for capacitated arcs * parm[15] (maxcap) maximum upper bound for capacitated arcs * * The routine generates a transportation problem if: * * nsorc + nsink = nodes, ntsorc = 0, and ntsink = 0. * * The routine generates an assignment problem if the requirements for * a transportation problem are met and: * * nsorc = nsink and itsup = nsorc. * * RETURNS * * If the instance was successfully generated, the routine glp_netgen * returns zero; otherwise, if specified parameters are inconsistent, * the routine returns a non-zero error code. * * REFERENCES * * D.Klingman, A.Napier, and J.Stutz. NETGEN: A program for generating * large scale capacitated assignment, transportation, and minimum cost * flow networks. Management Science 20 (1974), 814-20. */ struct csa { /* common storage area */ glp_graph *G; int v_rhs, a_cap, a_cost; int nodes, iarcs, mincst, maxcst, itsup, nsorc, nsink, nonsor, nfsink, narcs, nsort, nftsor, ipcap, mincap, maxcap, ktl, nodlft, *ipred, *ihead, *itail, *iflag, *isup, *lsinks, mult, modul, i15, i16, jran; }; #define G (csa->G) #define v_rhs (csa->v_rhs) #define a_cap (csa->a_cap) #define a_cost (csa->a_cost) #define nodes (csa->nodes) #define iarcs (csa->iarcs) #define mincst (csa->mincst) #define maxcst (csa->maxcst) #define itsup (csa->itsup) #define nsorc (csa->nsorc) #define nsink (csa->nsink) #define nonsor (csa->nonsor) #define nfsink (csa->nfsink) #define narcs (csa->narcs) #define nsort (csa->nsort) #define nftsor (csa->nftsor) #define ipcap (csa->ipcap) #define mincap (csa->mincap) #define maxcap (csa->maxcap) #define ktl (csa->ktl) #define nodlft (csa->nodlft) #if 0 /* spent a day to find out this bug */ #define ist (csa->ist) #else #define ist (ipred[0]) #endif #define ipred (csa->ipred) #define ihead (csa->ihead) #define itail (csa->itail) #define iflag (csa->iflag) #define isup (csa->isup) #define lsinks (csa->lsinks) #define mult (csa->mult) #define modul (csa->modul) #define i15 (csa->i15) #define i16 (csa->i16) #define jran (csa->jran) static void cresup(struct csa *csa); static void chain(struct csa *csa, int lpick, int lsorc); static void chnarc(struct csa *csa, int lsorc); static void sort(struct csa *csa); static void pickj(struct csa *csa, int it); static void assign(struct csa *csa); static void setran(struct csa *csa, int iseed); static int iran(struct csa *csa, int ilow, int ihigh); int glp_netgen(glp_graph *G_, int _v_rhs, int _a_cap, int _a_cost, const int parm[1+15]) { struct csa _csa, *csa = &_csa; int iseed, nprob, ntsorc, ntsink, iphic, i, nskel, nltr, ltsink, ntrans, npsink, nftr, npsorc, ntravl, ntrrem, lsorc, lpick, nsksr, nsrchn, j, item, l, ks, k, ksp, li, n, ii, it, ih, icap, jcap, icost, jcost, ret; G = G_; v_rhs = _v_rhs; a_cap = _a_cap; a_cost = _a_cost; if (G != NULL) { if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double)) xerror("glp_netgen: v_rhs = %d; invalid offset\n", v_rhs); if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) xerror("glp_netgen: a_cap = %d; invalid offset\n", a_cap); if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) xerror("glp_netgen: a_cost = %d; invalid offset\n", a_cost); } /* Input the user's random number seed and fix it if non-positive. */ iseed = parm[1]; nprob = parm[2]; if (iseed <= 0) iseed = 13502460; setran(csa, iseed); /* Input the user's problem characteristics. */ nodes = parm[3]; nsorc = parm[4]; nsink = parm[5]; iarcs = parm[6]; mincst = parm[7]; maxcst = parm[8]; itsup = parm[9]; ntsorc = parm[10]; ntsink = parm[11]; iphic = parm[12]; ipcap = parm[13]; mincap = parm[14]; maxcap = parm[15]; /* Check the size of the problem. */ if (!(10 <= nodes && nodes <= 100000)) { ret = 1; goto done; } /* Check user supplied parameters for consistency. */ if (!(nsorc >= 0 && nsink >= 0 && nsorc + nsink <= nodes)) { ret = 2; goto done; } if (iarcs < 0) { ret = 3; goto done; } if (mincst > maxcst) { ret = 4; goto done; } if (itsup < 0) { ret = 5; goto done; } if (!(0 <= ntsorc && ntsorc <= nsorc)) { ret = 6; goto done; } if (!(0 <= ntsink && ntsink <= nsink)) { ret = 7; goto done; } if (!(0 <= iphic && iphic <= 100)) { ret = 8; goto done; } if (!(0 <= ipcap && ipcap <= 100)) { ret = 9; goto done; } if (mincap > maxcap) { ret = 10; goto done; } /* Initailize the graph object. */ if (G != NULL) { glp_erase_graph(G, G->v_size, G->a_size); glp_add_vertices(G, nodes); if (v_rhs >= 0) { double zero = 0.0; for (i = 1; i <= nodes; i++) { glp_vertex *v = G->v[i]; memcpy((char *)v->data + v_rhs, &zero, sizeof(double)); } } } /* Allocate working arrays. */ ipred = xcalloc(1+nodes, sizeof(int)); ihead = xcalloc(1+nodes, sizeof(int)); itail = xcalloc(1+nodes, sizeof(int)); iflag = xcalloc(1+nodes, sizeof(int)); isup = xcalloc(1+nodes, sizeof(int)); lsinks = xcalloc(1+nodes, sizeof(int)); /* Print the problem documentation records. */ if (G == NULL) { xprintf("BEGIN\n"); xprintf("NETGEN PROBLEM%8d%10s%10d NODES AND%10d ARCS\n", nprob, "", nodes, iarcs); xprintf("USER:%11d%11d%11d%11d%11d%11d\nDATA:%11d%11d%11d%11d%" "11d%11d\n", iseed, nsorc, nsink, mincst, maxcst, itsup, ntsorc, ntsink, iphic, ipcap, mincap, maxcap); } else glp_set_graph_name(G, "NETGEN"); /* Set various constants used in the program. */ narcs = 0; nskel = 0; nltr = nodes - nsink; ltsink = nltr + ntsink; ntrans = nltr - nsorc; nfsink = nltr + 1; nonsor = nodes - nsorc + ntsorc; npsink = nsink - ntsink; nodlft = nodes - nsink + ntsink; nftr = nsorc + 1; nftsor = nsorc - ntsorc + 1; npsorc = nsorc - ntsorc; /* Randomly distribute the supply among the source nodes. */ if (npsorc + npsink == nodes && npsorc == npsink && itsup == nsorc) { assign(csa); nskel = nsorc; goto L390; } cresup(csa); /* Print the supply records. */ if (G == NULL) { xprintf("SUPPLY\n"); for (i = 1; i <= nsorc; i++) xprintf("%6s%6d%18s%10d\n", "", i, "", isup[i]); xprintf("ARCS\n"); } else { if (v_rhs >= 0) { for (i = 1; i <= nsorc; i++) { double temp = (double)isup[i]; glp_vertex *v = G->v[i]; memcpy((char *)v->data + v_rhs, &temp, sizeof(double)); } } } /* Make the sources point to themselves in ipred array. */ for (i = 1; i <= nsorc; i++) ipred[i] = i; if (ntrans == 0) goto L170; /* Chain the transshipment nodes together in the ipred array. */ ist = nftr; ipred[nltr] = 0; for (i = nftr; i < nltr; i++) ipred[i] = i+1; /* Form even length chains for 60 percent of the transshipments.*/ ntravl = 6 * ntrans / 10; ntrrem = ntrans - ntravl; L140: lsorc = 1; while (ntravl != 0) { lpick = iran(csa, 1, ntravl + ntrrem); ntravl--; chain(csa, lpick, lsorc); if (lsorc == nsorc) goto L140; lsorc++; } /* Add the remaining transshipments to the chains. */ while (ntrrem != 0) { lpick = iran(csa, 1, ntrrem); ntrrem--; lsorc = iran(csa, 1, nsorc); chain(csa, lpick, lsorc); } L170: /* Set all demands equal to zero. */ for (i = nfsink; i <= nodes; i++) ipred[i] = 0; /* The following loop takes one chain at a time (through the use of logic contained in the loop and calls to other routines) and creates the remaining network arcs. */ for (lsorc = 1; lsorc <= nsorc; lsorc++) { chnarc(csa, lsorc); for (i = nfsink; i <= nodes; i++) iflag[i] = 0; /* Choose the number of sinks to be hooked up to the current chain. */ if (ntrans != 0) nsksr = (nsort * 2 * nsink) / ntrans; else nsksr = nsink / nsorc + 1; if (nsksr < 2) nsksr = 2; if (nsksr > nsink) nsksr = nsink; nsrchn = nsort; /* Randomly pick nsksr sinks and put their names in lsinks. */ ktl = nsink; for (j = 1; j <= nsksr; j++) { item = iran(csa, 1, ktl); ktl--; for (l = nfsink; l <= nodes; l++) { if (iflag[l] != 1) { item--; if (item == 0) goto L230; } } break; L230: lsinks[j] = l; iflag[l] = 1; } /* If last source chain, add all sinks with zero demand to lsinks list. */ if (lsorc == nsorc) { for (j = nfsink; j <= nodes; j++) { if (ipred[j] == 0 && iflag[j] != 1) { nsksr++; lsinks[nsksr] = j; iflag[j] = 1; } } } /* Create demands for group of sinks in lsinks. */ ks = isup[lsorc] / nsksr; k = ipred[lsorc]; for (i = 1; i <= nsksr; i++) { nsort++; ksp = iran(csa, 1, ks); j = iran(csa, 1, nsksr); itail[nsort] = k; li = lsinks[i]; ihead[nsort] = li; ipred[li] += ksp; li = lsinks[j]; ipred[li] += ks - ksp; n = iran(csa, 1, nsrchn); k = lsorc; for (ii = 1; ii <= n; ii++) k = ipred[k]; } li = lsinks[1]; ipred[li] += isup[lsorc] - ks * nsksr; nskel += nsort; /* Sort the arcs in the chain from source lsorc using itail as sort key. */ sort(csa); /* Print this part of skeleton and create the arcs for these nodes. */ i = 1; itail[nsort+1] = 0; L300: for (j = nftsor; j <= nodes; j++) iflag[j] = 0; ktl = nonsor - 1; it = itail[i]; iflag[it] = 1; L320: ih = ihead[i]; iflag[ih] = 1; narcs++; ktl--; /* Determine if this skeleton arc should be capacitated. */ icap = itsup; jcap = iran(csa, 1, 100); if (jcap <= ipcap) { icap = isup[lsorc]; if (mincap > icap) icap = mincap; } /* Determine if this skeleton arc should have the maximum cost. */ icost = maxcst; jcost = iran(csa, 1, 100); if (jcost > iphic) icost = iran(csa, mincst, maxcst); if (G == NULL) xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, ih, "", icost, icap); else { glp_arc *a = glp_add_arc(G, it, ih); if (a_cap >= 0) { double temp = (double)icap; memcpy((char *)a->data + a_cap, &temp, sizeof(double)); } if (a_cost >= 0) { double temp = (double)icost; memcpy((char *)a->data + a_cost, &temp, sizeof(double)); } } i++; if (itail[i] == it) goto L320; pickj(csa, it); if (i <= nsort) goto L300; } /* Create arcs from the transshipment sinks. */ if (ntsink != 0) { for (i = nfsink; i <= ltsink; i++) { for (j = nftsor; j <= nodes; j++) iflag[j] = 0; ktl = nonsor - 1; iflag[i] = 1; pickj(csa, i); } } L390: /* Print the demand records and end record. */ if (G == NULL) { xprintf("DEMAND\n"); for (i = nfsink; i <= nodes; i++) xprintf("%6s%6d%18s%10d\n", "", i, "", ipred[i]); xprintf("END\n"); } else { if (v_rhs >= 0) { for (i = nfsink; i <= nodes; i++) { double temp = - (double)ipred[i]; glp_vertex *v = G->v[i]; memcpy((char *)v->data + v_rhs, &temp, sizeof(double)); } } } /* Free working arrays. */ xfree(ipred); xfree(ihead); xfree(itail); xfree(iflag); xfree(isup); xfree(lsinks); /* The instance has been successfully generated. */ ret = 0; done: return ret; } /*********************************************************************** * The routine cresup randomly distributes the total supply among the * source nodes. */ static void cresup(struct csa *csa) { int i, j, ks, ksp; xassert(itsup > nsorc); ks = itsup / nsorc; for (i = 1; i <= nsorc; i++) isup[i] = 0; for (i = 1; i <= nsorc; i++) { ksp = iran(csa, 1, ks); j = iran(csa, 1, nsorc); isup[i] += ksp; isup[j] += ks - ksp; } j = iran(csa, 1, nsorc); isup[j] += itsup - ks * nsorc; return; } /*********************************************************************** * The routine chain adds node lpick to the end of the chain with source * node lsorc. */ static void chain(struct csa *csa, int lpick, int lsorc) { int i, j, k, l, m; k = 0; m = ist; for (i = 1; i <= lpick; i++) { l = k; k = m; m = ipred[k]; } ipred[l] = m; j = ipred[lsorc]; ipred[k] = j; ipred[lsorc] = k; return; } /*********************************************************************** * The routine chnarc puts the arcs in the chain from source lsorc into * the ihead and itail arrays for sorting. */ static void chnarc(struct csa *csa, int lsorc) { int ito, ifrom; nsort = 0; ito = ipred[lsorc]; L10: if (ito == lsorc) return; nsort++; ifrom = ipred[ito]; ihead[nsort] = ito; itail[nsort] = ifrom; ito = ifrom; goto L10; } /*********************************************************************** * The routine sort sorts the nsort arcs in the ihead and itail arrays. * ihead is used as the sort key (i.e. forward star sort order). */ static void sort(struct csa *csa) { int i, j, k, l, m, n, it; n = nsort; m = n; L10: m /= 2; if (m == 0) return; k = n - m; j = 1; L20: i = j; L30: l = i + m; if (itail[i] <= itail[l]) goto L40; it = itail[i]; itail[i] = itail[l]; itail[l] = it; it = ihead[i]; ihead[i] = ihead[l]; ihead[l] = it; i -= m; if (i >= 1) goto L30; L40: j++; if (j <= k) goto L20; goto L10; } /*********************************************************************** * The routine pickj creates a random number of arcs out of node 'it'. * Various parameters are dynamically adjusted in an attempt to ensure * that the generated network has the correct number of arcs. */ static void pickj(struct csa *csa, int it) { int j, k, l, nn, nupbnd, icap, jcap, icost; if ((nodlft - 1) * 2 > iarcs - narcs - 1) { nodlft--; return; } if ((iarcs - narcs + nonsor - ktl - 1) / nodlft - nonsor + 1 >= 0) k = nonsor; else { nupbnd = (iarcs - narcs - nodlft) / nodlft * 2; L40: k = iran(csa, 1, nupbnd); if (nodlft == 1) k = iarcs - narcs; if ((nodlft - 1) * (nonsor - 1) < iarcs - narcs - k) goto L40; } nodlft--; for (j = 1; j <= k; j++) { nn = iran(csa, 1, ktl); ktl--; for (l = nftsor; l <= nodes; l++) { if (iflag[l] != 1) { nn--; if (nn == 0) goto L70; } } return; L70: iflag[l] = 1; icap = itsup; jcap = iran(csa, 1, 100); if (jcap <= ipcap) icap = iran(csa, mincap, maxcap); icost = iran(csa, mincst, maxcst); if (G == NULL) xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, l, "", icost, icap); else { glp_arc *a = glp_add_arc(G, it, l); if (a_cap >= 0) { double temp = (double)icap; memcpy((char *)a->data + a_cap, &temp, sizeof(double)); } if (a_cost >= 0) { double temp = (double)icost; memcpy((char *)a->data + a_cost, &temp, sizeof(double)); } } narcs++; } return; } /*********************************************************************** * The routine assign generate assignment problems. It defines the unit * supplies, builds a skeleton, then calls pickj to create the arcs. */ static void assign(struct csa *csa) { int i, it, nn, l, ll, icost; if (G == NULL) xprintf("SUPPLY\n"); for (i = 1; i <= nsorc; i++) { isup[i] = 1; iflag[i] = 0; if (G == NULL) xprintf("%6s%6d%18s%10d\n", "", i, "", isup[i]); else { if (v_rhs >= 0) { double temp = (double)isup[i]; glp_vertex *v = G->v[i]; memcpy((char *)v->data + v_rhs, &temp, sizeof(double)); } } } if (G == NULL) xprintf("ARCS\n"); for (i = nfsink; i <= nodes; i++) ipred[i] = 1; for (it = 1; it <= nsorc; it++) { for (i = nfsink; i <= nodes; i++) iflag[i] = 0; ktl = nsink - 1; nn = iran(csa, 1, nsink - it + 1); for (l = 1; l <= nsorc; l++) { if (iflag[l] != 1) { nn--; if (nn == 0) break; } } narcs++; ll = nsorc + l; icost = iran(csa, mincst, maxcst); if (G == NULL) xprintf("%6s%6d%6d%2s%10d%10d\n", "", it, ll, "", icost, isup[1]); else { glp_arc *a = glp_add_arc(G, it, ll); if (a_cap >= 0) { double temp = (double)isup[1]; memcpy((char *)a->data + a_cap, &temp, sizeof(double)); } if (a_cost >= 0) { double temp = (double)icost; memcpy((char *)a->data + a_cost, &temp, sizeof(double)); } } iflag[l] = 1; iflag[ll] = 1; pickj(csa, it); } return; } /*********************************************************************** * Portable congruential (uniform) random number generator: * * next_value = ((7**5) * previous_value) modulo ((2**31)-1) * * This generator consists of three routines: * * (1) setran - initializes constants and seed * (2) iran - generates an integer random number * (3) rran - generates a real random number * * The generator requires a machine with at least 32 bits of precision. * The seed (iseed) must be in the range [1,(2**31)-1]. */ static void setran(struct csa *csa, int iseed) { xassert(iseed >= 1); mult = 16807; modul = 2147483647; i15 = 1 << 15; i16 = 1 << 16; jran = iseed; return; } /*********************************************************************** * The routine iran generates an integer random number between ilow and * ihigh. If ilow > ihigh then iran returns ihigh. */ static int iran(struct csa *csa, int ilow, int ihigh) { int ixhi, ixlo, ixalo, leftlo, ixahi, ifulhi, irtlo, iover, irthi, j; ixhi = jran / i16; ixlo = jran - ixhi * i16; ixalo = ixlo * mult; leftlo = ixalo / i16; ixahi = ixhi * mult; ifulhi = ixahi + leftlo; irtlo = ixalo - leftlo * i16; iover = ifulhi / i15; irthi = ifulhi - iover * i15; jran = ((irtlo - modul) + irthi * i16) + iover; if (jran < 0) jran += modul; j = ihigh - ilow + 1; if (j > 0) return jran % j + ilow; else return ihigh; } /*********************************************************************** * NAME * * glp_netgen_prob - Klingman's standard network problem instance * * SYNOPSIS * * void glp_netgen_prob(int nprob, int parm[1+15]); * * DESCRIPTION * * The routine glp_netgen_prob provides the set of parameters for * Klingman's network problem generator (see the routine glp_netgen), * which describe a standard network problem instance. * * The parameter nprob (101 <= nprob <= 150) specifies the problem * instance number. * * The array parm contains description of the network, provided by the * routine. (For detailed description of these parameters see comments * to the routine glp_netgen.) * * PROBLEM CHARACTERISTICS * * The table below shows characteristics of Klingman's standard network * problem instances. * * Problem Nodes Arcs Optimum * ------- ----- ----- ---------- * 101 5000 25336 6191726 * 102 5000 25387 72337144 * 103 5000 25355 218947553 * 104 5000 25344 -19100371 * 105 5000 25332 31192578 * 106 5000 12870 4314276 * 107 5000 37832 7393769 * 108 5000 50309 8405738 * 109 5000 75299 9190300 * 110 5000 12825 8975048 * 111 5000 37828 4747532 * 112 5000 50325 4012671 * 113 5000 75318 2979725 * 114 5000 26514 5821181 * 115 5000 25962 6353310 * 116 5000 25304 5915426 * 117 5000 12816 4420560 * 118 5000 37797 7045842 * 119 5000 50301 7724179 * 120 5000 75330 8455200 * 121 5000 25000 66366360 * 122 5000 25000 30997529 * 123 5000 25000 23388777 * 124 5000 25000 17803443 * 125 5000 25000 14119622 * 126 5000 12500 18802218 * 127 5000 37500 27674647 * 128 5000 50000 30906194 * 129 5000 75000 40905209 * 130 5000 12500 38939608 * 131 5000 37500 16752978 * 132 5000 50000 13302951 * 133 5000 75000 9830268 * 134 1000 25000 3804874 * 135 2500 25000 11729616 * 136 7500 25000 33318101 * 137 10000 25000 46426030 * 138 5000 25000 60710879 * 139 5000 25000 32729682 * 140 5000 25000 27183831 * 141 5000 25000 19963286 * 142 5000 25000 20243457 * 143 5000 25000 18586777 * 144 5000 25000 2504591 * 145 5000 25000 215956138 * 146 5000 25000 2253113811 * 147 5000 25000 -427908373 * 148 5000 25000 -92965318 * 149 5000 25000 86051224 * 150 5000 25000 619314919 */ static const int data[50][1+15] = { { 0, 13502460, 101, 5000, 2500, 2500, 25000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000 }, { 0, 4281922, 102, 5000, 2500, 2500, 25000, 1, 100, 2500000, 0, 0, 0, 100, 1, 1000 }, { 0, 44820113, 103, 5000, 2500, 2500, 25000, 1, 100, 6250000, 0, 0, 0, 100, 1, 1000 }, { 0, 13450451, 104, 5000, 2500, 2500, 25000, -100, -1, 250000, 0, 0, 0, 100, 1, 1000 }, { 0, 14719436, 105, 5000, 2500, 2500, 25000, 101, 200, 250000, 0, 0, 0, 100, 1, 1000 }, { 0, 17365786, 106, 5000, 2500, 2500, 12500, 1, 100, 125000, 0, 0, 0, 100, 1, 1000 }, { 0, 19540113, 107, 5000, 2500, 2500, 37500, 1, 100, 375000, 0, 0, 0, 100, 1, 1000 }, { 0, 19560313, 108, 5000, 2500, 2500, 50000, 1, 100, 500000, 0, 0, 0, 100, 1, 1000 }, { 0, 2403509, 109, 5000, 2500, 2500, 75000, 1, 100, 750000, 0, 0, 0, 100, 1, 1000 }, { 0, 92480414, 110, 5000, 2500, 2500, 12500, 1, 100, 250000, 0, 0, 0, 100, 1, 1000 }, { 0, 4230140, 111, 5000, 2500, 2500, 37500, 1, 100, 250000, 0, 0, 0, 100, 1, 1000 }, { 0, 10032490, 112, 5000, 2500, 2500, 50000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000 }, { 0, 17307474, 113, 5000, 2500, 2500, 75000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000 }, { 0, 4925114, 114, 5000, 500, 4500, 25000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000 }, { 0, 19842704, 115, 5000, 1500, 3500, 25000, 1, 100, 250000, 0, 0, 0, 100, 1, 1000 }, { 0, 88392060, 116, 5000, 2500, 2500, 25000, 1, 100, 250000, 0, 0, 0, 0, 1, 1000 }, { 0, 12904407, 117, 5000, 2500, 2500, 12500, 1, 100, 125000, 0, 0, 0, 0, 1, 1000 }, { 0, 11811811, 118, 5000, 2500, 2500, 37500, 1, 100, 375000, 0, 0, 0, 0, 1, 1000 }, { 0, 90023593, 119, 5000, 2500, 2500, 50000, 1, 100, 500000, 0, 0, 0, 0, 1, 1000 }, { 0, 93028922, 120, 5000, 2500, 2500, 75000, 1, 100, 750000, 0, 0, 0, 0, 1, 1000 }, { 0, 72707401, 121, 5000, 50, 50, 25000, 1, 100, 250000, 50, 50, 0, 100, 1, 1000 }, { 0, 93040771, 122, 5000, 250, 250, 25000, 1, 100, 250000, 250, 250, 0, 100, 1, 1000 }, { 0, 70220611, 123, 5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000 }, { 0, 52774811, 124, 5000, 1000, 1000, 25000, 1, 100, 250000, 1000, 1000, 0, 100, 1, 1000 }, { 0, 22492311, 125, 5000, 1500, 1500, 25000, 1, 100, 250000, 1500, 1500, 0, 100, 1, 1000 }, { 0, 35269337, 126, 5000, 500, 500, 12500, 1, 100, 125000, 500, 500, 0, 100, 1, 1000 }, { 0, 30140502, 127, 5000, 500, 500, 37500, 1, 100, 375000, 500, 500, 0, 100, 1, 1000 }, { 0, 49205455, 128, 5000, 500, 500, 50000, 1, 100, 500000, 500, 500, 0, 100, 1, 1000 }, { 0, 42958341, 129, 5000, 500, 500, 75000, 1, 100, 750000, 500, 500, 0, 100, 1, 1000 }, { 0, 25440925, 130, 5000, 500, 500, 12500, 1, 100, 250000, 500, 500, 0, 100, 1, 1000 }, { 0, 75294924, 131, 5000, 500, 500, 37500, 1, 100, 250000, 500, 500, 0, 100, 1, 1000 }, { 0, 4463965, 132, 5000, 500, 500, 50000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000 }, { 0, 13390427, 133, 5000, 500, 500, 75000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000 }, { 0, 95250971, 134, 1000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000 }, { 0, 54830522, 135, 2500, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000 }, { 0, 520593, 136, 7500, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000 }, { 0, 52900925, 137, 10000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 1000 }, { 0, 22603395, 138, 5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 50 }, { 0, 55253099, 139, 5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 250 }, { 0, 75357001, 140, 5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 500 }, { 0, 10072459, 141, 5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 2500 }, { 0, 55728492, 142, 5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 100, 1, 5000 }, { 0, 593043, 143, 5000, 500, 500, 25000, 1, 100, 250000, 500, 500, 0, 0, 1, 1000 }, { 0, 94236572, 144, 5000, 500, 500, 25000, 1, 10, 250000, 500, 500, 0, 100, 1, 1000 }, { 0, 94882955, 145, 5000, 500, 500, 25000, 1, 1000, 250000, 500, 500, 0, 100, 1, 1000 }, { 0, 48489922, 146, 5000, 500, 500, 25000, 1, 10000, 250000, 500, 500, 0, 100, 1, 1000 }, { 0, 75578374, 147, 5000, 500, 500, 25000, -100, -1, 250000, 500, 500, 0, 100, 1, 1000 }, { 0, 44821152, 148, 5000, 500, 500, 25000, -50, 49, 250000, 500, 500, 0, 100, 1, 1000 }, { 0, 45224103, 149, 5000, 500, 500, 25000, 101, 200, 250000, 500, 500, 0, 100, 1, 1000 }, { 0, 63491741, 150, 5000, 500, 500, 25000, 1001, 1100, 250000, 500, 500, 0, 100, 1, 1000 }, }; void glp_netgen_prob(int nprob, int parm[1+15]) { int k; if (!(101 <= nprob && nprob <= 150)) xerror("glp_netgen_prob: nprob = %d; invalid problem instance " "number\n", nprob); for (k = 1; k <= 15; k++) parm[k] = data[nprob-101][k]; return; } /**********************************************************************/ #if 0 static int scan(char card[80+1], int pos, int len) { char buf[10+1]; memcpy(buf, &card[pos-1], len); buf[len] = '\0'; return atoi(buf); } int main(void) { int parm[1+15]; char card[80+1]; xassert(fgets(card, sizeof(card), stdin) == card); parm[1] = scan(card, 1, 8); parm[2] = scan(card, 9, 8); xassert(fgets(card, sizeof(card), stdin) == card); parm[3] = scan(card, 1, 5); parm[4] = scan(card, 6, 5); parm[5] = scan(card, 11, 5); parm[6] = scan(card, 16, 5); parm[7] = scan(card, 21, 5); parm[8] = scan(card, 26, 5); parm[9] = scan(card, 31, 10); parm[10] = scan(card, 41, 5); parm[11] = scan(card, 46, 5); parm[12] = scan(card, 51, 5); parm[13] = scan(card, 56, 5); parm[14] = scan(card, 61, 10); parm[15] = scan(card, 71, 10); glp_netgen(NULL, 0, 0, 0, parm); return 0; } #endif /* eof */ Rglpk/src/GLPK/fhvint.c0000644000176000001440000001307312245352174014360 0ustar ripleyusers/* fhvint.c (interface to FHV-factorization) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #include "fhvint.h" FHVINT *fhvint_create(void) { /* create interface to FHV-factorization */ FHVINT *fi; fi = talloc(1, FHVINT); fi->valid = 0; fi->fhv = NULL; fi->lufint = NULL; fi->nfs_max = 0; return fi; } int fhvint_factorize(FHVINT *fi, int n, int (*col)(void *info, int j, int ind[], double val[]), void *info) { /* compute FHV-factorization of specified matrix A */ FHV *fhv; LUFINT *lufint; int nfs_max, old_n_max, n_max, k, ret; xassert(n > 0); fi->valid = 0; /* get required value of nfs_max */ nfs_max = fi->nfs_max; if (nfs_max == 0) nfs_max = 100; xassert(nfs_max > 0); /* create interface to LU-factorization, if necessary */ lufint = fi->lufint; if (lufint == NULL) { lufint = fi->lufint = lufint_create(); lufint->sva_n_max = 4 * n + nfs_max; lufint->sva_size = 10 * n; lufint->delta_n0 = 0; lufint->delta_n = 100; lufint->sgf_updat = 1; } /* compute LU-factorization of specified matrix A */ old_n_max = lufint->n_max; ret = lufint_factorize(lufint, n, col, info); n_max = lufint->n_max; /* create FHV-factorization, if necessary */ fhv = fi->fhv; if (fhv == NULL) { fhv = fi->fhv = talloc(1, FHV); fhv->luf = lufint->luf; fhv->nfs_max = 0; fhv->hh_ind = NULL; fhv->p0_ind = NULL; fhv->p0_inv = NULL; } /* allocate/reallocate FHV-factorization, if necessary */ if (fhv->nfs_max != nfs_max) { fhv->nfs_max = nfs_max; if (fhv->hh_ind != NULL) tfree(fhv->hh_ind); fhv->hh_ind = talloc(1+nfs_max, int); } if (old_n_max < n_max) { if (fhv->p0_ind != NULL) tfree(fhv->p0_ind); if (fhv->p0_inv != NULL) tfree(fhv->p0_inv); fhv->p0_ind = talloc(1+n_max, int); fhv->p0_inv = talloc(1+n_max, int); } /* H := I */ fhv->nfs = 0; fhv->hh_ref = sva_alloc_vecs(fi->lufint->sva, nfs_max); /* P0 := P */ for (k = 1; k <= n; k++) { fhv->p0_ind[k] = fi->lufint->luf->pp_ind[k]; fhv->p0_inv[k] = fi->lufint->luf->pp_inv[k]; } /* set validation flag */ if (ret == 0) fi->valid = 1; return ret; } int fhvint_update(FHVINT *fi, int j, int len, const int ind[], const double val[]) { /* update FHV-factorization after replacing j-th column of A */ SGF *sgf = fi->lufint->sgf; int *ind1 = sgf->rs_next; double *val1 = sgf->vr_max; double *work = sgf->work; int ret; xassert(fi->valid); ret = fhv_ft_update(fi->fhv, j, len, ind, val, ind1, val1, work); if (ret != 0) fi->valid = 0; return ret; } void fhvint_ftran(FHVINT *fi, double x[]) { /* solve system A * x = b */ FHV *fhv = fi->fhv; LUF *luf = fhv->luf; int n = luf->n; int *pp_ind = luf->pp_ind; int *pp_inv = luf->pp_inv; SGF *sgf = fi->lufint->sgf; double *work = sgf->work; xassert(fi->valid); /* A = F * H * V */ /* x = inv(A) * b = inv(V) * inv(H) * inv(F) * b */ luf->pp_ind = fhv->p0_ind; luf->pp_inv = fhv->p0_inv; luf_f_solve(luf, x); luf->pp_ind = pp_ind; luf->pp_inv = pp_inv; fhv_h_solve(fhv, x); luf_v_solve(luf, x, work); memcpy(&x[1], &work[1], n * sizeof(double)); return; } void fhvint_btran(FHVINT *fi, double x[]) { /* solve system A'* x = b */ FHV *fhv = fi->fhv; LUF *luf = fhv->luf; int n = luf->n; int *pp_ind = luf->pp_ind; int *pp_inv = luf->pp_inv; SGF *sgf = fi->lufint->sgf; double *work = sgf->work; xassert(fi->valid); /* A' = (F * H * V)' = V'* H'* F' */ /* x = inv(A') * b = inv(F') * inv(H') * inv(V') * b */ luf_vt_solve(luf, x, work); fhv_ht_solve(fhv, work); luf->pp_ind = fhv->p0_ind; luf->pp_inv = fhv->p0_inv; luf_ft_solve(luf, work); luf->pp_ind = pp_ind; luf->pp_inv = pp_inv; memcpy(&x[1], &work[1], n * sizeof(double)); return; } void fhvint_delete(FHVINT *fi) { /* delete interface to FHV-factorization */ FHV *fhv = fi->fhv; LUFINT *lufint = fi->lufint; if (fhv != NULL) { tfree(fhv->hh_ind); tfree(fhv->p0_ind); tfree(fhv->p0_inv); tfree(fhv); } if (lufint != NULL) lufint_delete(fi->lufint); tfree(fi); return; } /* eof */ Rglpk/src/GLPK/glpnet05.c0000644000176000001440000002600212245352174014514 0ustar ripleyusers/* glpnet05.c (Goldfarb's maximum flow problem generator) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * This code is a modified version of the program RMFGEN, a maxflow * problem generator developed by D.Goldfarb and M.Grigoriadis, and * originally implemented by Tamas Badics . * The original code is publically available on the DIMACS ftp site at: * . * * All changes concern only the program interface, so this modified * version produces exactly the same instances as the original version. * * Changes were made by Andrew Makhorin . * * 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 . ***********************************************************************/ #include "glpapi.h" #include "rng.h" /*********************************************************************** * NAME * * glp_rmfgen - Goldfarb's maximum flow problem generator * * SYNOPSIS * * int glp_rmfgen(glp_graph *G, int *s, int *t, int a_cap, * const int parm[1+5]); * * DESCRIPTION * * The routine glp_rmfgen is a maximum flow problem generator developed * by D.Goldfarb and M.Grigoriadis. * * The parameter G specifies the graph object, to which the generated * problem data have to be stored. Note that on entry the graph object * is erased with the routine glp_erase_graph. * * The pointer s specifies a location, to which the routine stores the * source node number. If s is NULL, the node number is not stored. * * The pointer t specifies a location, to which the routine stores the * sink node number. If t is NULL, the node number is not stored. * * The parameter a_cap specifies an offset of the field of type double * in the arc data block, to which the routine stores the arc capacity. * If a_cap < 0, the capacity is not stored. * * The array parm contains description of the network to be generated: * * parm[0] not used * parm[1] (seed) random number seed (a positive integer) * parm[2] (a) frame size * parm[3] (b) depth * parm[4] (c1) minimal arc capacity * parm[5] (c2) maximal arc capacity * * RETURNS * * If the instance was successfully generated, the routine glp_netgen * returns zero; otherwise, if specified parameters are inconsistent, * the routine returns a non-zero error code. * * COMMENTS * * The generated network is as follows. It has b pieces of frames of * size a * a. (So alltogether the number of vertices is a * a * b) * * In each frame all the vertices are connected with their neighbours * (forth and back). In addition the vertices of a frame are connected * one to one with the vertices of next frame using a random permutation * of those vertices. * * The source is the lower left vertex of the first frame, the sink is * the upper right vertex of the b'th frame. * * t * +-------+ * | .| * | . | * / | / | * +-------+/ -+ b * | | |/. * a | -v- |/ * | | |/ * +-------+ 1 * s a * * The capacities are randomly chosen integers from the range of [c1,c2] * in the case of interconnecting edges, and c2 * a * a for the in-frame * edges. * * REFERENCES * * D.Goldfarb and M.D.Grigoriadis, "A computational comparison of the * Dinic and network simplex methods for maximum flow." Annals of Op. * Res. 13 (1988), pp. 83-123. * * U.Derigs and W.Meier, "Implementing Goldberg's max-flow algorithm: * A computational investigation." Zeitschrift fuer Operations Research * 33 (1989), pp. 383-403. */ typedef struct VERTEX { struct EDGE **edgelist; /* Pointer to the list of pointers to the adjacent edges. (No matter that to or from edges) */ struct EDGE **current; /* Pointer to the current edge */ int degree; /* Number of adjacent edges (both direction) */ int index; } vertex; typedef struct EDGE { int from; int to; int cap; /* Capacity */ } edge; typedef struct NETWORK { struct NETWORK *next, *prev; int vertnum; int edgenum; vertex *verts; /* Vertex array[1..vertnum] */ edge *edges; /* Edge array[1..edgenum] */ int source; /* Pointer to the source */ int sink; /* Pointer to the sink */ } network; struct csa { /* common storage area */ glp_graph *G; int *s, *t, a_cap; RNG *rand; network *N; int *Parr; int A, AA, C2AA, Ec; }; #define G (csa->G) #define s (csa->s) #define t (csa->t) #define a_cap (csa->a_cap) #define N (csa->N) #define Parr (csa->Parr) #define A (csa->A) #define AA (csa->AA) #define C2AA (csa->C2AA) #define Ec (csa->Ec) #undef random #define random(A) (int)(rng_unif_01(csa->rand) * (double)(A)) #define RANDOM(A, B) (int)(random((B) - (A) + 1) + (A)) #define sgn(A) (((A) > 0) ? 1 : ((A) == 0) ? 0 : -1) static void make_edge(struct csa *csa, int from, int to, int c1, int c2) { Ec++; N->edges[Ec].from = from; N->edges[Ec].to = to; N->edges[Ec].cap = RANDOM(c1, c2); return; } static void permute(struct csa *csa) { int i, j, tmp; for (i = 1; i < AA; i++) { j = RANDOM(i, AA); tmp = Parr[i]; Parr[i] = Parr[j]; Parr[j] = tmp; } return; } static void connect(struct csa *csa, int offset, int cv, int x1, int y1) { int cv1; cv1 = offset + (x1 - 1) * A + y1; Ec++; N->edges[Ec].from = cv; N->edges[Ec].to = cv1; N->edges[Ec].cap = C2AA; return; } static network *gen_rmf(struct csa *csa, int a, int b, int c1, int c2) { /* generates a network with a*a*b nodes and 6a*a*b-4ab-2a*a edges random_frame network: Derigs & Meier, Methods & Models of OR (1989), 33:383-403 */ int x, y, z, offset, cv; A = a; AA = a * a; C2AA = c2 * AA; Ec = 0; N = (network *)xmalloc(sizeof(network)); N->vertnum = AA * b; N->edgenum = 5 * AA * b - 4 * A * b - AA; N->edges = (edge *)xcalloc(N->edgenum + 1, sizeof(edge)); N->source = 1; N->sink = N->vertnum; Parr = (int *)xcalloc(AA + 1, sizeof(int)); for (x = 1; x <= AA; x++) Parr[x] = x; for (z = 1; z <= b; z++) { offset = AA * (z - 1); if (z != b) permute(csa); for (x = 1; x <= A; x++) { for (y = 1; y <= A; y++) { cv = offset + (x - 1) * A + y; if (z != b) make_edge(csa, cv, offset + AA + Parr[cv - offset], c1, c2); /* the intermediate edges */ if (y < A) connect(csa, offset, cv, x, y + 1); if (y > 1) connect(csa, offset, cv, x, y - 1); if (x < A) connect(csa, offset, cv, x + 1, y); if (x > 1) connect(csa, offset, cv, x - 1, y); } } } xfree(Parr); return N; } static void print_max_format(struct csa *csa, network *n, char *comm[], int dim) { /* prints a network heading with dim lines of comments (no \n needs at the ends) */ int i, vnum, e_num; edge *e; vnum = n->vertnum; e_num = n->edgenum; if (G == NULL) { for (i = 0; i < dim; i++) xprintf("c %s\n", comm[i]); xprintf("p max %7d %10d\n", vnum, e_num); xprintf("n %7d s\n", n->source); xprintf("n %7d t\n", n->sink); } else { glp_add_vertices(G, vnum); if (s != NULL) *s = n->source; if (t != NULL) *t = n->sink; } for (i = 1; i <= e_num; i++) { e = &n->edges[i]; if (G == NULL) xprintf("a %7d %7d %10d\n", e->from, e->to, (int)e->cap); else { glp_arc *a = glp_add_arc(G, e->from, e->to); if (a_cap >= 0) { double temp = (double)e->cap; memcpy((char *)a->data + a_cap, &temp, sizeof(double)); } } } return; } static void gen_free_net(network *n) { xfree(n->edges); xfree(n); return; } int glp_rmfgen(glp_graph *G_, int *_s, int *_t, int _a_cap, const int parm[1+5]) { struct csa _csa, *csa = &_csa; network *n; char comm[10][80], *com1[10]; int seed, a, b, c1, c2, ret; G = G_; s = _s; t = _t; a_cap = _a_cap; if (G != NULL) { if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) xerror("glp_rmfgen: a_cap = %d; invalid offset\n", a_cap); } seed = parm[1]; a = parm[2]; b = parm[3]; c1 = parm[4]; c2 = parm[5]; if (!(seed > 0 && 1 <= a && a <= 1000 && 1 <= b && b <= 1000 && 0 <= c1 && c1 <= c2 && c2 <= 1000)) { ret = 1; goto done; } if (G != NULL) { glp_erase_graph(G, G->v_size, G->a_size); glp_set_graph_name(G, "RMFGEN"); } csa->rand = rng_create_rand(); rng_init_rand(csa->rand, seed); n = gen_rmf(csa, a, b, c1, c2); sprintf(comm[0], "This file was generated by genrmf."); sprintf(comm[1], "The parameters are: a: %d b: %d c1: %d c2: %d", a, b, c1, c2); com1[0] = comm[0]; com1[1] = comm[1]; print_max_format(csa, n, com1, 2); gen_free_net(n); rng_delete_rand(csa->rand); ret = 0; done: return ret; } /**********************************************************************/ #if 0 int main(int argc, char *argv[]) { int seed, a, b, c1, c2, i, parm[1+5]; seed = 123; a = b = c1 = c2 = -1; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-seed") == 0) seed = atoi(argv[++i]); else if (strcmp(argv[i], "-a") == 0) a = atoi(argv[++i]); else if (strcmp(argv[i], "-b") == 0) b = atoi(argv[++i]); else if (strcmp(argv[i], "-c1") == 0) c1 = atoi(argv[++i]); else if (strcmp(argv[i], "-c2") == 0) c2 = atoi(argv[++i]); } if (a < 0 || b < 0 || c1 < 0 || c2 < 0) { xprintf("Usage:\n"); xprintf("genrmf [-seed seed] -a frame_size -b depth\n"); xprintf(" -c1 cap_range1 -c2 cap_range2\n"); } else { parm[1] = seed; parm[2] = a; parm[3] = b; parm[4] = c1; parm[5] = c2; glp_rmfgen(NULL, NULL, NULL, 0, parm); } return 0; } #endif /* eof */ Rglpk/src/GLPK/glpios01.c0000644000176000001440000014621212245352174014522 0ustar ripleyusers/* glpios01.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpios.h" #include "glplib.h" /*********************************************************************** * NAME * * ios_create_tree - create branch-and-bound tree * * SYNOPSIS * * #include "glpios.h" * glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm); * * DESCRIPTION * * The routine ios_create_tree creates the branch-and-bound tree. * * Being created the tree consists of the only root subproblem whose * reference number is 1. Note that initially the root subproblem is in * frozen state and therefore needs to be revived. * * RETURNS * * The routine returns a pointer to the tree created. */ static IOSNPD *new_node(glp_tree *tree, IOSNPD *parent); glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm) { int m = mip->m; int n = mip->n; glp_tree *tree; int i, j; xassert(mip->tree == NULL); mip->tree = tree = xmalloc(sizeof(glp_tree)); tree->pool = dmp_create_pool(); tree->n = n; /* save original problem components */ tree->orig_m = m; tree->orig_type = xcalloc(1+m+n, sizeof(char)); tree->orig_lb = xcalloc(1+m+n, sizeof(double)); tree->orig_ub = xcalloc(1+m+n, sizeof(double)); tree->orig_stat = xcalloc(1+m+n, sizeof(char)); tree->orig_prim = xcalloc(1+m+n, sizeof(double)); tree->orig_dual = xcalloc(1+m+n, sizeof(double)); for (i = 1; i <= m; i++) { GLPROW *row = mip->row[i]; tree->orig_type[i] = (char)row->type; tree->orig_lb[i] = row->lb; tree->orig_ub[i] = row->ub; tree->orig_stat[i] = (char)row->stat; tree->orig_prim[i] = row->prim; tree->orig_dual[i] = row->dual; } for (j = 1; j <= n; j++) { GLPCOL *col = mip->col[j]; tree->orig_type[m+j] = (char)col->type; tree->orig_lb[m+j] = col->lb; tree->orig_ub[m+j] = col->ub; tree->orig_stat[m+j] = (char)col->stat; tree->orig_prim[m+j] = col->prim; tree->orig_dual[m+j] = col->dual; } tree->orig_obj = mip->obj_val; /* initialize the branch-and-bound tree */ tree->nslots = 0; tree->avail = 0; tree->slot = NULL; tree->head = tree->tail = NULL; tree->a_cnt = tree->n_cnt = tree->t_cnt = 0; /* the root subproblem is not solved yet, so its final components are unknown so far */ tree->root_m = 0; tree->root_type = NULL; tree->root_lb = tree->root_ub = NULL; tree->root_stat = NULL; /* the current subproblem does not exist yet */ tree->curr = NULL; tree->mip = mip; /*tree->solved = 0;*/ tree->non_int = xcalloc(1+n, sizeof(char)); memset(&tree->non_int[1], 0, n); /* arrays to save parent subproblem components will be allocated later */ tree->pred_m = tree->pred_max = 0; tree->pred_type = NULL; tree->pred_lb = tree->pred_ub = NULL; tree->pred_stat = NULL; /* cut generator */ tree->local = ios_create_pool(tree); /*tree->first_attempt = 1;*/ /*tree->max_added_cuts = 0;*/ /*tree->min_eff = 0.0;*/ /*tree->miss = 0;*/ /*tree->just_selected = 0;*/ tree->mir_gen = NULL; tree->clq_gen = NULL; /*tree->round = 0;*/ #if 0 /* create the conflict graph */ tree->n_ref = xcalloc(1+n, sizeof(int)); memset(&tree->n_ref[1], 0, n * sizeof(int)); tree->c_ref = xcalloc(1+n, sizeof(int)); memset(&tree->c_ref[1], 0, n * sizeof(int)); tree->g = scg_create_graph(0); tree->j_ref = xcalloc(1+tree->g->n_max, sizeof(int)); #endif /* pseudocost branching */ tree->pcost = NULL; tree->iwrk = xcalloc(1+n, sizeof(int)); tree->dwrk = xcalloc(1+n, sizeof(double)); /* initialize control parameters */ tree->parm = parm; tree->tm_beg = xtime(); #if 0 /* 10/VI-2013 */ tree->tm_lag = xlset(0); #else tree->tm_lag = 0.0; #endif tree->sol_cnt = 0; #if 1 /* 11/VII-2013 */ tree->P = NULL; tree->npp = NULL; tree->save_sol = parm->save_sol; tree->save_cnt = 0; #endif /* initialize advanced solver interface */ tree->reason = 0; tree->reopt = 0; tree->reinv = 0; tree->br_var = 0; tree->br_sel = 0; tree->child = 0; tree->next_p = 0; /*tree->btrack = NULL;*/ tree->stop = 0; /* create the root subproblem, which initially is identical to the original MIP */ new_node(tree, NULL); return tree; } /*********************************************************************** * NAME * * ios_revive_node - revive specified subproblem * * SYNOPSIS * * #include "glpios.h" * void ios_revive_node(glp_tree *tree, int p); * * DESCRIPTION * * The routine ios_revive_node revives the specified subproblem, whose * reference number is p, and thereby makes it the current subproblem. * Note that the specified subproblem must be active. Besides, if the * current subproblem already exists, it must be frozen before reviving * another subproblem. */ void ios_revive_node(glp_tree *tree, int p) { glp_prob *mip = tree->mip; IOSNPD *node, *root; /* obtain pointer to the specified subproblem */ xassert(1 <= p && p <= tree->nslots); node = tree->slot[p].node; xassert(node != NULL); /* the specified subproblem must be active */ xassert(node->count == 0); /* the current subproblem must not exist */ xassert(tree->curr == NULL); /* the specified subproblem becomes current */ tree->curr = node; /*tree->solved = 0;*/ /* obtain pointer to the root subproblem */ root = tree->slot[1].node; xassert(root != NULL); /* at this point problem object components correspond to the root subproblem, so if the root subproblem should be revived, there is nothing more to do */ if (node == root) goto done; xassert(mip->m == tree->root_m); /* build path from the root to the current node */ node->temp = NULL; for (node = node; node != NULL; node = node->up) { if (node->up == NULL) xassert(node == root); else node->up->temp = node; } /* go down from the root to the current node and make necessary changes to restore components of the current subproblem */ for (node = root; node != NULL; node = node->temp) { int m = mip->m; int n = mip->n; /* if the current node is reached, the problem object at this point corresponds to its parent, so save attributes of rows and columns for the parent subproblem */ if (node->temp == NULL) { int i, j; tree->pred_m = m; /* allocate/reallocate arrays, if necessary */ if (tree->pred_max < m + n) { int new_size = m + n + 100; if (tree->pred_type != NULL) xfree(tree->pred_type); if (tree->pred_lb != NULL) xfree(tree->pred_lb); if (tree->pred_ub != NULL) xfree(tree->pred_ub); if (tree->pred_stat != NULL) xfree(tree->pred_stat); tree->pred_max = new_size; tree->pred_type = xcalloc(1+new_size, sizeof(char)); tree->pred_lb = xcalloc(1+new_size, sizeof(double)); tree->pred_ub = xcalloc(1+new_size, sizeof(double)); tree->pred_stat = xcalloc(1+new_size, sizeof(char)); } /* save row attributes */ for (i = 1; i <= m; i++) { GLPROW *row = mip->row[i]; tree->pred_type[i] = (char)row->type; tree->pred_lb[i] = row->lb; tree->pred_ub[i] = row->ub; tree->pred_stat[i] = (char)row->stat; } /* save column attributes */ for (j = 1; j <= n; j++) { GLPCOL *col = mip->col[j]; tree->pred_type[mip->m+j] = (char)col->type; tree->pred_lb[mip->m+j] = col->lb; tree->pred_ub[mip->m+j] = col->ub; tree->pred_stat[mip->m+j] = (char)col->stat; } } /* change bounds of rows and columns */ { IOSBND *b; for (b = node->b_ptr; b != NULL; b = b->next) { if (b->k <= m) glp_set_row_bnds(mip, b->k, b->type, b->lb, b->ub); else glp_set_col_bnds(mip, b->k-m, b->type, b->lb, b->ub); } } /* change statuses of rows and columns */ { IOSTAT *s; for (s = node->s_ptr; s != NULL; s = s->next) { if (s->k <= m) glp_set_row_stat(mip, s->k, s->stat); else glp_set_col_stat(mip, s->k-m, s->stat); } } /* add new rows */ if (node->r_ptr != NULL) { IOSROW *r; IOSAIJ *a; int i, len, *ind; double *val; ind = xcalloc(1+n, sizeof(int)); val = xcalloc(1+n, sizeof(double)); for (r = node->r_ptr; r != NULL; r = r->next) { i = glp_add_rows(mip, 1); glp_set_row_name(mip, i, r->name); #if 1 /* 20/IX-2008 */ xassert(mip->row[i]->level == 0); mip->row[i]->level = node->level; mip->row[i]->origin = r->origin; mip->row[i]->klass = r->klass; #endif glp_set_row_bnds(mip, i, r->type, r->lb, r->ub); len = 0; for (a = r->ptr; a != NULL; a = a->next) len++, ind[len] = a->j, val[len] = a->val; glp_set_mat_row(mip, i, len, ind, val); glp_set_rii(mip, i, r->rii); glp_set_row_stat(mip, i, r->stat); } xfree(ind); xfree(val); } #if 0 /* add new edges to the conflict graph */ /* add new cliques to the conflict graph */ /* (not implemented yet) */ xassert(node->own_nn == 0); xassert(node->own_nc == 0); xassert(node->e_ptr == NULL); #endif } /* the specified subproblem has been revived */ node = tree->curr; /* delete its bound change list */ while (node->b_ptr != NULL) { IOSBND *b; b = node->b_ptr; node->b_ptr = b->next; dmp_free_atom(tree->pool, b, sizeof(IOSBND)); } /* delete its status change list */ while (node->s_ptr != NULL) { IOSTAT *s; s = node->s_ptr; node->s_ptr = s->next; dmp_free_atom(tree->pool, s, sizeof(IOSTAT)); } #if 1 /* 20/XI-2009 */ /* delete its row addition list (additional rows may appear, for example, due to branching on GUB constraints */ while (node->r_ptr != NULL) { IOSROW *r; r = node->r_ptr; node->r_ptr = r->next; xassert(r->name == NULL); while (r->ptr != NULL) { IOSAIJ *a; a = r->ptr; r->ptr = a->next; dmp_free_atom(tree->pool, a, sizeof(IOSAIJ)); } dmp_free_atom(tree->pool, r, sizeof(IOSROW)); } #endif done: return; } /*********************************************************************** * NAME * * ios_freeze_node - freeze current subproblem * * SYNOPSIS * * #include "glpios.h" * void ios_freeze_node(glp_tree *tree); * * DESCRIPTION * * The routine ios_freeze_node freezes the current subproblem. */ void ios_freeze_node(glp_tree *tree) { glp_prob *mip = tree->mip; int m = mip->m; int n = mip->n; IOSNPD *node; /* obtain pointer to the current subproblem */ node = tree->curr; xassert(node != NULL); if (node->up == NULL) { /* freeze the root subproblem */ int k; xassert(node->p == 1); xassert(tree->root_m == 0); xassert(tree->root_type == NULL); xassert(tree->root_lb == NULL); xassert(tree->root_ub == NULL); xassert(tree->root_stat == NULL); tree->root_m = m; tree->root_type = xcalloc(1+m+n, sizeof(char)); tree->root_lb = xcalloc(1+m+n, sizeof(double)); tree->root_ub = xcalloc(1+m+n, sizeof(double)); tree->root_stat = xcalloc(1+m+n, sizeof(char)); for (k = 1; k <= m+n; k++) { if (k <= m) { GLPROW *row = mip->row[k]; tree->root_type[k] = (char)row->type; tree->root_lb[k] = row->lb; tree->root_ub[k] = row->ub; tree->root_stat[k] = (char)row->stat; } else { GLPCOL *col = mip->col[k-m]; tree->root_type[k] = (char)col->type; tree->root_lb[k] = col->lb; tree->root_ub[k] = col->ub; tree->root_stat[k] = (char)col->stat; } } } else { /* freeze non-root subproblem */ int root_m = tree->root_m; int pred_m = tree->pred_m; int i, j, k; xassert(pred_m <= m); /* build change lists for rows and columns which exist in the parent subproblem */ xassert(node->b_ptr == NULL); xassert(node->s_ptr == NULL); for (k = 1; k <= pred_m + n; k++) { int pred_type, pred_stat, type, stat; double pred_lb, pred_ub, lb, ub; /* determine attributes in the parent subproblem */ pred_type = tree->pred_type[k]; pred_lb = tree->pred_lb[k]; pred_ub = tree->pred_ub[k]; pred_stat = tree->pred_stat[k]; /* determine attributes in the current subproblem */ if (k <= pred_m) { GLPROW *row = mip->row[k]; type = row->type; lb = row->lb; ub = row->ub; stat = row->stat; } else { GLPCOL *col = mip->col[k - pred_m]; type = col->type; lb = col->lb; ub = col->ub; stat = col->stat; } /* save type and bounds of a row/column, if changed */ if (!(pred_type == type && pred_lb == lb && pred_ub == ub)) { IOSBND *b; b = dmp_get_atom(tree->pool, sizeof(IOSBND)); b->k = k; b->type = (unsigned char)type; b->lb = lb; b->ub = ub; b->next = node->b_ptr; node->b_ptr = b; } /* save status of a row/column, if changed */ if (pred_stat != stat) { IOSTAT *s; s = dmp_get_atom(tree->pool, sizeof(IOSTAT)); s->k = k; s->stat = (unsigned char)stat; s->next = node->s_ptr; node->s_ptr = s; } } /* save new rows added to the current subproblem */ xassert(node->r_ptr == NULL); if (pred_m < m) { int i, len, *ind; double *val; ind = xcalloc(1+n, sizeof(int)); val = xcalloc(1+n, sizeof(double)); for (i = m; i > pred_m; i--) { GLPROW *row = mip->row[i]; IOSROW *r; const char *name; r = dmp_get_atom(tree->pool, sizeof(IOSROW)); name = glp_get_row_name(mip, i); if (name == NULL) r->name = NULL; else { r->name = dmp_get_atom(tree->pool, strlen(name)+1); strcpy(r->name, name); } #if 1 /* 20/IX-2008 */ r->origin = row->origin; r->klass = row->klass; #endif r->type = (unsigned char)row->type; r->lb = row->lb; r->ub = row->ub; r->ptr = NULL; len = glp_get_mat_row(mip, i, ind, val); for (k = 1; k <= len; k++) { IOSAIJ *a; a = dmp_get_atom(tree->pool, sizeof(IOSAIJ)); a->j = ind[k]; a->val = val[k]; a->next = r->ptr; r->ptr = a; } r->rii = row->rii; r->stat = (unsigned char)row->stat; r->next = node->r_ptr; node->r_ptr = r; } xfree(ind); xfree(val); } /* remove all rows missing in the root subproblem */ if (m != root_m) { int nrs, *num; nrs = m - root_m; xassert(nrs > 0); num = xcalloc(1+nrs, sizeof(int)); for (i = 1; i <= nrs; i++) num[i] = root_m + i; glp_del_rows(mip, nrs, num); xfree(num); } m = mip->m; /* and restore attributes of all rows and columns for the root subproblem */ xassert(m == root_m); for (i = 1; i <= m; i++) { glp_set_row_bnds(mip, i, tree->root_type[i], tree->root_lb[i], tree->root_ub[i]); glp_set_row_stat(mip, i, tree->root_stat[i]); } for (j = 1; j <= n; j++) { glp_set_col_bnds(mip, j, tree->root_type[m+j], tree->root_lb[m+j], tree->root_ub[m+j]); glp_set_col_stat(mip, j, tree->root_stat[m+j]); } #if 1 /* remove all edges and cliques missing in the conflict graph for the root subproblem */ /* (not implemented yet) */ #endif } /* the current subproblem has been frozen */ tree->curr = NULL; return; } /*********************************************************************** * NAME * * ios_clone_node - clone specified subproblem * * SYNOPSIS * * #include "glpios.h" * void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[]); * * DESCRIPTION * * The routine ios_clone_node clones the specified subproblem, whose * reference number is p, creating its nnn exact copies. Note that the * specified subproblem must be active and must be in the frozen state * (i.e. it must not be the current subproblem). * * Each clone, an exact copy of the specified subproblem, becomes a new * active subproblem added to the end of the active list. After cloning * the specified subproblem becomes inactive. * * The reference numbers of clone subproblems are stored to locations * ref[1], ..., ref[nnn]. */ static int get_slot(glp_tree *tree) { int p; /* if no free slots are available, increase the room */ if (tree->avail == 0) { int nslots = tree->nslots; IOSLOT *save = tree->slot; if (nslots == 0) tree->nslots = 20; else { tree->nslots = nslots + nslots; xassert(tree->nslots > nslots); } tree->slot = xcalloc(1+tree->nslots, sizeof(IOSLOT)); if (save != NULL) { memcpy(&tree->slot[1], &save[1], nslots * sizeof(IOSLOT)); xfree(save); } /* push more free slots into the stack */ for (p = tree->nslots; p > nslots; p--) { tree->slot[p].node = NULL; tree->slot[p].next = tree->avail; tree->avail = p; } } /* pull a free slot from the stack */ p = tree->avail; tree->avail = tree->slot[p].next; xassert(tree->slot[p].node == NULL); tree->slot[p].next = 0; return p; } static IOSNPD *new_node(glp_tree *tree, IOSNPD *parent) { IOSNPD *node; int p; /* pull a free slot for the new node */ p = get_slot(tree); /* create descriptor of the new subproblem */ node = dmp_get_atom(tree->pool, sizeof(IOSNPD)); tree->slot[p].node = node; node->p = p; node->up = parent; node->level = (parent == NULL ? 0 : parent->level + 1); node->count = 0; node->b_ptr = NULL; node->s_ptr = NULL; node->r_ptr = NULL; node->solved = 0; #if 0 node->own_nn = node->own_nc = 0; node->e_ptr = NULL; #endif #if 1 /* 04/X-2008 */ node->lp_obj = (parent == NULL ? (tree->mip->dir == GLP_MIN ? -DBL_MAX : +DBL_MAX) : parent->lp_obj); #endif node->bound = (parent == NULL ? (tree->mip->dir == GLP_MIN ? -DBL_MAX : +DBL_MAX) : parent->bound); node->br_var = 0; node->br_val = 0.0; node->ii_cnt = 0; node->ii_sum = 0.0; #if 1 /* 30/XI-2009 */ node->changed = 0; #endif if (tree->parm->cb_size == 0) node->data = NULL; else { node->data = dmp_get_atom(tree->pool, tree->parm->cb_size); memset(node->data, 0, tree->parm->cb_size); } node->temp = NULL; node->prev = tree->tail; node->next = NULL; /* add the new subproblem to the end of the active list */ if (tree->head == NULL) tree->head = node; else tree->tail->next = node; tree->tail = node; tree->a_cnt++; tree->n_cnt++; tree->t_cnt++; /* increase the number of child subproblems */ if (parent == NULL) xassert(p == 1); else parent->count++; return node; } void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[]) { IOSNPD *node; int k; /* obtain pointer to the subproblem to be cloned */ xassert(1 <= p && p <= tree->nslots); node = tree->slot[p].node; xassert(node != NULL); /* the specified subproblem must be active */ xassert(node->count == 0); /* and must be in the frozen state */ xassert(tree->curr != node); /* remove the specified subproblem from the active list, because it becomes inactive */ if (node->prev == NULL) tree->head = node->next; else node->prev->next = node->next; if (node->next == NULL) tree->tail = node->prev; else node->next->prev = node->prev; node->prev = node->next = NULL; tree->a_cnt--; /* create clone subproblems */ xassert(nnn > 0); for (k = 1; k <= nnn; k++) ref[k] = new_node(tree, node)->p; return; } /*********************************************************************** * NAME * * ios_delete_node - delete specified subproblem * * SYNOPSIS * * #include "glpios.h" * void ios_delete_node(glp_tree *tree, int p); * * DESCRIPTION * * The routine ios_delete_node deletes the specified subproblem, whose * reference number is p. The subproblem must be active and must be in * the frozen state (i.e. it must not be the current subproblem). * * Note that deletion is performed recursively, i.e. if a subproblem to * be deleted is the only child of its parent, the parent subproblem is * also deleted, etc. */ void ios_delete_node(glp_tree *tree, int p) { IOSNPD *node, *temp; /* obtain pointer to the subproblem to be deleted */ xassert(1 <= p && p <= tree->nslots); node = tree->slot[p].node; xassert(node != NULL); /* the specified subproblem must be active */ xassert(node->count == 0); /* and must be in the frozen state */ xassert(tree->curr != node); /* remove the specified subproblem from the active list, because it is gone from the tree */ if (node->prev == NULL) tree->head = node->next; else node->prev->next = node->next; if (node->next == NULL) tree->tail = node->prev; else node->next->prev = node->prev; node->prev = node->next = NULL; tree->a_cnt--; loop: /* recursive deletion starts here */ /* delete the bound change list */ { IOSBND *b; while (node->b_ptr != NULL) { b = node->b_ptr; node->b_ptr = b->next; dmp_free_atom(tree->pool, b, sizeof(IOSBND)); } } /* delete the status change list */ { IOSTAT *s; while (node->s_ptr != NULL) { s = node->s_ptr; node->s_ptr = s->next; dmp_free_atom(tree->pool, s, sizeof(IOSTAT)); } } /* delete the row addition list */ while (node->r_ptr != NULL) { IOSROW *r; r = node->r_ptr; if (r->name != NULL) dmp_free_atom(tree->pool, r->name, strlen(r->name)+1); while (r->ptr != NULL) { IOSAIJ *a; a = r->ptr; r->ptr = a->next; dmp_free_atom(tree->pool, a, sizeof(IOSAIJ)); } node->r_ptr = r->next; dmp_free_atom(tree->pool, r, sizeof(IOSROW)); } #if 0 /* delete the edge addition list */ /* delete the clique addition list */ /* (not implemented yet) */ xassert(node->own_nn == 0); xassert(node->own_nc == 0); xassert(node->e_ptr == NULL); #endif /* free application-specific data */ if (tree->parm->cb_size == 0) xassert(node->data == NULL); else dmp_free_atom(tree->pool, node->data, tree->parm->cb_size); /* free the corresponding node slot */ p = node->p; xassert(tree->slot[p].node == node); tree->slot[p].node = NULL; tree->slot[p].next = tree->avail; tree->avail = p; /* save pointer to the parent subproblem */ temp = node->up; /* delete the subproblem descriptor */ dmp_free_atom(tree->pool, node, sizeof(IOSNPD)); tree->n_cnt--; /* take pointer to the parent subproblem */ node = temp; if (node != NULL) { /* the parent subproblem exists; decrease the number of its child subproblems */ xassert(node->count > 0); node->count--; /* if now the parent subproblem has no childs, it also must be deleted */ if (node->count == 0) goto loop; } return; } /*********************************************************************** * NAME * * ios_delete_tree - delete branch-and-bound tree * * SYNOPSIS * * #include "glpios.h" * void ios_delete_tree(glp_tree *tree); * * DESCRIPTION * * The routine ios_delete_tree deletes the branch-and-bound tree, which * the parameter tree points to, and frees all the memory allocated to * this program object. * * On exit components of the problem object are restored to correspond * to the original MIP passed to the routine ios_create_tree. */ void ios_delete_tree(glp_tree *tree) { glp_prob *mip = tree->mip; int i, j; int m = mip->m; int n = mip->n; xassert(mip->tree == tree); /* remove all additional rows */ if (m != tree->orig_m) { int nrs, *num; nrs = m - tree->orig_m; xassert(nrs > 0); num = xcalloc(1+nrs, sizeof(int)); for (i = 1; i <= nrs; i++) num[i] = tree->orig_m + i; glp_del_rows(mip, nrs, num); xfree(num); } m = tree->orig_m; /* restore original attributes of rows and columns */ xassert(m == tree->orig_m); xassert(n == tree->n); for (i = 1; i <= m; i++) { glp_set_row_bnds(mip, i, tree->orig_type[i], tree->orig_lb[i], tree->orig_ub[i]); glp_set_row_stat(mip, i, tree->orig_stat[i]); mip->row[i]->prim = tree->orig_prim[i]; mip->row[i]->dual = tree->orig_dual[i]; } for (j = 1; j <= n; j++) { glp_set_col_bnds(mip, j, tree->orig_type[m+j], tree->orig_lb[m+j], tree->orig_ub[m+j]); glp_set_col_stat(mip, j, tree->orig_stat[m+j]); mip->col[j]->prim = tree->orig_prim[m+j]; mip->col[j]->dual = tree->orig_dual[m+j]; } mip->pbs_stat = mip->dbs_stat = GLP_FEAS; mip->obj_val = tree->orig_obj; /* delete the branch-and-bound tree */ xassert(tree->local != NULL); ios_delete_pool(tree, tree->local); dmp_delete_pool(tree->pool); xfree(tree->orig_type); xfree(tree->orig_lb); xfree(tree->orig_ub); xfree(tree->orig_stat); xfree(tree->orig_prim); xfree(tree->orig_dual); xfree(tree->slot); if (tree->root_type != NULL) xfree(tree->root_type); if (tree->root_lb != NULL) xfree(tree->root_lb); if (tree->root_ub != NULL) xfree(tree->root_ub); if (tree->root_stat != NULL) xfree(tree->root_stat); xfree(tree->non_int); #if 0 xfree(tree->n_ref); xfree(tree->c_ref); xfree(tree->j_ref); #endif if (tree->pcost != NULL) ios_pcost_free(tree); xfree(tree->iwrk); xfree(tree->dwrk); #if 0 scg_delete_graph(tree->g); #endif if (tree->pred_type != NULL) xfree(tree->pred_type); if (tree->pred_lb != NULL) xfree(tree->pred_lb); if (tree->pred_ub != NULL) xfree(tree->pred_ub); if (tree->pred_stat != NULL) xfree(tree->pred_stat); #if 0 xassert(tree->cut_gen == NULL); #endif xassert(tree->mir_gen == NULL); xassert(tree->clq_gen == NULL); xfree(tree); mip->tree = NULL; return; } /*********************************************************************** * NAME * * ios_eval_degrad - estimate obj. degrad. for down- and up-branches * * SYNOPSIS * * #include "glpios.h" * void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up); * * DESCRIPTION * * Given optimal basis to LP relaxation of the current subproblem the * routine ios_eval_degrad performs the dual ratio test to compute the * objective values in the adjacent basis for down- and up-branches, * which are stored in locations *dn and *up, assuming that x[j] is a * variable chosen to branch upon. */ void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up) { glp_prob *mip = tree->mip; int m = mip->m, n = mip->n; int len, kase, k, t, stat; double alfa, beta, gamma, delta, dz; int *ind = tree->iwrk; double *val = tree->dwrk; /* current basis must be optimal */ xassert(glp_get_status(mip) == GLP_OPT); /* basis factorization must exist */ xassert(glp_bf_exists(mip)); /* obtain (fractional) value of x[j] in optimal basic solution to LP relaxation of the current subproblem */ xassert(1 <= j && j <= n); beta = mip->col[j]->prim; /* since the value of x[j] is fractional, it is basic; compute corresponding row of the simplex table */ len = lpx_eval_tab_row(mip, m+j, ind, val); /* kase < 0 means down-branch; kase > 0 means up-branch */ for (kase = -1; kase <= +1; kase += 2) { /* for down-branch we introduce new upper bound floor(beta) for x[j]; similarly, for up-branch we introduce new lower bound ceil(beta) for x[j]; in the current basis this new upper/lower bound is violated, so in the adjacent basis x[j] will leave the basis and go to its new upper/lower bound; we need to know which non-basic variable x[k] should enter the basis to keep dual feasibility */ #if 0 /* 23/XI-2009 */ k = lpx_dual_ratio_test(mip, len, ind, val, kase, 1e-7); #else k = lpx_dual_ratio_test(mip, len, ind, val, kase, 1e-9); #endif /* if no variable has been chosen, current basis being primal infeasible due to the new upper/lower bound of x[j] is dual unbounded, therefore, LP relaxation to corresponding branch has no primal feasible solution */ if (k == 0) { if (mip->dir == GLP_MIN) { if (kase < 0) *dn = +DBL_MAX; else *up = +DBL_MAX; } else if (mip->dir == GLP_MAX) { if (kase < 0) *dn = -DBL_MAX; else *up = -DBL_MAX; } else xassert(mip != mip); continue; } xassert(1 <= k && k <= m+n); /* row of the simplex table corresponding to specified basic variable x[j] is the following: x[j] = ... + alfa * x[k] + ... ; we need to know influence coefficient, alfa, at non-basic variable x[k] chosen with the dual ratio test */ for (t = 1; t <= len; t++) if (ind[t] == k) break; xassert(1 <= t && t <= len); alfa = val[t]; /* determine status and reduced cost of variable x[k] */ if (k <= m) { stat = mip->row[k]->stat; gamma = mip->row[k]->dual; } else { stat = mip->col[k-m]->stat; gamma = mip->col[k-m]->dual; } /* x[k] cannot be basic or fixed non-basic */ xassert(stat == GLP_NL || stat == GLP_NU || stat == GLP_NF); /* if the current basis is dual degenerative, some reduced costs, which are close to zero, may have wrong sign due to round-off errors, so correct the sign of gamma */ if (mip->dir == GLP_MIN) { if (stat == GLP_NL && gamma < 0.0 || stat == GLP_NU && gamma > 0.0 || stat == GLP_NF) gamma = 0.0; } else if (mip->dir == GLP_MAX) { if (stat == GLP_NL && gamma > 0.0 || stat == GLP_NU && gamma < 0.0 || stat == GLP_NF) gamma = 0.0; } else xassert(mip != mip); /* determine the change of x[j] in the adjacent basis: delta x[j] = new x[j] - old x[j] */ delta = (kase < 0 ? floor(beta) : ceil(beta)) - beta; /* compute the change of x[k] in the adjacent basis: delta x[k] = new x[k] - old x[k] = delta x[j] / alfa */ delta /= alfa; /* compute the change of the objective in the adjacent basis: delta z = new z - old z = gamma * delta x[k] */ dz = gamma * delta; if (mip->dir == GLP_MIN) xassert(dz >= 0.0); else if (mip->dir == GLP_MAX) xassert(dz <= 0.0); else xassert(mip != mip); /* compute the new objective value in the adjacent basis: new z = old z + delta z */ if (kase < 0) *dn = mip->obj_val + dz; else *up = mip->obj_val + dz; } /*xprintf("obj = %g; dn = %g; up = %g\n", mip->obj_val, *dn, *up);*/ return; } /*********************************************************************** * NAME * * ios_round_bound - improve local bound by rounding * * SYNOPSIS * * #include "glpios.h" * double ios_round_bound(glp_tree *tree, double bound); * * RETURNS * * For the given local bound for any integer feasible solution to the * current subproblem the routine ios_round_bound returns an improved * local bound for the same integer feasible solution. * * BACKGROUND * * Let the current subproblem has the following objective function: * * z = sum c[j] * x[j] + s >= b, (1) * j in J * * where J = {j: c[j] is non-zero and integer, x[j] is integer}, s is * the sum of terms corresponding to fixed variables, b is an initial * local bound (minimization). * * From (1) it follows that: * * d * sum (c[j] / d) * x[j] + s >= b, (2) * j in J * * or, equivalently, * * sum (c[j] / d) * x[j] >= (b - s) / d = h, (3) * j in J * * where d = gcd(c[j]). Since the left-hand side of (3) is integer, * h = (b - s) / d can be rounded up to the nearest integer: * * h' = ceil(h) = (b' - s) / d, (4) * * that gives an rounded, improved local bound: * * b' = d * h' + s. (5) * * In case of maximization '>=' in (1) should be replaced by '<=' that * leads to the following formula: * * h' = floor(h) = (b' - s) / d, (6) * * which should used in the same way as (4). * * NOTE: If b is a valid local bound for a child of the current * subproblem, b' is also valid for that child subproblem. */ double ios_round_bound(glp_tree *tree, double bound) { glp_prob *mip = tree->mip; int n = mip->n; int d, j, nn, *c = tree->iwrk; double s, h; /* determine c[j] and compute s */ nn = 0, s = mip->c0, d = 0; for (j = 1; j <= n; j++) { GLPCOL *col = mip->col[j]; if (col->coef == 0.0) continue; if (col->type == GLP_FX) { /* fixed variable */ s += col->coef * col->prim; } else { /* non-fixed variable */ if (col->kind != GLP_IV) goto skip; if (col->coef != floor(col->coef)) goto skip; if (fabs(col->coef) <= (double)INT_MAX) c[++nn] = (int)fabs(col->coef); else d = 1; } } /* compute d = gcd(c[1],...c[nn]) */ if (d == 0) { if (nn == 0) goto skip; d = gcdn(nn, c); } xassert(d > 0); /* compute new local bound */ if (mip->dir == GLP_MIN) { if (bound != +DBL_MAX) { h = (bound - s) / (double)d; if (h >= floor(h) + 0.001) { /* round up */ h = ceil(h); /*xprintf("d = %d; old = %g; ", d, bound);*/ bound = (double)d * h + s; /*xprintf("new = %g\n", bound);*/ } } } else if (mip->dir == GLP_MAX) { if (bound != -DBL_MAX) { h = (bound - s) / (double)d; if (h <= ceil(h) - 0.001) { /* round down */ h = floor(h); bound = (double)d * h + s; } } } else xassert(mip != mip); skip: return bound; } /*********************************************************************** * NAME * * ios_is_hopeful - check if subproblem is hopeful * * SYNOPSIS * * #include "glpios.h" * int ios_is_hopeful(glp_tree *tree, double bound); * * DESCRIPTION * * Given the local bound of a subproblem the routine ios_is_hopeful * checks if the subproblem can have an integer optimal solution which * is better than the best one currently known. * * RETURNS * * If the subproblem can have a better integer optimal solution, the * routine returns non-zero; otherwise, if the corresponding branch can * be pruned, the routine returns zero. */ int ios_is_hopeful(glp_tree *tree, double bound) { glp_prob *mip = tree->mip; int ret = 1; double eps; if (mip->mip_stat == GLP_FEAS) { eps = tree->parm->tol_obj * (1.0 + fabs(mip->mip_obj)); switch (mip->dir) { case GLP_MIN: if (bound >= mip->mip_obj - eps) ret = 0; break; case GLP_MAX: if (bound <= mip->mip_obj + eps) ret = 0; break; default: xassert(mip != mip); } } else { switch (mip->dir) { case GLP_MIN: if (bound == +DBL_MAX) ret = 0; break; case GLP_MAX: if (bound == -DBL_MAX) ret = 0; break; default: xassert(mip != mip); } } return ret; } /*********************************************************************** * NAME * * ios_best_node - find active node with best local bound * * SYNOPSIS * * #include "glpios.h" * int ios_best_node(glp_tree *tree); * * DESCRIPTION * * The routine ios_best_node finds an active node whose local bound is * best among other active nodes. * * It is understood that the integer optimal solution of the original * mip problem cannot be better than the best bound, so the best bound * is an lower (minimization) or upper (maximization) global bound for * the original problem. * * RETURNS * * The routine ios_best_node returns the subproblem reference number * for the best node. However, if the tree is empty, it returns zero. */ int ios_best_node(glp_tree *tree) { IOSNPD *node, *best = NULL; switch (tree->mip->dir) { case GLP_MIN: /* minimization */ for (node = tree->head; node != NULL; node = node->next) if (best == NULL || best->bound > node->bound) best = node; break; case GLP_MAX: /* maximization */ for (node = tree->head; node != NULL; node = node->next) if (best == NULL || best->bound < node->bound) best = node; break; default: xassert(tree != tree); } return best == NULL ? 0 : best->p; } /*********************************************************************** * NAME * * ios_relative_gap - compute relative mip gap * * SYNOPSIS * * #include "glpios.h" * double ios_relative_gap(glp_tree *tree); * * DESCRIPTION * * The routine ios_relative_gap computes the relative mip gap using the * formula: * * gap = |best_mip - best_bnd| / (|best_mip| + DBL_EPSILON), * * where best_mip is the best integer feasible solution found so far, * best_bnd is the best (global) bound. If no integer feasible solution * has been found yet, rel_gap is set to DBL_MAX. * * RETURNS * * The routine ios_relative_gap returns the relative mip gap. */ double ios_relative_gap(glp_tree *tree) { glp_prob *mip = tree->mip; int p; double best_mip, best_bnd, gap; if (mip->mip_stat == GLP_FEAS) { best_mip = mip->mip_obj; p = ios_best_node(tree); if (p == 0) { /* the tree is empty */ gap = 0.0; } else { best_bnd = tree->slot[p].node->bound; gap = fabs(best_mip - best_bnd) / (fabs(best_mip) + DBL_EPSILON); } } else { /* no integer feasible solution has been found yet */ gap = DBL_MAX; } return gap; } /*********************************************************************** * NAME * * ios_solve_node - solve LP relaxation of current subproblem * * SYNOPSIS * * #include "glpios.h" * int ios_solve_node(glp_tree *tree); * * DESCRIPTION * * The routine ios_solve_node re-optimizes LP relaxation of the current * subproblem using the dual simplex method. * * RETURNS * * The routine returns the code which is reported by glp_simplex. */ int ios_solve_node(glp_tree *tree) { glp_prob *mip = tree->mip; glp_smcp parm; int ret; /* the current subproblem must exist */ xassert(tree->curr != NULL); /* set some control parameters */ glp_init_smcp(&parm); switch (tree->parm->msg_lev) { case GLP_MSG_OFF: parm.msg_lev = GLP_MSG_OFF; break; case GLP_MSG_ERR: parm.msg_lev = GLP_MSG_ERR; break; case GLP_MSG_ON: case GLP_MSG_ALL: parm.msg_lev = GLP_MSG_ON; break; case GLP_MSG_DBG: parm.msg_lev = GLP_MSG_ALL; break; default: xassert(tree != tree); } parm.meth = GLP_DUALP; if (tree->parm->msg_lev < GLP_MSG_DBG) parm.out_dly = tree->parm->out_dly; else parm.out_dly = 0; /* if the incumbent objective value is already known, use it to prematurely terminate the dual simplex search */ if (mip->mip_stat == GLP_FEAS) { switch (tree->mip->dir) { case GLP_MIN: parm.obj_ul = mip->mip_obj; break; case GLP_MAX: parm.obj_ll = mip->mip_obj; break; default: xassert(mip != mip); } } /* try to solve/re-optimize the LP relaxation */ ret = glp_simplex(mip, &parm); tree->curr->solved++; #if 0 xprintf("ret = %d; status = %d; pbs = %d; dbs = %d; some = %d\n", ret, glp_get_status(mip), mip->pbs_stat, mip->dbs_stat, mip->some); lpx_print_sol(mip, "sol"); #endif return ret; } /**********************************************************************/ IOSPOOL *ios_create_pool(glp_tree *tree) { /* create cut pool */ IOSPOOL *pool; #if 0 pool = dmp_get_atom(tree->pool, sizeof(IOSPOOL)); #else xassert(tree == tree); pool = xmalloc(sizeof(IOSPOOL)); #endif pool->size = 0; pool->head = pool->tail = NULL; pool->ord = 0, pool->curr = NULL; return pool; } int ios_add_row(glp_tree *tree, IOSPOOL *pool, const char *name, int klass, int flags, int len, const int ind[], const double val[], int type, double rhs) { /* add row (constraint) to the cut pool */ IOSCUT *cut; IOSAIJ *aij; int k; xassert(pool != NULL); cut = dmp_get_atom(tree->pool, sizeof(IOSCUT)); if (name == NULL || name[0] == '\0') cut->name = NULL; else { for (k = 0; name[k] != '\0'; k++) { if (k == 256) xerror("glp_ios_add_row: cut name too long\n"); if (iscntrl((unsigned char)name[k])) xerror("glp_ios_add_row: cut name contains invalid chara" "cter(s)\n"); } cut->name = dmp_get_atom(tree->pool, strlen(name)+1); strcpy(cut->name, name); } if (!(0 <= klass && klass <= 255)) xerror("glp_ios_add_row: klass = %d; invalid cut class\n", klass); cut->klass = (unsigned char)klass; if (flags != 0) xerror("glp_ios_add_row: flags = %d; invalid cut flags\n", flags); cut->ptr = NULL; if (!(0 <= len && len <= tree->n)) xerror("glp_ios_add_row: len = %d; invalid cut length\n", len); for (k = 1; k <= len; k++) { aij = dmp_get_atom(tree->pool, sizeof(IOSAIJ)); if (!(1 <= ind[k] && ind[k] <= tree->n)) xerror("glp_ios_add_row: ind[%d] = %d; column index out of " "range\n", k, ind[k]); aij->j = ind[k]; aij->val = val[k]; aij->next = cut->ptr; cut->ptr = aij; } if (!(type == GLP_LO || type == GLP_UP || type == GLP_FX)) xerror("glp_ios_add_row: type = %d; invalid cut type\n", type); cut->type = (unsigned char)type; cut->rhs = rhs; cut->prev = pool->tail; cut->next = NULL; if (cut->prev == NULL) pool->head = cut; else cut->prev->next = cut; pool->tail = cut; pool->size++; return pool->size; } IOSCUT *ios_find_row(IOSPOOL *pool, int i) { /* find row (constraint) in the cut pool */ /* (smart linear search) */ xassert(pool != NULL); xassert(1 <= i && i <= pool->size); if (pool->ord == 0) { xassert(pool->curr == NULL); pool->ord = 1; pool->curr = pool->head; } xassert(pool->curr != NULL); if (i < pool->ord) { if (i < pool->ord - i) { pool->ord = 1; pool->curr = pool->head; while (pool->ord != i) { pool->ord++; xassert(pool->curr != NULL); pool->curr = pool->curr->next; } } else { while (pool->ord != i) { pool->ord--; xassert(pool->curr != NULL); pool->curr = pool->curr->prev; } } } else if (i > pool->ord) { if (i - pool->ord < pool->size - i) { while (pool->ord != i) { pool->ord++; xassert(pool->curr != NULL); pool->curr = pool->curr->next; } } else { pool->ord = pool->size; pool->curr = pool->tail; while (pool->ord != i) { pool->ord--; xassert(pool->curr != NULL); pool->curr = pool->curr->prev; } } } xassert(pool->ord == i); xassert(pool->curr != NULL); return pool->curr; } void ios_del_row(glp_tree *tree, IOSPOOL *pool, int i) { /* remove row (constraint) from the cut pool */ IOSCUT *cut; IOSAIJ *aij; xassert(pool != NULL); if (!(1 <= i && i <= pool->size)) xerror("glp_ios_del_row: i = %d; cut number out of range\n", i); cut = ios_find_row(pool, i); xassert(pool->curr == cut); if (cut->next != NULL) pool->curr = cut->next; else if (cut->prev != NULL) pool->ord--, pool->curr = cut->prev; else pool->ord = 0, pool->curr = NULL; if (cut->name != NULL) dmp_free_atom(tree->pool, cut->name, strlen(cut->name)+1); if (cut->prev == NULL) { xassert(pool->head == cut); pool->head = cut->next; } else { xassert(cut->prev->next == cut); cut->prev->next = cut->next; } if (cut->next == NULL) { xassert(pool->tail == cut); pool->tail = cut->prev; } else { xassert(cut->next->prev == cut); cut->next->prev = cut->prev; } while (cut->ptr != NULL) { aij = cut->ptr; cut->ptr = aij->next; dmp_free_atom(tree->pool, aij, sizeof(IOSAIJ)); } dmp_free_atom(tree->pool, cut, sizeof(IOSCUT)); pool->size--; return; } void ios_clear_pool(glp_tree *tree, IOSPOOL *pool) { /* remove all rows (constraints) from the cut pool */ xassert(pool != NULL); while (pool->head != NULL) { IOSCUT *cut = pool->head; pool->head = cut->next; if (cut->name != NULL) dmp_free_atom(tree->pool, cut->name, strlen(cut->name)+1); while (cut->ptr != NULL) { IOSAIJ *aij = cut->ptr; cut->ptr = aij->next; dmp_free_atom(tree->pool, aij, sizeof(IOSAIJ)); } dmp_free_atom(tree->pool, cut, sizeof(IOSCUT)); } pool->size = 0; pool->head = pool->tail = NULL; pool->ord = 0, pool->curr = NULL; return; } void ios_delete_pool(glp_tree *tree, IOSPOOL *pool) { /* delete cut pool */ xassert(pool != NULL); ios_clear_pool(tree, pool); xfree(pool); return; } #if 1 /* 11/VII-2013 */ #include "glpnpp.h" void ios_process_sol(glp_tree *T) { /* process integer feasible solution just found */ if (T->npp != NULL) { /* postprocess solution from transformed mip */ npp_postprocess(T->npp, T->mip); /* store solution to problem passed to glp_intopt */ npp_unload_sol(T->npp, T->P); } xassert(T->P != NULL); /* save solution to text file, if requested */ if (T->save_sol != NULL) { char *fn, *mark; fn = talloc(strlen(T->save_sol) + 50, char); mark = strrchr(T->save_sol, '*'); if (mark == NULL) strcpy(fn, T->save_sol); else { memcpy(fn, T->save_sol, mark - T->save_sol); fn[mark - T->save_sol] = '\0'; sprintf(fn + strlen(fn), "%03d", ++(T->save_cnt)); strcat(fn, &mark[1]); } glp_write_mip(T->P, fn); tfree(fn); } return; } #endif /* eof */ Rglpk/src/GLPK/glptsp.c0000644000176000001440000005712512245352174014401 0ustar ripleyusers/* glptsp.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #define _GLPSTD_ERRNO #define _GLPSTD_STDIO #include "env.h" #include "glplib.h" #include "glptsp.h" #define xfault xerror /*---------------------------------------------------------------------- -- tsp_read_data - read TSP instance data. -- -- *Synopsis* -- -- #include "glptsp.h" -- TSP *tsp_read_data(char *fname); -- -- *Description* -- -- The routine tsp_read_data reads a TSP (or related problem) instance -- data from the text file, whose name is the character string fname. -- -- For detailed description of the format recognized by the routine see -- the report: G.Reinelt, TSPLIB 95. -- -- *Returns* -- -- If no error occurred, the routine tsp_read_data returns a pointer to -- the TSP instance data block, which contains loaded data. In the case -- of error the routine prints an error message and returns NULL. */ struct dsa { /* dynamic storage area used by the routine tsp_read_data */ char *fname; /* name of the input text file */ FILE *fp; /* stream assigned to the input text file */ int seqn; /* line sequential number */ int c; /* current character */ char token[255+1]; /* current token */ }; static int get_char(struct dsa *dsa) { dsa->c = fgetc(dsa->fp); if (ferror(dsa->fp)) { xprintf("%s:%d: read error - %s\n", dsa->fname, dsa->seqn, strerror(errno)); return 1; } if (feof(dsa->fp)) dsa->c = EOF; else if (dsa->c == '\n') dsa->seqn++; else if (isspace(dsa->c)) dsa->c = ' '; else if (iscntrl(dsa->c)) { xprintf("%s:%d: invalid control character 0x%02X\n", dsa->fname, dsa->seqn, dsa->c); return 1; } return 0; } static int skip_spaces(struct dsa *dsa, int across) { while (dsa->c == ' ' || (across && dsa->c == '\n')) if (get_char(dsa)) return 1; return 0; } static int scan_keyword(struct dsa *dsa) { int len = 0; if (skip_spaces(dsa, 0)) return 1; dsa->token[0] = '\0'; while (isalnum(dsa->c) || dsa->c == '_') { if (len == 31) { xprintf("%s:%d: keyword `%s...' too long\n", dsa->fname, dsa->seqn, dsa->token); return 1; } dsa->token[len++] = (char)dsa->c, dsa->token[len] = '\0'; if (get_char(dsa)) return 1; } if (len == 0) { xprintf("%s:%d: missing keyword\n", dsa->fname, dsa->seqn); return 1; } return 0; } static int check_colon(struct dsa *dsa) { if (skip_spaces(dsa, 0)) return 1; if (dsa->c != ':') { xprintf("%s:%d: missing colon after `%s'\n", dsa->fname, dsa->seqn, dsa->token); return 1; } if (get_char(dsa)) return 1; return 0; } static int scan_token(struct dsa *dsa, int across) { int len = 0; if (skip_spaces(dsa, across)) return 1; dsa->token[0] = '\0'; while (!(dsa->c == EOF || dsa->c == '\n' || dsa->c == ' ')) { if (len == 255) { dsa->token[31] = '\0'; xprintf("%s:%d: token `%s...' too long\n", dsa->fname, dsa->seqn, dsa->token); return 1; } dsa->token[len++] = (char)dsa->c, dsa->token[len] = '\0'; if (get_char(dsa)) return 1; } return 0; } static int check_newline(struct dsa *dsa) { if (skip_spaces(dsa, 0)) return 1; if (!(dsa->c == EOF || dsa->c == '\n')) { xprintf("%s:%d: extra symbols detected\n", dsa->fname, dsa->seqn); return 1; } if (get_char(dsa)) return 1; return 0; } static int scan_comment(struct dsa *dsa) { int len = 0; if (skip_spaces(dsa, 0)) return 1; dsa->token[0] = '\0'; while (!(dsa->c == EOF || dsa->c == '\n')) { if (len == 255) { xprintf("%s:%d: comment too long\n", dsa->fname, dsa->seqn) ; return 1; } dsa->token[len++] = (char)dsa->c, dsa->token[len] = '\0'; if (get_char(dsa)) return 1; } return 0; } static int scan_integer(struct dsa *dsa, int across, int *val) { if (scan_token(dsa, across)) return 1; if (strlen(dsa->token) == 0) { xprintf("%s:%d: missing integer\n", dsa->fname, dsa->seqn); return 1; } if (str2int(dsa->token, val)) { xprintf("%s:%d: integer `%s' invalid\n", dsa->fname, dsa->seqn , dsa->token); return 1; } return 0; } static int scan_number(struct dsa *dsa, int across, double *val) { if (scan_token(dsa, across)) return 1; if (strlen(dsa->token) == 0) { xprintf("%s:%d: missing number\n", dsa->fname, dsa->seqn); return 1; } if (str2num(dsa->token, val)) { xprintf("%s:%d: number `%s' invalid\n", dsa->fname, dsa->seqn, dsa->token); return 1; } return 0; } TSP *tsp_read_data(char *fname) { struct dsa _dsa, *dsa = &_dsa; TSP *tsp = NULL; dsa->fname = fname; xprintf("tsp_read_data: reading TSP data from `%s'...\n", dsa->fname); dsa->fp = fopen(dsa->fname, "r"); if (dsa->fp == NULL) { xprintf("tsp_read_data: unable to open `%s' - %s\n", dsa->fname, strerror(errno)); goto fail; } tsp = xmalloc(sizeof(TSP)); tsp->name = NULL; tsp->type = TSP_UNDEF; tsp->comment = NULL; tsp->dimension = 0; tsp->edge_weight_type = TSP_UNDEF; tsp->edge_weight_format = TSP_UNDEF; tsp->display_data_type = TSP_UNDEF; tsp->node_x_coord = NULL; tsp->node_y_coord = NULL; tsp->dply_x_coord = NULL; tsp->dply_y_coord = NULL; tsp->tour = NULL; tsp->edge_weight = NULL; dsa->seqn = 1; if (get_char(dsa)) goto fail; loop: if (scan_keyword(dsa)) goto fail; if (strcmp(dsa->token, "NAME") == 0) { if (tsp->name != NULL) { xprintf("%s:%d: NAME entry multiply defined\n", dsa->fname, dsa->seqn); goto fail; } if (check_colon(dsa)) goto fail; if (scan_token(dsa, 0)) goto fail; if (strlen(dsa->token) == 0) { xprintf("%s:%d: NAME entry incomplete\n", dsa->fname, dsa->seqn); goto fail; } tsp->name = xmalloc(strlen(dsa->token) + 1); strcpy(tsp->name, dsa->token); xprintf("tsp_read_data: NAME: %s\n", tsp->name); if (check_newline(dsa)) goto fail; } else if (strcmp(dsa->token, "TYPE") == 0) { if (tsp->type != TSP_UNDEF) { xprintf("%s:%d: TYPE entry multiply defined\n", dsa->fname, dsa->seqn); goto fail; } if (check_colon(dsa)) goto fail; if (scan_keyword(dsa)) goto fail; if (strcmp(dsa->token, "TSP") == 0) tsp->type = TSP_TSP; else if (strcmp(dsa->token, "ATSP") == 0) tsp->type = TSP_ATSP; else if (strcmp(dsa->token, "TOUR") == 0) tsp->type = TSP_TOUR; else { xprintf("%s:%d: data type `%s' not recognized\n", dsa->fname, dsa->seqn, dsa->token); goto fail; } xprintf("tsp_read_data: TYPE: %s\n", dsa->token); if (check_newline(dsa)) goto fail; } else if (strcmp(dsa->token, "COMMENT") == 0) { if (tsp->comment != NULL) { xprintf("%s:%d: COMMENT entry multiply defined\n", dsa->fname, dsa->seqn); goto fail; } if (check_colon(dsa)) goto fail; if (scan_comment(dsa)) goto fail; tsp->comment = xmalloc(strlen(dsa->token) + 1); strcpy(tsp->comment, dsa->token); xprintf("tsp_read_data: COMMENT: %s\n", tsp->comment); if (check_newline(dsa)) goto fail; } else if (strcmp(dsa->token, "DIMENSION") == 0) { if (tsp->dimension != 0) { xprintf("%s:%d: DIMENSION entry multiply defined\n", dsa->fname, dsa->seqn); goto fail; } if (check_colon(dsa)) goto fail; if (scan_integer(dsa, 0, &tsp->dimension)) goto fail; if (tsp->dimension < 1) { xprintf("%s:%d: invalid dimension\n", dsa->fname, dsa->seqn); goto fail; } xprintf("tsp_read_data: DIMENSION: %d\n", tsp->dimension); if (check_newline(dsa)) goto fail; } else if (strcmp(dsa->token, "EDGE_WEIGHT_TYPE") == 0) { if (tsp->edge_weight_type != TSP_UNDEF) { xprintf("%s:%d: EDGE_WEIGHT_TYPE entry multiply defined\n", dsa->fname, dsa->seqn); goto fail; } if (check_colon(dsa)) goto fail; if (scan_keyword(dsa)) goto fail; if (strcmp(dsa->token, "GEO") == 0) tsp->edge_weight_type = TSP_GEO; else if (strcmp(dsa->token, "EUC_2D") == 0) tsp->edge_weight_type = TSP_EUC_2D; else if (strcmp(dsa->token, "ATT") == 0) tsp->edge_weight_type = TSP_ATT; else if (strcmp(dsa->token, "EXPLICIT") == 0) tsp->edge_weight_type = TSP_EXPLICIT; else if (strcmp(dsa->token, "CEIL_2D") == 0) tsp->edge_weight_type = TSP_CEIL_2D; else { xprintf("%s:%d: edge weight type `%s' not recognized\n", dsa->fname, dsa->seqn, dsa->token); goto fail; } xprintf("tsp_read_data: EDGE_WEIGHT_TYPE: %s\n", dsa->token); if (check_newline(dsa)) goto fail; } else if (strcmp(dsa->token, "EDGE_WEIGHT_FORMAT") == 0) { if (tsp->edge_weight_format != TSP_UNDEF) { xprintf( "%s:%d: EDGE_WEIGHT_FORMAT entry multiply defined\n", dsa->fname, dsa->seqn); goto fail; } if (check_colon(dsa)) goto fail; if (scan_keyword(dsa)) goto fail; if (strcmp(dsa->token, "UPPER_ROW") == 0) tsp->edge_weight_format = TSP_UPPER_ROW; else if (strcmp(dsa->token, "FULL_MATRIX") == 0) tsp->edge_weight_format = TSP_FULL_MATRIX; else if (strcmp(dsa->token, "FUNCTION") == 0) tsp->edge_weight_format = TSP_FUNCTION; else if (strcmp(dsa->token, "LOWER_DIAG_ROW") == 0) tsp->edge_weight_format = TSP_LOWER_DIAG_ROW; else { xprintf("%s:%d: edge weight format `%s' not recognized\n", dsa->fname, dsa->seqn, dsa->token); goto fail; } xprintf("tsp_read_data: EDGE_WEIGHT_FORMAT: %s\n", dsa->token); if (check_newline(dsa)) goto fail; } else if (strcmp(dsa->token, "DISPLAY_DATA_TYPE") == 0) { if (tsp->display_data_type != TSP_UNDEF) { xprintf("%s:%d: DISPLAY_DATA_TYPE entry multiply defined\n", dsa->fname, dsa->seqn); goto fail; } if (check_colon(dsa)) goto fail; if (scan_keyword(dsa)) goto fail; if (strcmp(dsa->token, "COORD_DISPLAY") == 0) tsp->display_data_type = TSP_COORD_DISPLAY; else if (strcmp(dsa->token, "TWOD_DISPLAY") == 0) tsp->display_data_type = TSP_TWOD_DISPLAY; else { xprintf("%s:%d: display data type `%s' not recognized\n", dsa->fname, dsa->seqn, dsa->token); goto fail; } xprintf("tsp_read_data: DISPLAY_DATA_TYPE: %s\n", dsa->token); if (check_newline(dsa)) goto fail; } else if (strcmp(dsa->token, "NODE_COORD_SECTION") == 0) { int n = tsp->dimension, k, node; if (n == 0) { xprintf("%s:%d: DIMENSION entry not specified\n", dsa->fname, dsa->seqn); goto fail; } if (tsp->node_x_coord != NULL) { xprintf("%s:%d: NODE_COORD_SECTION multiply specified\n", dsa->fname, dsa->seqn); goto fail; } if (check_newline(dsa)) goto fail; tsp->node_x_coord = xcalloc(1+n, sizeof(double)); tsp->node_y_coord = xcalloc(1+n, sizeof(double)); for (node = 1; node <= n; node++) tsp->node_x_coord[node] = tsp->node_y_coord[node] = DBL_MAX; for (k = 1; k <= n; k++) { if (scan_integer(dsa, 0, &node)) goto fail; if (!(1 <= node && node <= n)) { xprintf("%s:%d: invalid node number %d\n", dsa->fname, dsa->seqn, node); goto fail; } if (tsp->node_x_coord[node] != DBL_MAX) { xprintf("%s:%d: node number %d multiply specified\n", dsa->fname, dsa->seqn, node); goto fail; } if (scan_number(dsa, 0, &tsp->node_x_coord[node])) goto fail; if (scan_number(dsa, 0, &tsp->node_y_coord[node])) goto fail; if (check_newline(dsa)) goto fail; } } else if (strcmp(dsa->token, "DISPLAY_DATA_SECTION") == 0) { int n = tsp->dimension, k, node; if (n == 0) { xprintf("%s:%d: DIMENSION entry not specified\n", dsa->fname, dsa->seqn); goto fail; } if (tsp->dply_x_coord != NULL) { xprintf("%s:%d: DISPLAY_DATA_SECTION multiply specified\n", dsa->fname, dsa->seqn); goto fail; } if (check_newline(dsa)) goto fail; tsp->dply_x_coord = xcalloc(1+n, sizeof(double)); tsp->dply_y_coord = xcalloc(1+n, sizeof(double)); for (node = 1; node <= n; node++) tsp->dply_x_coord[node] = tsp->dply_y_coord[node] = DBL_MAX; for (k = 1; k <= n; k++) { if (scan_integer(dsa, 0, &node)) goto fail; if (!(1 <= node && node <= n)) { xprintf("%s:%d: invalid node number %d\n", dsa->fname, dsa->seqn, node); goto fail; } if (tsp->dply_x_coord[node] != DBL_MAX) { xprintf("%s:%d: node number %d multiply specified\n", dsa->fname, dsa->seqn, node); goto fail; } if (scan_number(dsa, 0, &tsp->dply_x_coord[node])) goto fail; if (scan_number(dsa, 0, &tsp->dply_y_coord[node])) goto fail; if (check_newline(dsa)) goto fail; } } else if (strcmp(dsa->token, "TOUR_SECTION") == 0) { int n = tsp->dimension, k, node; if (n == 0) { xprintf("%s:%d: DIMENSION entry not specified\n", dsa->fname, dsa->seqn); goto fail; } if (tsp->tour != NULL) { xprintf("%s:%d: TOUR_SECTION multiply specified\n", dsa->fname, dsa->seqn); goto fail; } if (check_newline(dsa)) goto fail; tsp->tour = xcalloc(1+n, sizeof(int)); for (k = 1; k <= n; k++) { if (scan_integer(dsa, 1, &node)) goto fail; if (!(1 <= node && node <= n)) { xprintf("%s:%d: invalid node number %d\n", dsa->fname, dsa->seqn, node); goto fail; } tsp->tour[k] = node; } if (scan_integer(dsa, 1, &node)) goto fail; if (node != -1) { xprintf("%s:%d: extra node(s) detected\n", dsa->fname, dsa->seqn); goto fail; } if (check_newline(dsa)) goto fail; } else if (strcmp(dsa->token, "EDGE_WEIGHT_SECTION") == 0) { int n = tsp->dimension, i, j, temp; if (n == 0) { xprintf("%s:%d: DIMENSION entry not specified\n", dsa->fname, dsa->seqn); goto fail; } if (tsp->edge_weight_format == TSP_UNDEF) { xprintf("%s:%d: EDGE_WEIGHT_FORMAT entry not specified\n", dsa->fname, dsa->seqn); goto fail; } if (tsp->edge_weight != NULL) { xprintf("%s:%d: EDGE_WEIGHT_SECTION multiply specified\n", dsa->fname, dsa->seqn); goto fail; } if (check_newline(dsa)) goto fail; tsp->edge_weight = xcalloc(1+n*n, sizeof(int)); switch (tsp->edge_weight_format) { case TSP_FULL_MATRIX: for (i = 1; i <= n; i++) { for (j = 1; j <= n; j++) { if (scan_integer(dsa, 1, &temp)) goto fail; tsp->edge_weight[(i - 1) * n + j] = temp; } } break; case TSP_UPPER_ROW: for (i = 1; i <= n; i++) { tsp->edge_weight[(i - 1) * n + i] = 0; for (j = i + 1; j <= n; j++) { if (scan_integer(dsa, 1, &temp)) goto fail; tsp->edge_weight[(i - 1) * n + j] = temp; tsp->edge_weight[(j - 1) * n + i] = temp; } } break; case TSP_LOWER_DIAG_ROW: for (i = 1; i <= n; i++) { for (j = 1; j <= i; j++) { if (scan_integer(dsa, 1, &temp)) goto fail; tsp->edge_weight[(i - 1) * n + j] = temp; tsp->edge_weight[(j - 1) * n + i] = temp; } } break; default: goto fail; } if (check_newline(dsa)) goto fail; } else if (strcmp(dsa->token, "EOF") == 0) { if (check_newline(dsa)) goto fail; goto done; } else { xprintf("%s:%d: keyword `%s' not recognized\n", dsa->fname, dsa->seqn, dsa->token); goto fail; } goto loop; done: xprintf("tsp_read_data: %d lines were read\n", dsa->seqn-1); fclose(dsa->fp); return tsp; fail: if (tsp != NULL) { if (tsp->name != NULL) xfree(tsp->name); if (tsp->comment != NULL) xfree(tsp->comment); if (tsp->node_x_coord != NULL) xfree(tsp->node_x_coord); if (tsp->node_y_coord != NULL) xfree(tsp->node_y_coord); if (tsp->dply_x_coord != NULL) xfree(tsp->dply_x_coord); if (tsp->dply_y_coord != NULL) xfree(tsp->dply_y_coord); if (tsp->tour != NULL) xfree(tsp->tour); if (tsp->edge_weight != NULL) xfree(tsp->edge_weight); xfree(tsp); } if (dsa->fp != NULL) fclose(dsa->fp); return NULL; } /*---------------------------------------------------------------------- -- tsp_free_data - free TSP instance data. -- -- *Synopsis* -- -- #include "glptsp.h" -- void tsp_free_data(TSP *tsp); -- -- *Description* -- -- The routine tsp_free_data frees all the memory allocated to the TSP -- instance data block, which the parameter tsp points to. */ void tsp_free_data(TSP *tsp) { if (tsp->name != NULL) xfree(tsp->name); if (tsp->comment != NULL) xfree(tsp->comment); if (tsp->node_x_coord != NULL) xfree(tsp->node_x_coord); if (tsp->node_y_coord != NULL) xfree(tsp->node_y_coord); if (tsp->dply_x_coord != NULL) xfree(tsp->dply_x_coord); if (tsp->dply_y_coord != NULL) xfree(tsp->dply_y_coord); if (tsp->tour != NULL) xfree(tsp->tour); if (tsp->edge_weight != NULL) xfree(tsp->edge_weight); xfree(tsp); return; } /*---------------------------------------------------------------------- -- tsp_distance - compute distance between two nodes. -- -- *Synopsis* -- -- #include "glptsp.h" -- int tsp_distance(TSP *tsp, int i, int j); -- -- *Description* -- -- The routine tsp_distance computes the distance between i-th and j-th -- nodes for the TSP instance, which tsp points to. -- -- *Returns* -- -- The routine tsp_distance returns the computed distance. */ #define nint(x) ((int)((x) + 0.5)) static double rad(double x) { /* convert input coordinate to longitude/latitude, in radians */ double pi = 3.141592, deg, min; deg = (int)x; min = x - deg; return pi * (deg + 5.0 * min / 3.0) / 180.0; } int tsp_distance(TSP *tsp, int i, int j) { int n = tsp->dimension, dij; if (!(tsp->type == TSP_TSP || tsp->type == TSP_ATSP)) xfault("tsp_distance: invalid TSP instance\n"); if (!(1 <= i && i <= n && 1 <= j && j <= n)) xfault("tsp_distance: node number out of range\n"); switch (tsp->edge_weight_type) { case TSP_UNDEF: xfault("tsp_distance: edge weight type not specified\n"); case TSP_EXPLICIT: if (tsp->edge_weight == NULL) xfault("tsp_distance: edge weights not specified\n"); dij = tsp->edge_weight[(i - 1) * n + j]; break; case TSP_EUC_2D: if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL) xfault("tsp_distance: node coordinates not specified\n"); { double xd, yd; xd = tsp->node_x_coord[i] - tsp->node_x_coord[j]; yd = tsp->node_y_coord[i] - tsp->node_y_coord[j]; dij = nint(sqrt(xd * xd + yd * yd)); } break; case TSP_CEIL_2D: if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL) xfault("tsp_distance: node coordinates not specified\n"); { double xd, yd; xd = tsp->node_x_coord[i] - tsp->node_x_coord[j]; yd = tsp->node_y_coord[i] - tsp->node_y_coord[j]; dij = (int)ceil(sqrt(xd * xd + yd * yd)); } break; case TSP_GEO: if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL) xfault("tsp_distance: node coordinates not specified\n"); { double rrr = 6378.388; double latitude_i = rad(tsp->node_x_coord[i]); double latitude_j = rad(tsp->node_x_coord[j]); double longitude_i = rad(tsp->node_y_coord[i]); double longitude_j = rad(tsp->node_y_coord[j]); double q1 = cos(longitude_i - longitude_j); double q2 = cos(latitude_i - latitude_j); double q3 = cos(latitude_i + latitude_j); dij = (int)(rrr * acos(0.5 * ((1.0 + q1) * q2 - (1.0 - q1) *q3)) + 1.0); } break; case TSP_ATT: if (tsp->node_x_coord == NULL || tsp->node_y_coord == NULL) xfault("tsp_distance: node coordinates not specified\n"); { int tij; double xd, yd, rij; xd = tsp->node_x_coord[i] - tsp->node_x_coord[j]; yd = tsp->node_y_coord[i] - tsp->node_y_coord[j]; rij = sqrt((xd * xd + yd * yd) / 10.0); tij = nint(rij); if (tij < rij) dij = tij + 1; else dij = tij; } break; default: xassert(tsp->edge_weight_type != tsp->edge_weight_type); } return dij; } /* eof */ Rglpk/src/GLPK/sgf.c0000644000176000001440000015452112245352174013645 0ustar ripleyusers/* sgf.c (sparse Gaussian factorizer) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #include "sgf.h" /*********************************************************************** * sgf_reduce_nuc - initial reordering to minimize nucleus size * * On entry to this routine it is assumed that V = A and F = P = Q = I, * where A is the original matrix to be factorized. It is also assumed * that matrix V = A is stored in both row- and column-wise formats. * * This routine performs (implicit) non-symmetric permutations of rows * and columns of matrix U = P'* V * Q' to reduce it to the form: * * 1 k1 k2 n * 1 x x x x x x x x x x * . x x x x x x x x x * . . x x x x x x x x * k1 . . . * * * * x x x * . . . * * * * x x x * . . . * * * * x x x * k2 . . . * * * * x x x * . . . . . . . x x x * . . . . . . . . x x * n . . . . . . . . . x * * where non-zeros in rows and columns k1, k1+1, ..., k2 constitute so * called nucleus ('*'), whose size is minimized by the routine. * * The numbers k1 and k2 are returned by the routine on exit. Usually, * if the nucleus exists, 1 <= k1 < k2 <= n. However, if the resultant * matrix U is upper triangular (has no nucleus), k1 = n+1 and k2 = n. * * Note that the routines sgf_choose_pivot and sgf_eliminate perform * exactly the same transformations (by processing row and columns * singletons), so preliminary minimization of the nucleus may not be * used. However, processing row and column singletons by the routines * sgf_minimize_nuc and sgf_singl_phase is more efficient. */ void sgf_reduce_nuc(LUF *luf, int *k1_, int *k2_, int cnt[/*1+n*/], int list[/*1+n*/]) { int n = luf->n; SVA *sva = luf->sva; int *sv_ind = sva->ind; int vr_ref = luf->vr_ref; int *vr_ptr = &sva->ptr[vr_ref-1]; int *vr_len = &sva->len[vr_ref-1]; int vc_ref = luf->vc_ref; int *vc_ptr = &sva->ptr[vc_ref-1]; int *vc_len = &sva->len[vc_ref-1]; int *pp_ind = luf->pp_ind; int *pp_inv = luf->pp_inv; int *qq_ind = luf->qq_ind; int *qq_inv = luf->qq_inv; int i, ii, j, jj, k1, k2, ns, ptr, end; /* initial nucleus is U = V = A */ k1 = 1, k2 = n; /*--------------------------------------------------------------*/ /* process column singletons */ /*--------------------------------------------------------------*/ /* determine initial counts of columns of V and initialize list * of active column singletons */ ns = 0; /* number of active column singletons */ for (j = 1; j <= n; j++) { if ((cnt[j] = vc_len[j]) == 1) list[++ns] = j; } /* process active column singletons */ while (ns > 0) { /* column singleton is in j-th column of V */ j = list[ns--]; /* find i-th row of V containing column singleton */ ptr = vc_ptr[j]; end = ptr + vc_len[j]; for (; pp_ind[i = sv_ind[ptr]] < k1; ptr++) /* nop */; xassert(ptr < end); /* permute rows and columns of U to move column singleton to * position u[k1,k1] */ ii = pp_ind[i]; luf_swap_u_rows(k1, ii); jj = qq_inv[j]; luf_swap_u_cols(k1, jj); /* nucleus size decreased */ k1++; /* walk thru i-th row of V and decrease column counts; this * may cause new column singletons to appear */ ptr = vr_ptr[i]; end = ptr + vr_len[i]; for (; ptr < end; ptr++) { if (--(cnt[j = sv_ind[ptr]]) == 1) list[++ns] = j; } } /* nucleus begins at k1-th row/column of U */ if (k1 > n) { /* U is upper triangular; no nucleus exist */ goto done; } /*--------------------------------------------------------------*/ /* process row singletons */ /*--------------------------------------------------------------*/ /* determine initial counts of rows of V and initialize list of * active row singletons */ ns = 0; /* number of active row singletons */ for (i = 1; i <= n; i++) { if (pp_ind[i] < k1) { /* corresponding row of U is above its k1-th row; set its * count to zero to prevent including it in active list */ cnt[i] = 0; } else if ((cnt[i] = vr_len[i]) == 1) list[++ns] = i; } /* process active row singletons */ while (ns > 0) { /* row singleton is in i-th row of V */ i = list[ns--]; /* find j-th column of V containing row singleton */ ptr = vr_ptr[i]; end = ptr + vr_len[i]; for (; qq_inv[j = sv_ind[ptr]] > k2; ptr++) /* nop */; xassert(ptr < end); /* permute rows and columns of U to move row singleton to * position u[k2,k2] */ ii = pp_ind[i]; luf_swap_u_rows(k2, ii); jj = qq_inv[j]; luf_swap_u_cols(k2, jj); /* nucleus size decreased */ k2--; /* walk thru j-th column of V and decrease row counts; this * may cause new row singletons to appear */ ptr = vc_ptr[j]; end = ptr + vc_len[j]; for (; ptr < end; ptr++) { if (--(cnt[i = sv_ind[ptr]]) == 1) list[++ns] = i; } } /* nucleus ends at k2-th row/column of U */ xassert(k1 < k2); done: *k1_ = k1, *k2_ = k2; return; } /*********************************************************************** * sgf_singl_phase - compute LU-factorization (singleton phase) * * It is assumed that on entry to the routine L = P'* F * P = F = I * and matrix U = P'* V * Q' has the following structure (provided by * the routine sgf_reduce_nuc): * * 1 k1 k2 n * 1 a a a b b b b c c c * . a a b b b b c c c * . . a b b b b c c c * k1 . . . * * * * d d d * . . . * * * * d d d * . . . * * * * d d d * k2 . . . * * * * d d d * . . . . . . . e e e * . . . . . . . . e e * n . . . . . . . . . e * * First, the routine performs (implicit) symmetric permutations of * rows and columns of matrix U to place them in the following order: * * 1, 2, ..., k1-1; n, n-1, ..., k2+1; k1, k1+1, ..., k2 * * This changes the structure of matrix U as follows: * * 1 k1 k2' n * 1 a a a c c c b b b b * . a a c c c b b b b * . . a c c c b b b b * k1 . . . e . . . . . . * . . . e e . . . . . * . . . e e e . . . . * k2'. . . d d d * * * * * . . . d d d * * * * * . . . d d d * * * * * n . . . d d d * * * * * * where k2' = n - k2 + k1. * * Then the routine performs elementary gaussian transformations to * eliminate subdiagonal elements in columns k1, ..., k2'-1 of U. The * effect is the same as if the routine sgf_eliminate would be called * for k = 1, ..., k2'-1 using diagonal elements u[k,k] as pivots. * * After elimination matrices L and U becomes the following: * * 1 k1 k2' n 1 k1 k2' n * 1 1 . . . . . . . . . 1 a a a c c c b b b b * . 1 . . . . . . . . . a a c c c b b b b * . . 1 . . . . . . . . . a c c c b b b b * k1 . . . 1 . . . . . . k1 . . . e . . . . . . * . . . e'1 . . . . . . . . . e . . . . . * . . . e'e'1 . . . . . . . . . e . . . . * k2'. . . d'd'd'1 . . . k2'. . . . . . * * * * * . . . d'd'd'. 1 . . . . . . . . * * * * * . . . d'd'd'. . 1 . . . . . . . * * * * * n . . . d'd'd'. . . 1 n . . . . . . * * * * * * matrix L matrix U * * where columns k1, ..., k2'-1 of L consist of subdiagonal elements * of initial matrix U divided by pivots u[k,k]. * * On exit the routine returns k2', the elimination step number, from * which computing of the factorization should be continued. Note that * k2' = n+1 means that matrix U is already upper triangular. */ int sgf_singl_phase(LUF *luf, int k1, int k2, int updat, int ind[/*1+n*/], double val[/*1+n*/]) { int n = luf->n; SVA *sva = luf->sva; int *sv_ind = sva->ind; double *sv_val = sva->val; int fc_ref = luf->fc_ref; int *fc_ptr = &sva->ptr[fc_ref-1]; int *fc_len = &sva->len[fc_ref-1]; int vr_ref = luf->vr_ref; int *vr_ptr = &sva->ptr[vr_ref-1]; int *vr_len = &sva->len[vr_ref-1]; double *vr_piv = luf->vr_piv; int vc_ref = luf->vc_ref; int *vc_ptr = &sva->ptr[vc_ref-1]; int *vc_len = &sva->len[vc_ref-1]; int *pp_ind = luf->pp_ind; int *pp_inv = luf->pp_inv; int *qq_ind = luf->qq_ind; int *qq_inv = luf->qq_inv; int i, j, k, ptr, ptr1, end, len; double piv; /* (see routine sgf_reduce_nuc) */ xassert((1 <= k1 && k1 < k2 && k2 <= n) || (k1 == n+1 && k2 == n)); /* perform symmetric permutations of rows/columns of U */ for (k = k1; k <= k2; k++) pp_ind[pp_inv[k]] = qq_inv[qq_ind[k]] = k - k2 + n; for (k = k2+1; k <= n; k++) pp_ind[pp_inv[k]] = qq_inv[qq_ind[k]] = n - k + k1; for (k = 1; k <= n; k++) pp_inv[pp_ind[k]] = qq_ind[qq_inv[k]] = k; /* determine k2' */ k2 = n - k2 + k1; /* process rows and columns of V corresponding to rows and * columns 1, ..., k1-1 of U */ for (k = 1; k < k1; k++) { /* k-th row of U = i-th row of V */ i = pp_inv[k]; /* find pivot u[k,k] = v[i,j] in i-th row of V */ ptr = vr_ptr[i]; end = ptr + vr_len[i]; for (; qq_inv[sv_ind[ptr]] != k; ptr++) /* nop */; xassert(ptr < end); /* store pivot */ vr_piv[i] = sv_val[ptr]; /* and remove it from i-th row of V */ sv_ind[ptr] = sv_ind[end-1]; sv_val[ptr] = sv_val[end-1]; vr_len[i]--; /* clear column of V corresponding to k-th column of U */ vc_len[qq_ind[k]] = 0; } /* clear rows of V corresponding to rows k1, ..., k2'-1 of U */ for (k = k1; k < k2; k++) vr_len[pp_inv[k]] = 0; /* process rows and columns of V corresponding to rows and * columns k2', ..., n of U */ for (k = k2; k <= n; k++) { /* k-th row of U = i-th row of V */ i = pp_inv[k]; /* remove elements from i-th row of V that correspond to * elements u[k,k1], ..., u[k,k2'-1] */ ptr = ptr1 = vr_ptr[i]; end = ptr + vr_len[i]; for (; ptr < end; ptr++) { if (qq_inv[sv_ind[ptr]] >= k2) { sv_ind[ptr1] = sv_ind[ptr]; sv_val[ptr1] = sv_val[ptr]; ptr1++; } } vr_len[i] = ptr1 - vr_ptr[i]; /* k-th column of U = j-th column of V */ j = qq_ind[k]; /* remove elements from j-th column of V that correspond to * elements u[1,k], ..., u[k1-1,k] */ ptr = ptr1 = vc_ptr[j]; end = ptr + vc_len[j]; for (; ptr < end; ptr++) { if (pp_ind[sv_ind[ptr]] >= k2) /* element value is not needed in this case */ sv_ind[ptr1++] = sv_ind[ptr]; } vc_len[j] = ptr1 - vc_ptr[j]; } /* process columns of V corresponding to columns k1, ..., k2'-1 * of U, build columns of F */ for (k = k1; k < k2; k++) { /* k-th column of U = j-th column of V */ j = qq_ind[k]; /* remove elements from j-th column of V that correspond to * pivot (diagonal) element u[k,k] and subdiagonal elements * u[k+1,k], ..., u[n,k]; subdiagonal elements are stored for * further addition to matrix F */ len = 0; piv = 0.0; ptr = vc_ptr[j]; end = ptr + vc_len[j]; for (; ptr < end; ptr++) { i = sv_ind[ptr]; /* v[i,j] */ if (pp_ind[i] == k) { /* store pivot v[i,j] = u[k,k] */ piv = vr_piv[i] = sv_val[ptr]; } else if (pp_ind[i] > k) { /* store subdiagonal element v[i,j] = u[i',k] */ len++; ind[len] = i; val[len] = sv_val[ptr]; } } /* clear j-th column of V = k-th column of U */ vc_len[j] = 0; /* build k-th column of L = j-th column of F */ j = pp_inv[k]; xassert(piv != 0.0); if (len > 0) { if (sva->r_ptr - sva->m_ptr < len) { sva_more_space(sva, len); sv_ind = sva->ind; sv_val = sva->val; } sva_reserve_cap(sva, fc_ref-1+j, len); for (ptr = fc_ptr[j], ptr1 = 1; ptr1 <= len; ptr++, ptr1++) { sv_ind[ptr] = ind[ptr1]; sv_val[ptr] = val[ptr1] / piv; } fc_len[j] = len; } } /* if it is not planned to update matrix V, relocate all its * non-active rows corresponding to rows 1, ..., k2'-1 of U to * the right (static) part of SVA */ if (!updat) { for (k = 1; k < k2; k++) { i = pp_inv[k]; len = vr_len[i]; if (sva->r_ptr - sva->m_ptr < len) { sva_more_space(sva, len); sv_ind = sva->ind; sv_val = sva->val; } sva_make_static(sva, vr_ref-1+i); } } /* elimination steps 1, ..., k2'-1 have been performed */ return k2; } /*********************************************************************** * sgf_choose_pivot - choose pivot element v[p,q] * * This routine chooses pivot element v[p,q], k <= p, q <= n, in the * active submatrix of matrix V = P * U * Q, where k is the number of * current elimination step, 1 <= k <= n. * * It is assumed that on entry to the routine matrix U = P'* V * Q' has * the following partially triangularized form: * * 1 k n * 1 x x x x x x x x x x * . x x x x x x x x x * . . x x x x x x x x * . . . x x x x x x x * k . . . . * * * * * * * . . . . * * * * * * * . . . . * * * * * * * . . . . * * * * * * * . . . . * * * * * * * n . . . . * * * * * * * * where rows and columns k, k+1, ..., n belong to the active submatrix * (its elements are marked by '*'). * * Since the matrix U is not stored, the routine works with the matrix * V = P * U * Q. It is assumed that the row-wise representation * corresponds to the matrix V, but the column-wise representation * corresponds to the active submatrix of the matrix V, i.e. elements, * which are not in the active submatrix, are not included in column * vectors. It is also assumed that each active row of the matrix V is * in the set R[len], where len is the number of non-zeros in the row, * and each active column of the matrix V is in the set C[len], where * len is the number of non-zeros in the column (in the latter case * only elements of the active submatrix are counted; such elements are * marked by '*' on the figure above). * * For the reason of numerical stability the routine applies so called * threshold pivoting proposed by J.Reid. It is assumed that an element * v[i,j] can be selected as a pivot candidate if it is not very small * (in magnitude) among other elements in the same row, i.e. if it * satisfies to the stability condition |v[i,j]| >= tol * max|v[i,*]|, * where 0 < tol < 1 is a given tolerance. * * In order to keep sparsity of the matrix V the routine uses Markowitz * strategy, trying to choose such element v[p,q], which satisfies to * the stability condition (see above) and has smallest Markowitz cost * (nr[p]-1) * (nc[q]-1), where nr[p] and nc[q] are, resp., numbers of * non-zeros in p-th row and q-th column of the active submatrix. * * In order to reduce the search, i.e. not to walk through all elements * of the active submatrix, the routine uses a technique proposed by * I.Duff. This technique is based on using the sets R[len] and C[len] * of active rows and columns. * * If the pivot element v[p,q] has been chosen, the routine stores its * indices to locations *p and *q and returns zero. Otherwise, non-zero * is returned. */ int sgf_choose_pivot(SGF *sgf, int *p_, int *q_) { LUF *luf = sgf->luf; int n = luf->n; SVA *sva = luf->sva; int *sv_ind = sva->ind; double *sv_val = sva->val; int vr_ref = luf->vr_ref; int *vr_ptr = &sva->ptr[vr_ref-1]; int *vr_len = &sva->len[vr_ref-1]; int vc_ref = luf->vc_ref; int *vc_ptr = &sva->ptr[vc_ref-1]; int *vc_len = &sva->len[vc_ref-1]; int *rs_head = sgf->rs_head; int *rs_next = sgf->rs_next; int *cs_head = sgf->cs_head; int *cs_prev = sgf->cs_prev; int *cs_next = sgf->cs_next; double *vr_max = sgf->vr_max; double piv_tol = sgf->piv_tol; int piv_lim = sgf->piv_lim; int suhl = sgf->suhl; int i, i_ptr, i_end, j, j_ptr, j_end, len, min_i, min_j, min_len, ncand, next_j, p, q; double best, big, cost, temp; /* no pivot candidate has been chosen so far */ p = q = 0, best = DBL_MAX, ncand = 0; /* if the active submatrix contains a column having the only * non-zero element (column singleton), choose it as the pivot */ j = cs_head[1]; if (j != 0) { xassert(vc_len[j] == 1); p = sv_ind[vc_ptr[j]], q = j; goto done; } /* if the active submatrix contains a row having the only * non-zero element (row singleton), choose it as the pivot */ i = rs_head[1]; if (i != 0) { xassert(vr_len[i] == 1); p = i, q = sv_ind[vr_ptr[i]]; goto done; } /* the active submatrix contains no singletons; walk thru its * other non-empty rows and columns */ for (len = 2; len <= n; len++) { /* consider active columns containing len non-zeros */ for (j = cs_head[len]; j != 0; j = next_j) { /* save the number of next column of the same length */ next_j = cs_next[j]; /* find an element in j-th column, which is placed in the * row with minimal number of non-zeros and satisfies to * the stability condition (such element may not exist) */ min_i = min_j = 0, min_len = INT_MAX; for (j_end = (j_ptr = vc_ptr[j]) + vc_len[j]; j_ptr < j_end; j_ptr++) { /* get row index of v[i,j] */ i = sv_ind[j_ptr]; /* if i-th row is not shorter, skip v[i,j] */ if (vr_len[i] >= min_len) continue; /* big := max|v[i,*]| */ if ((big = vr_max[i]) < 0.0) { /* largest magnitude is unknown; compute it */ for (i_end = (i_ptr = vr_ptr[i]) + vr_len[i]; i_ptr < i_end; i_ptr++) { if ((temp = sv_val[i_ptr]) < 0.0) temp = -temp; if (big < temp) big = temp; } xassert(big > 0.0); vr_max[i] = big; } /* find v[i,j] in i-th row */ for (i_end = (i_ptr = vr_ptr[i]) + vr_len[i]; sv_ind[i_ptr] != j; i_ptr++) /* nop */; xassert(i_ptr < i_end); /* if |v[i,j]| < piv_tol * max|v[i,*]|, skip v[i,j] */ if ((temp = sv_val[i_ptr]) < 0.0) temp = -temp; if (temp < piv_tol * big) continue; /* v[i,j] is a better candidate */ min_i = i, min_j = j, min_len = vr_len[i]; /* if Markowitz cost of v[i,j] is not greater than * (len-1)**2, v[i,j] can be chosen as the pivot right * now; this heuristic reduces the search and works well * in many cases */ if (min_len <= len) { p = min_i, q = min_j; goto done; } } /* j-th column has been scanned */ if (min_i != 0) { /* element v[min_i,min_j] is a next pivot candidate */ ncand++; /* compute its Markowitz cost */ cost = (double)(min_len - 1) * (double)(len - 1); /* if this element is better, choose it as the pivot */ if (cost < best) p = min_i, q = min_j, best = cost; /* if piv_lim candidates were considered, terminate * the search, because it is doubtful that a much better * candidate will be found */ if (ncand == piv_lim) goto done; } else if (suhl) { /* j-th column has no eligible elements that satisfy to * the stability criterion; Uwe Suhl suggests to exclude * such column from further considerations until it * becomes a column singleton; in hard cases this may * significantly reduce the time needed to choose the * pivot element */ sgf_deactivate_col(j); cs_prev[j] = cs_next[j] = j; } } /* consider active rows containing len non-zeros */ for (i = rs_head[len]; i != 0; i = rs_next[i]) { /* big := max|v[i,*]| */ if ((big = vr_max[i]) < 0.0) { /* largest magnitude is unknown; compute it */ for (i_end = (i_ptr = vr_ptr[i]) + vr_len[i]; i_ptr < i_end; i_ptr++) { if ((temp = sv_val[i_ptr]) < 0.0) temp = -temp; if (big < temp) big = temp; } xassert(big > 0.0); vr_max[i] = big; } /* find an element in i-th row, which is placed in the * column with minimal number of non-zeros and satisfies to * the stability condition (such element always exists) */ min_i = min_j = 0, min_len = INT_MAX; for (i_end = (i_ptr = vr_ptr[i]) + vr_len[i]; i_ptr < i_end; i_ptr++) { /* get column index of v[i,j] */ j = sv_ind[i_ptr]; /* if j-th column is not shorter, skip v[i,j] */ if (vc_len[j] >= min_len) continue; /* if |v[i,j]| < piv_tol * max|v[i,*]|, skip v[i,j] */ if ((temp = sv_val[i_ptr]) < 0.0) temp = -temp; if (temp < piv_tol * big) continue; /* v[i,j] is a better candidate */ min_i = i, min_j = j, min_len = vc_len[j]; /* if Markowitz cost of v[i,j] is not greater than * (len-1)**2, v[i,j] can be chosen as the pivot right * now; this heuristic reduces the search and works well * in many cases */ if (min_len <= len) { p = min_i, q = min_j; goto done; } } /* i-th row has been scanned */ if (min_i != 0) { /* element v[min_i,min_j] is a next pivot candidate */ ncand++; /* compute its Markowitz cost */ cost = (double)(len - 1) * (double)(min_len - 1); /* if this element is better, choose it as the pivot */ if (cost < best) p = min_i, q = min_j, best = cost; /* if piv_lim candidates were considered, terminate * the search, because it is doubtful that a much better * candidate will be found */ if (ncand == piv_lim) goto done; } else { /* this can never be */ xassert(min_i != min_i); } } } done: /* report the pivot to the factorization routine */ *p_ = p, *q_ = q; return (p == 0); } /*********************************************************************** * sgf_eliminate - perform gaussian elimination * * This routine performs elementary gaussian transformations in order * to eliminate subdiagonal elements in k-th column of matrix * U = P'* V * Q' using pivot element u[k,k], where k is the number of * current elimination step, 1 <= k <= n. * * The parameters p and q specify, resp., row and column indices of the * pivot element v[p,q] = u[k,k]. * * On entry the routine assumes that partially triangularized matrices * L = P'* F * P and U = P'* V * Q' have the following structure: * * 1 k n 1 k n * 1 1 . . . . . . . . . 1 x x x x x x x x x x * x 1 . . . . . . . . . x x x x x x x x x * x x 1 . . . . . . . . . x x x x x x x x * x x x 1 . . . . . . . . . x x x x x x x * k x x x x 1 . . . . . k . . . . * * * * * * * x x x x _ 1 . . . . . . . . # * * * * * * x x x x _ . 1 . . . . . . . # * * * * * * x x x x _ . . 1 . . . . . . # * * * * * * x x x x _ . . . 1 . . . . . # * * * * * * n x x x x _ . . . . 1 n . . . . # * * * * * * * matrix L matrix U * * where rows and columns k, k+1, ..., n of matrix U constitute the * active submatrix. Elements to be eliminated are marked by '#', and * other elements of the active submatrix are marked by '*'. May note * that each eliminated non-zero element u[i,k] of matrix U gives * corresponding non-zero element l[i,k] of matrix L (marked by '_'). * * Actually all operations are performed on matrix V. It is assumed * that the row-wise representation corresponds to matrix V, but the * column-wise representation corresponds to the active submatrix of * matrix V (or, more precisely, to its pattern, because only row * indices for columns of the active submatrix are used on this stage). * * Let u[k,k] = v[p,q] be the pivot. In order to eliminate subdiagonal * elements u[i',k] = v[i,q], i'= k+1, k+2, ..., n, the routine applies * the following elementary gaussian transformations: * * (i-th row of V) := (i-th row of V) - f[i,p] * (p-th row of V), * * where f[i,p] = v[i,q] / v[p,q] is a gaussian multiplier stored to * p-th column of matrix F to keep the main equality A = F * V * (corresponding elements l[i',k] of matrix L are marked by '_' on the * figure above). * * NOTE: On entry to the routine the working arrays flag and work * should contain zeros. This status is retained by the routine * on exit. */ int sgf_eliminate(SGF *sgf, int p, int q) { LUF *luf = sgf->luf; int n = luf->n; SVA *sva = luf->sva; int *sv_ind = sva->ind; double *sv_val = sva->val; int fc_ref = luf->fc_ref; int *fc_ptr = &sva->ptr[fc_ref-1]; int *fc_len = &sva->len[fc_ref-1]; int vr_ref = luf->vr_ref; int *vr_ptr = &sva->ptr[vr_ref-1]; int *vr_len = &sva->len[vr_ref-1]; int *vr_cap = &sva->cap[vr_ref-1]; double *vr_piv = luf->vr_piv; int vc_ref = luf->vc_ref; int *vc_ptr = &sva->ptr[vc_ref-1]; int *vc_len = &sva->len[vc_ref-1]; int *vc_cap = &sva->cap[vc_ref-1]; int *rs_head = sgf->rs_head; int *rs_prev = sgf->rs_prev; int *rs_next = sgf->rs_next; int *cs_head = sgf->cs_head; int *cs_prev = sgf->cs_prev; int *cs_next = sgf->cs_next; double *vr_max = sgf->vr_max; char *flag = sgf->flag; double *work = sgf->work; double eps_tol = sgf->eps_tol; int nnz_diff = 0; int fill, i, i_ptr, i_end, j, j_ptr, j_end, ptr, len, loc, loc1; double vpq, fip, vij; xassert(1 <= p && p <= n); xassert(1 <= q && q <= n); /* remove p-th row from the active set; this row will never * return there */ sgf_deactivate_row(p); /* process p-th (pivot) row */ ptr = 0; for (i_end = (i_ptr = vr_ptr[p]) + vr_len[p]; i_ptr < i_end; i_ptr++) { /* get column index of v[p,j] */ j = sv_ind[i_ptr]; if (j == q) { /* save pointer to pivot v[p,q] */ ptr = i_ptr; } else { /* store v[p,j], j != q, to working array */ flag[j] = 1; work[j] = sv_val[i_ptr]; } /* remove j-th column from the active set; q-th column will * never return there while other columns will return to the * active set with new length */ if (cs_next[j] == j) { /* j-th column was marked by the pivoting routine according * to Uwe Suhl's suggestion and is already inactive */ xassert(cs_prev[j] == j); } else sgf_deactivate_col(j); nnz_diff -= vc_len[j]; /* find and remove v[p,j] from j-th column */ for (j_end = (j_ptr = vc_ptr[j]) + vc_len[j]; sv_ind[j_ptr] != p; j_ptr++) /* nop */; xassert(j_ptr < j_end); sv_ind[j_ptr] = sv_ind[j_end-1]; vc_len[j]--; } /* save pivot v[p,q] and remove it from p-th row */ xassert(ptr > 0); vpq = vr_piv[p] = sv_val[ptr]; sv_ind[ptr] = sv_ind[i_end-1]; sv_val[ptr] = sv_val[i_end-1]; vr_len[p]--; /* if it is not planned to update matrix V, relocate p-th row to * the right (static) part of SVA */ if (!sgf->updat) { len = vr_len[p]; if (sva->r_ptr - sva->m_ptr < len) { sva_more_space(sva, len); sv_ind = sva->ind; sv_val = sva->val; } sva_make_static(sva, vr_ref-1+p); } /* copy the pattern (row indices) of q-th column of the active * submatrix (from which v[p,q] has been just removed) to p-th * column of matrix F (without unity diagonal element) */ len = vc_len[q]; if (len > 0) { if (sva->r_ptr - sva->m_ptr < len) { sva_more_space(sva, len); sv_ind = sva->ind; sv_val = sva->val; } sva_reserve_cap(sva, fc_ref-1+p, len); memcpy(&sv_ind[fc_ptr[p]], &sv_ind[vc_ptr[q]], len * sizeof(int)); fc_len[p] = len; } /* make q-th column of the active submatrix empty */ vc_len[q] = 0; /* transform non-pivot rows of the active submatrix */ for (loc = fc_len[p]-1; loc >= 0; loc--) { /* get row index of v[i,q] = row index of f[i,p] */ i = sv_ind[fc_ptr[p] + loc]; xassert(i != p); /* v[p,q] was removed */ /* remove i-th row from the active set; this row will return * there with new length */ sgf_deactivate_row(i); /* find v[i,q] in i-th row */ for (i_end = (i_ptr = vr_ptr[i]) + vr_len[i]; sv_ind[i_ptr] != q; i_ptr++) /* nop */; xassert(i_ptr < i_end); /* compute gaussian multiplier f[i,p] = v[i,q] / v[p,q] */ fip = sv_val[fc_ptr[p] + loc] = sv_val[i_ptr] / vpq; /* remove v[i,q] from i-th row */ sv_ind[i_ptr] = sv_ind[i_end-1]; sv_val[i_ptr] = sv_val[i_end-1]; vr_len[i]--; /* perform elementary gaussian transformation: * (i-th row) := (i-th row) - f[i,p] * (p-th row) * note that p-th row of V, which is in the working array, * doesn't contain pivot v[p,q], and i-th row of V doesn't * contain v[i,q] to be eliminated */ /* walk thru i-th row and transform existing elements */ fill = vr_len[p]; for (i_end = (i_ptr = ptr = vr_ptr[i]) + vr_len[i]; i_ptr < i_end; i_ptr++) { /* get column index and value of v[i,j] */ j = sv_ind[i_ptr]; vij = sv_val[i_ptr]; if (flag[j]) { /* v[p,j] != 0 */ flag[j] = 0, fill--; /* v[i,j] := v[i,j] - f[i,p] * v[p,j] */ vij -= fip * work[j]; if (-eps_tol < vij && vij < +eps_tol) { /* new v[i,j] is close to zero; remove it from the * active submatrix, i.e. replace it by exact zero */ /* find and remove v[i,j] from j-th column */ for (j_end = (j_ptr = vc_ptr[j]) + vc_len[j]; sv_ind[j_ptr] != i; j_ptr++) /* nop */; xassert(j_ptr < j_end); sv_ind[j_ptr] = sv_ind[j_end-1]; vc_len[j]--; continue; } } /* keep new v[i,j] in i-th row */ sv_ind[ptr] = j; sv_val[ptr] = vij; ptr++; } /* (new length of i-th row may decrease because of numerical * cancellation) */ vr_len[i] = len = ptr - vr_ptr[i]; /* now flag[*] is the pattern of the set v[p,*] \ v[i,*], and * fill is the number of non-zeros in this set */ if (fill == 0) { /* no fill-in occurs */ /* walk thru p-th row and restore the column flags */ for (i_end = (i_ptr = vr_ptr[p]) + vr_len[p]; i_ptr < i_end; i_ptr++) flag[sv_ind[i_ptr]] = 1; /* v[p,j] != 0 */ goto skip; } /* up to fill new non-zero elements may appear in i-th row due * to fill-in; reserve locations for these elements (note that * actual length of i-th row is currently stored in len) */ if (vr_cap[i] < len + fill) { if (sva->r_ptr - sva->m_ptr < len + fill) { sva_more_space(sva, len + fill); sv_ind = sva->ind; sv_val = sva->val; } sva_enlarge_cap(sva, vr_ref-1+i, len + fill, 0); } vr_len[i] += fill; /* walk thru p-th row and add new elements to i-th row */ for (loc1 = vr_len[p]-1; loc1 >= 0; loc1--) { /* get column index of v[p,j] */ j = sv_ind[vr_ptr[p] + loc1]; if (!flag[j]) { /* restore j-th column flag */ flag[j] = 1; /* v[i,j] was computed earlier on transforming existing * elements of i-th row */ continue; } /* v[i,j] := 0 - f[i,p] * v[p,j] */ vij = - fip * work[j]; if (-eps_tol < vij && vij < +eps_tol) { /* new v[i,j] is close to zero; do not add it to the * active submatrix, i.e. replace it by exact zero */ continue; } /* add new v[i,j] to i-th row */ sv_ind[ptr = vr_ptr[i] + (len++)] = j; sv_val[ptr] = vij; /* add new v[i,j] to j-th column */ if (vc_cap[j] == vc_len[j]) { /* we reserve extra locations in j-th column to reduce * further relocations of that column */ #if 1 /* FIXME */ /* use control parameter to specify the number of extra * locations reserved */ int need = vc_len[j] + 10; #endif if (sva->r_ptr - sva->m_ptr < need) { sva_more_space(sva, need); sv_ind = sva->ind; sv_val = sva->val; } sva_enlarge_cap(sva, vc_ref-1+j, need, 1); } sv_ind[vc_ptr[j] + (vc_len[j]++)] = i; } /* set final length of i-th row just transformed */ xassert(len <= vr_len[i]); vr_len[i] = len; skip: /* return i-th row to the active set with new length */ sgf_activate_row(i); /* since i-th row has been changed, largest magnitude of its * elements becomes unknown */ vr_max[i] = -1.0; } /* walk thru p-th (pivot) row */ for (i_end = (i_ptr = vr_ptr[p]) + vr_len[p]; i_ptr < i_end; i_ptr++) { /* get column index of v[p,j] */ j = sv_ind[i_ptr]; xassert(j != q); /* v[p,q] was removed */ /* return j-th column to the active set with new length */ if (cs_next[j] == j && vc_len[j] != 1) { /* j-th column was marked by the pivoting routine and it is * still not a column singleton, so leave it incative */ xassert(cs_prev[j] == j); } else sgf_activate_col(j); nnz_diff += vc_len[j]; /* restore zero content of the working arrays */ flag[j] = 0; work[j] = 0.0; } /* return the difference between the numbers of non-zeros in the * active submatrix on entry and on exit, resp. */ return nnz_diff; } /*********************************************************************** * sgf_dense_lu - compute dense LU-factorization with full pivoting * * This routine performs Gaussian elimination with full pivoting to * compute dense LU-factorization of the specified matrix A of order n * in the form: * * A = P * L * U * Q, (1) * * where L is lower triangular matrix with unit diagonal, U is upper * triangular matrix, P and Q are permutation matrices. * * On entry to the routine elements of matrix A = (a[i,j]) should be * placed in the array elements a[0], ..., a[n^2-1] in dense row-wise * format. On exit from the routine matrix A is replaced by factors L * and U as follows: * * u[1,1] u[1,2] ... u[1,n-1] u[1,n] * l[2,1] u[2,2] ... u[2,n-1] u[2,n] * . . . . . . . . . . . . . . * l[n-1,1] l[n-1,2] u[n-1,n-1] u[n-1,n] * l[n,1] l[n,2] ... l[n,n-1] u[n,n] * * The unit diagonal elements of L are not stored. * * Information on permutations of rows and columns of active submatrix * during factorization is accumulated by the routine as follows. Every * time the routine permutes rows i and i' or columns j and j', it also * permutes elements r[i-1] and r[i'-1] or c[j-1] and c[j'-1], resp. * Thus, on entry to the routine elements r[0], r[1], ..., r[n-1] and * c[0], c[1], ..., c[n-1] should be initialized by some integers that * identify rows and columns of the original matrix A. * * If the factorization has been successfully computed, the routine * returns zero. Otherwise, if on k-th elimination step, 1 <= k <= n, * all elements of the active submatrix are close to zero, the routine * returns k, in which case a partial factorization is stored in the * array a. */ int sgf_dense_lu(int n, double a_[], int r[], int c[], double eps) { /* non-optimized version */ int i, j, k, p, q, ref; double akk, big, temp; # define a(i,j) a_[(i)*n+(j)] /* initially U = A, L = P = Q = I */ /* main elimination loop */ for (k = 0; k < n; k++) { /* choose pivot u[p,q], k <= p, q <= n */ p = q = -1, big = eps; for (i = k; i < n; i++) { for (j = k; j < n; j++) { /* temp = |u[i,j]| */ if ((temp = a(i,j)) < 0.0) temp = -temp; if (big < temp) p = i, q = j, big = temp; } } if (p < 0) { /* k-th elimination step failed */ return k+1; } /* permute rows k and p */ if (k != p) { for (j = 0; j < n; j++) temp = a(k,j), a(k,j) = a(p,j), a(p,j) = temp; ref = r[k], r[k] = r[p], r[p] = ref; } /* permute columns k and q */ if (k != q) { for (i = 0; i < n; i++) temp = a(i,k), a(i,k) = a(i,q), a(i,q) = temp; ref = c[k], c[k] = c[q], c[q] = ref; } /* now pivot is in position u[k,k] */ akk = a(k,k); /* eliminate subdiagonal elements u[k+1,k], ..., u[n,k] */ for (i = k+1; i < n; i++) { if (a(i,k) != 0.0) { /* gaussian multiplier l[i,k] := u[i,k] / u[k,k] */ temp = (a(i,k) /= akk); /* (i-th row) := (i-th row) - l[i,k] * (k-th row) */ for (j = k+1; j < n; j++) a(i,j) -= temp * a(k,j); } } } # undef a return 0; } /*********************************************************************** * sgf_dense_phase - compute LU-factorization (dense phase) * * This routine performs dense phase of computing LU-factorization. * * The aim is two-fold. First, the main factorization routine switches * to dense phase when the active submatrix is relatively dense, so * using dense format allows significantly reduces overheads needed to * maintain sparse data structures. And second, that is more important, * on dense phase full pivoting is used (rather than partial pivoting) * that allows improving numerical stability, since round-off errors * tend to increase on last steps of the elimination process. * * On entry the routine assumes that elimination steps 1, 2, ..., k-1 * have been performed, so partially transformed matrices L = P'* F * P * and U = P'* V * Q' have the following structure: * * 1 k n 1 k n * 1 1 . . . . . . . . . 1 x x x x x x x x x x * x 1 . . . . . . . . . x x x x x x x x x * x x 1 . . . . . . . . . x x x x x x x x * x x x 1 . . . . . . . . . x x x x x x x * k x x x x 1 . . . . . k . . . . * * * * * * * x x x x . 1 . . . . . . . . * * * * * * * x x x x . . 1 . . . . . . . * * * * * * * x x x x . . . 1 . . . . . . * * * * * * * x x x x . . . . 1 . . . . . * * * * * * * n x x x x . . . . . 1 n . . . . * * * * * * * * matrix L matrix U * * where rows and columns k, k+1, ..., n of matrix U constitute the * active submatrix A~, whose elements are marked by '*'. * * The routine copies the active submatrix A~ to a working array in * dense format, compute dense factorization A~ = P~* L~* U~* Q~ using * full pivoting, and then copies non-zero elements of factors L~ and * U~ back to factors L and U (more precisely, to factors F and V). * * If the factorization has been successfully computed, the routine * returns zero. Otherwise, if on k-th elimination step, 1 <= k <= n, * all elements of the active submatrix are close to zero, the routine * returns k (information on linearly dependent rows/columns in this * case is provided by matrices P and Q). */ int sgf_dense_phase(LUF *luf, int k, int updat) { int n = luf->n; SVA *sva = luf->sva; int *sv_ind = sva->ind; double *sv_val = sva->val; int fc_ref = luf->fc_ref; int *fc_ptr = &sva->ptr[fc_ref-1]; int *fc_len = &sva->len[fc_ref-1]; int *fc_cap = &sva->cap[fc_ref-1]; int vr_ref = luf->vr_ref; int *vr_ptr = &sva->ptr[vr_ref-1]; int *vr_len = &sva->len[vr_ref-1]; int *vr_cap = &sva->cap[vr_ref-1]; double *vr_piv = luf->vr_piv; int vc_ref = luf->vc_ref; int *vc_len = &sva->len[vc_ref-1]; int *pp_inv = luf->pp_inv; int *pp_ind = luf->pp_ind; int *qq_ind = luf->qq_ind; int *qq_inv = luf->qq_inv; int a_end, a_ptr, end, i, ia, ii, j, ja, jj, ka, len, na, ne, need, ptr; double *a_; xassert(1 <= k && k <= n); /* active columns of V are not longer needed; make them empty */ for (jj = k; jj <= n; jj++) { /* jj is number of active column of U = P'* V * Q' */ vc_len[qq_ind[jj]] = 0; } /* determine order of active submatrix A~ of matrix U */ na = n - k + 1; xassert(1 <= na && na <= n); /* determine number of elements in dense triangular factor (L~ or * U~), except diagonal elements */ ne = na * (na - 1) / 2; /* we allocate active submatrix A~ in free (middle) part of SVA; * to avoid defragmentation that could destroy A~ we also should * reserve ne locations to build rows of V from rows of U~ and ne * locations to build columns of F from columns of L~ */ need = na * na + ne + ne; if (sva->r_ptr - sva->m_ptr < need) { sva_more_space(sva, need); sv_ind = sva->ind; sv_val = sva->val; } /* free (middle) part of SVA is structured as follows: * end of left (dynamic) part * ne free locations for new rows of V * na free locations for active submatrix A~ * unused locations, if any * ne free locations for new columns of F * beginning of right (static) part */ a_ptr = sva->m_ptr + ne; a_end = a_ptr + na * na; /* copy active submatrix A~ from matrix V to working array in * dense row-wise format */ a_ = &sva->val[a_ptr]; # define a(ia, ja) a_[((ia) - 1) * na + ((ja) - 1)] for (ia = 1; ia <= na; ia++) { /* clear ia-th row of A~ */ for (ja = 1; ja <= na; ja++) a(ia, ja) = 0.0; /* ia-th row of A~ = (k-1+ia)-th row of U = i-th row of V */ i = pp_inv[k-1+ia]; ptr = vr_ptr[i]; end = ptr + vr_len[i]; for (; ptr < end; ptr++) a(ia, qq_inv[sv_ind[ptr]]-k+1) = sv_val[ptr]; /* i-th row of V is no longer needed; make it empty */ vr_len[i] = 0; } /* compute dense factorization A~ = P~* L~* U~* Q~ */ #if 1 /* FIXME: epsilon tolerance */ ka = sgf_dense_lu(na, &a(1, 1), &pp_inv[k], &qq_ind[k], 1e-20); #endif /* rows of U with numbers pp_inv[k, k+1, ..., n] were permuted * due to row permutations of A~; update matrix P using P~ */ for (ii = k; ii <= n; ii++) pp_ind[pp_inv[ii]] = ii; /* columns of U with numbers qq_ind[k, k+1, ..., n] were permuted * due to column permutations of A~; update matrix Q using Q~ */ for (jj = k; jj <= n; jj++) qq_inv[qq_ind[jj]] = jj; /* check if dense factorization is complete */ if (ka != 0) { /* A~ is singular to working precision */ /* information on linearly dependent rows/columns is provided * by matrices P and Q */ xassert(1 <= ka && ka <= na); return k - 1 + ka; } /* build new rows of V from rows of U~ */ for (ia = 1; ia <= na; ia++) { /* ia-th row of U~ = (k-1+ia)-th row of U = i-th row of V */ i = pp_inv[k-1+ia]; xassert(vr_len[i] == 0); /* store diagonal element u~[ia,ia] */ vr_piv[i] = a(ia, ia); /* determine number of non-zero non-diagonal elements in ia-th row of U~ */ len = 0; for (ja = ia+1; ja <= na; ja++) { if (a(ia, ja) != 0.0) len++; } /* reserve len locations for i-th row of matrix V in left * (dynamic) part of SVA */ if (vr_cap[i] < len) { /* there should be enough room in free part of SVA */ xassert(sva->r_ptr - sva->m_ptr >= len); sva_enlarge_cap(sva, vr_ref-1+i, len, 0); /* left part of SVA should not overlap matrix A~ */ xassert(sva->m_ptr <= a_ptr); } /* copy non-zero non-diaginal elements of ia-th row of U~ to * i-th row of V */ ptr = vr_ptr[i]; for (ja = ia+1; ja <= na; ja++) { if (a(ia, ja) != 0.0) { sv_ind[ptr] = qq_ind[k-1+ja]; sv_val[ptr] = a(ia, ja); ptr++; } } xassert(ptr - vr_ptr[i] == len); vr_len[i] = len; } /* build new columns of F from columns of L~ */ for (ja = 1; ja <= na; ja++) { /* ja-th column of L~ = (k-1+ja)-th column of L = j-th column * of F */ j = pp_inv[k-1+ja]; xassert(fc_len[j] == 0); xassert(fc_cap[j] == 0); /* determine number of non-zero non-diagonal elements in ja-th * column of L~ */ len = 0; for (ia = ja+1; ia <= na; ia++) { if (a(ia, ja) != 0.0) len++; } /* reserve len locations for j-th column of matrix F in right * (static) part of SVA */ /* there should be enough room in free part of SVA */ xassert(sva->r_ptr - sva->m_ptr >= len); if (len > 0) sva_reserve_cap(sva, fc_ref-1+j, len); /* right part of SVA should not overlap matrix A~ */ xassert(a_end <= sva->r_ptr); /* copy non-zero non-diagonal elements of ja-th column of L~ * to j-th column of F */ ptr = fc_ptr[j]; for (ia = ja+1; ia <= na; ia++) { if (a(ia, ja) != 0.0) { sv_ind[ptr] = pp_inv[k-1+ia]; sv_val[ptr] = a(ia, ja); ptr++; } } xassert(ptr - fc_ptr[j] == len); fc_len[j] = len; } /* factors L~ and U~ are no longer needed */ # undef a /* if it is not planned to update matrix V, relocate all its new * rows to the right (static) part of SVA */ if (!updat) { for (ia = 1; ia <= na; ia++) { i = pp_inv[k-1+ia]; len = vr_len[i]; if (sva->r_ptr - sva->m_ptr < len) { sva_more_space(sva, len); sv_ind = sva->ind; sv_val = sva->val; } sva_make_static(sva, vr_ref-1+i); } } return 0; } /*********************************************************************** * sgf_factorize - compute LU-factorization (main routine) * * This routine computes sparse LU-factorization of specified matrix A * using Gaussian elimination. * * On entry to the routine matrix V = A should be stored in column-wise * format. * * If the factorization has been successfully computed, the routine * returns zero. Otherwise, if on k-th elimination step, 1 <= k <= n, * all elements of the active submatrix are close to zero, the routine * returns k (information on linearly dependent rows/columns in this * case is provided by matrices P and Q). */ int sgf_factorize(SGF *sgf, int singl) { LUF *luf = sgf->luf; int n = luf->n; SVA *sva = luf->sva; int vr_ref = luf->vr_ref; int *vr_len = &sva->len[vr_ref-1]; double *vr_piv = luf->vr_piv; int vc_ref = luf->vc_ref; int *vc_len = &sva->len[vc_ref-1]; int *pp_ind = luf->pp_ind; int *pp_inv = luf->pp_inv; int *qq_ind = luf->qq_ind; int *qq_inv = luf->qq_inv; int *rs_head = sgf->rs_head; int *rs_prev = sgf->rs_prev; int *rs_next = sgf->rs_next; int *cs_head = sgf->cs_head; int *cs_prev = sgf->cs_prev; int *cs_next = sgf->cs_next; double *vr_max = sgf->vr_max; char *flag = sgf->flag; double *work = sgf->work; int i, j, k, k1, k2, p, q, nnz; /* build matrix V = A in row-wise format */ luf_build_v_rows(luf, rs_prev); /* P := Q := I, so V = U = A, F = L = I */ for (k = 1; k <= n; k++) { vr_piv[k] = 0.0; pp_ind[k] = pp_inv[k] = qq_ind[k] = qq_inv[k] = k; } #ifdef GLP_DEBUG sva_check_area(sva); luf_check_all(luf, 1); #endif /* perform singleton phase, if required */ if (!singl) { /* assume that nucleus is entire matrix U */ k2 = 1; } else { /* minimize nucleus size */ sgf_reduce_nuc(luf, &k1, &k2, rs_prev, rs_next); #ifdef GLP_DEBUG xprintf("n = %d; k1 = %d; k2 = %d\n", n, k1, k2); #endif /* perform singleton phase */ k2 = sgf_singl_phase(luf, k1, k2, sgf->updat, rs_prev, work); } #ifdef GLP_DEBUG sva_check_area(sva); luf_check_all(luf, k2); #endif /* initialize working arrays */ rs_head[0] = cs_head[0] = 0; for (k = 1; k <= n; k++) { rs_head[k] = cs_head[k] = 0; vr_max[k] = -1.0; flag[k] = 0; work[k] = 0.0; } /* build lists of active rows and columns of matrix V; determine * number of non-zeros in initial active submatrix */ nnz = 0; for (k = k2; k <= n; k++) { i = pp_inv[k]; sgf_activate_row(i); nnz += vr_len[i]; j = qq_ind[k]; sgf_activate_col(j); } /* main factorization loop */ for (k = k2; k <= n; k++) { int na; double den; /* calculate density of active submatrix */ na = n - k + 1; /* order of active submatrix */ den = (double)nnz / (double)(na * na); /* if active submatrix is relatively dense, switch to dense * phase */ #if 1 /* FIXME */ if (na >= 5 && den >= 0.71) { #ifdef GLP_DEBUG xprintf("na = %d; nnz = %d; den = %g\n", na, nnz, den); #endif break; } #endif /* choose pivot v[p,q] */ if (sgf_choose_pivot(sgf, &p, &q) != 0) return k; /* failure */ /* u[i,j] = v[p,q], k <= i, j <= n */ i = pp_ind[p]; xassert(k <= i && i <= n); j = qq_inv[q]; xassert(k <= j && j <= n); /* move u[i,j] to position u[k,k] by implicit permutations of * rows and columns of matrix U */ luf_swap_u_rows(k, i); luf_swap_u_cols(k, j); /* perform gaussian elimination */ nnz += sgf_eliminate(sgf, p, q); } #if 1 /* FIXME */ if (k <= n) { /* continue computing factorization in dense mode */ #ifdef GLP_DEBUG sva_check_area(sva); luf_check_all(luf, k); #endif k = sgf_dense_phase(luf, k, sgf->updat); if (k != 0) return k; /* failure */ } #endif #ifdef GLP_DEBUG sva_check_area(sva); luf_check_all(luf, n+1); #endif /* defragment SVA; currently all columns of V are empty, so they * will have zero capacity as required by luf_build_v_cols */ sva_defrag_area(sva); /* build matrix F in row-wise format */ luf_build_f_rows(luf, rs_head); /* build matrix V in column-wise format */ luf_build_v_cols(luf, sgf->updat, rs_head); return 0; } /* eof */ Rglpk/src/GLPK/glpcpx.c0000644000176000001440000012553712245352174014370 0ustar ripleyusers/* glpcpx.c (CPLEX LP format routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #if 1 /* 11/VI-2013 */ #include "env2.h" #endif #include "glpapi.h" #include "glplib.h" /*********************************************************************** * NAME * * glp_init_cpxcp - initialize CPLEX LP format control parameters * * SYNOPSIS * * void glp_init_cpxcp(glp_cpxcp *parm): * * The routine glp_init_cpxcp initializes control parameters used by * the CPLEX LP input/output routines glp_read_lp and glp_write_lp with * default values. * * Default values of the control parameters are stored in the glp_cpxcp * structure, which the parameter parm points to. */ void glp_init_cpxcp(glp_cpxcp *parm) { xassert(parm != NULL); return; } static void check_parm(const char *func, const glp_cpxcp *parm) { /* check control parameters */ xassert(func != NULL); xassert(parm != NULL); return; } /*********************************************************************** * NAME * * glp_read_lp - read problem data in CPLEX LP format * * SYNOPSIS * * int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char * *fname); * * DESCRIPTION * * The routine glp_read_lp reads problem data in CPLEX LP format from * a text file. * * The parameter parm is a pointer to the structure glp_cpxcp, which * specifies control parameters used by the routine. If parm is NULL, * the routine uses default settings. * * The character string fname specifies a name of the text file to be * read. * * Note that before reading data the current content of the problem * object is completely erased with the routine glp_erase_prob. * * RETURNS * * If the operation was successful, the routine glp_read_lp returns * zero. Otherwise, it prints an error message and returns non-zero. */ struct csa { /* common storage area */ glp_prob *P; /* LP/MIP problem object */ const glp_cpxcp *parm; /* pointer to control parameters */ const char *fname; /* name of input CPLEX LP file */ XFILE *fp; /* stream assigned to input CPLEX LP file */ jmp_buf jump; /* label for go to in case of error */ int count; /* line count */ int c; /* current character or XEOF */ int token; /* current token: */ #define T_EOF 0x00 /* end of file */ #define T_MINIMIZE 0x01 /* keyword 'minimize' */ #define T_MAXIMIZE 0x02 /* keyword 'maximize' */ #define T_SUBJECT_TO 0x03 /* keyword 'subject to' */ #define T_BOUNDS 0x04 /* keyword 'bounds' */ #define T_GENERAL 0x05 /* keyword 'general' */ #define T_INTEGER 0x06 /* keyword 'integer' */ #define T_BINARY 0x07 /* keyword 'binary' */ #define T_END 0x08 /* keyword 'end' */ #define T_NAME 0x09 /* symbolic name */ #define T_NUMBER 0x0A /* numeric constant */ #define T_PLUS 0x0B /* delimiter '+' */ #define T_MINUS 0x0C /* delimiter '-' */ #define T_COLON 0x0D /* delimiter ':' */ #define T_LE 0x0E /* delimiter '<=' */ #define T_GE 0x0F /* delimiter '>=' */ #define T_EQ 0x10 /* delimiter '=' */ char image[255+1]; /* image of current token */ int imlen; /* length of token image */ double value; /* value of numeric constant */ int n_max; /* length of the following five arrays (enlarged automatically, if necessary) */ int *ind; /* int ind[1+n_max]; */ double *val; /* double val[1+n_max]; */ char *flag; /* char flag[1+n_max]; */ /* working arrays used to construct linear forms */ double *lb; /* double lb[1+n_max]; */ double *ub; /* double ub[1+n_max]; */ /* lower and upper bounds of variables (columns) */ #if 1 /* 27/VII-2013 */ int lb_warn, ub_warn; /* warning 'lower/upper bound redefined' already issued */ #endif }; #define CHAR_SET "!\"#$%&()/,.;?@_`'{}|~" /* characters, which may appear in symbolic names */ static void error(struct csa *csa, const char *fmt, ...) { /* print error message and terminate processing */ va_list arg; xprintf("%s:%d: ", csa->fname, csa->count); va_start(arg, fmt); xvprintf(fmt, arg); va_end(arg); longjmp(csa->jump, 1); /* no return */ } static void warning(struct csa *csa, const char *fmt, ...) { /* print warning message and continue processing */ va_list arg; xprintf("%s:%d: warning: ", csa->fname, csa->count); va_start(arg, fmt); xvprintf(fmt, arg); va_end(arg); return; } static void read_char(struct csa *csa) { /* read next character from input file */ int c; xassert(csa->c != XEOF); if (csa->c == '\n') csa->count++; c = xfgetc(csa->fp); if (c < 0) { if (xferror(csa->fp)) error(csa, "read error - %s\n", xerrmsg()); else if (csa->c == '\n') { csa->count--; c = XEOF; } else { warning(csa, "missing final end of line\n"); c = '\n'; } } else if (c == '\n') ; else if (isspace(c)) c = ' '; else if (iscntrl(c)) error(csa, "invalid control character 0x%02X\n", c); csa->c = c; return; } static void add_char(struct csa *csa) { /* append current character to current token */ if (csa->imlen == sizeof(csa->image)-1) error(csa, "token '%.15s...' too long\n", csa->image); csa->image[csa->imlen++] = (char)csa->c; csa->image[csa->imlen] = '\0'; read_char(csa); return; } static int the_same(char *s1, char *s2) { /* compare two character strings ignoring case sensitivity */ for (; *s1 != '\0'; s1++, s2++) { if (tolower((unsigned char)*s1) != tolower((unsigned char)*s2)) return 0; } return 1; } static void scan_token(struct csa *csa) { /* scan next token */ int flag; csa->token = -1; csa->image[0] = '\0'; csa->imlen = 0; csa->value = 0.0; loop: flag = 0; /* skip non-significant characters */ while (csa->c == ' ') read_char(csa); /* recognize and scan current token */ if (csa->c == XEOF) csa->token = T_EOF; else if (csa->c == '\n') { read_char(csa); /* if the next character is letter, it may begin a keyword */ if (isalpha(csa->c)) { flag = 1; goto name; } goto loop; } else if (csa->c == '\\') { /* comment; ignore everything until end-of-line */ while (csa->c != '\n') read_char(csa); goto loop; } else if (isalpha(csa->c) || csa->c != '.' && strchr(CHAR_SET, csa->c) != NULL) name: { /* symbolic name */ csa->token = T_NAME; while (isalnum(csa->c) || strchr(CHAR_SET, csa->c) != NULL) add_char(csa); if (flag) { /* check for keyword */ if (the_same(csa->image, "minimize")) csa->token = T_MINIMIZE; else if (the_same(csa->image, "minimum")) csa->token = T_MINIMIZE; else if (the_same(csa->image, "min")) csa->token = T_MINIMIZE; else if (the_same(csa->image, "maximize")) csa->token = T_MAXIMIZE; else if (the_same(csa->image, "maximum")) csa->token = T_MAXIMIZE; else if (the_same(csa->image, "max")) csa->token = T_MAXIMIZE; else if (the_same(csa->image, "subject")) { if (csa->c == ' ') { read_char(csa); if (tolower(csa->c) == 't') { csa->token = T_SUBJECT_TO; csa->image[csa->imlen++] = ' '; csa->image[csa->imlen] = '\0'; add_char(csa); if (tolower(csa->c) != 'o') error(csa, "keyword 'subject to' incomplete\n"); add_char(csa); if (isalpha(csa->c)) error(csa, "keyword '%s%c...' not recognized\n", csa->image, csa->c); } } } else if (the_same(csa->image, "such")) { if (csa->c == ' ') { read_char(csa); if (tolower(csa->c) == 't') { csa->token = T_SUBJECT_TO; csa->image[csa->imlen++] = ' '; csa->image[csa->imlen] = '\0'; add_char(csa); if (tolower(csa->c) != 'h') err: error(csa, "keyword 'such that' incomplete\n"); add_char(csa); if (tolower(csa->c) != 'a') goto err; add_char(csa); if (tolower(csa->c) != 't') goto err; add_char(csa); if (isalpha(csa->c)) error(csa, "keyword '%s%c...' not recognized\n", csa->image, csa->c); } } } else if (the_same(csa->image, "st")) csa->token = T_SUBJECT_TO; else if (the_same(csa->image, "s.t.")) csa->token = T_SUBJECT_TO; else if (the_same(csa->image, "st.")) csa->token = T_SUBJECT_TO; else if (the_same(csa->image, "bounds")) csa->token = T_BOUNDS; else if (the_same(csa->image, "bound")) csa->token = T_BOUNDS; else if (the_same(csa->image, "general")) csa->token = T_GENERAL; else if (the_same(csa->image, "generals")) csa->token = T_GENERAL; else if (the_same(csa->image, "gen")) csa->token = T_GENERAL; else if (the_same(csa->image, "integer")) csa->token = T_INTEGER; else if (the_same(csa->image, "integers")) csa->token = T_INTEGER; else if (the_same(csa->image, "int")) csa->token = T_INTEGER; else if (the_same(csa->image, "binary")) csa->token = T_BINARY; else if (the_same(csa->image, "binaries")) csa->token = T_BINARY; else if (the_same(csa->image, "bin")) csa->token = T_BINARY; else if (the_same(csa->image, "end")) csa->token = T_END; } } else if (isdigit(csa->c) || csa->c == '.') { /* numeric constant */ csa->token = T_NUMBER; /* scan integer part */ while (isdigit(csa->c)) add_char(csa); /* scan optional fractional part (it is mandatory, if there is no integer part) */ if (csa->c == '.') { add_char(csa); if (csa->imlen == 1 && !isdigit(csa->c)) error(csa, "invalid use of decimal point\n"); while (isdigit(csa->c)) add_char(csa); } /* scan optional decimal exponent */ if (csa->c == 'e' || csa->c == 'E') { add_char(csa); if (csa->c == '+' || csa->c == '-') add_char(csa); if (!isdigit(csa->c)) error(csa, "numeric constant '%s' incomplete\n", csa->image); while (isdigit(csa->c)) add_char(csa); } /* convert the numeric constant to floating-point */ if (str2num(csa->image, &csa->value)) error(csa, "numeric constant '%s' out of range\n", csa->image); } else if (csa->c == '+') csa->token = T_PLUS, add_char(csa); else if (csa->c == '-') csa->token = T_MINUS, add_char(csa); else if (csa->c == ':') csa->token = T_COLON, add_char(csa); else if (csa->c == '<') { csa->token = T_LE, add_char(csa); if (csa->c == '=') add_char(csa); } else if (csa->c == '>') { csa->token = T_GE, add_char(csa); if (csa->c == '=') add_char(csa); } else if (csa->c == '=') { csa->token = T_EQ, add_char(csa); if (csa->c == '<') csa->token = T_LE, add_char(csa); else if (csa->c == '>') csa->token = T_GE, add_char(csa); } else error(csa, "character '%c' not recognized\n", csa->c); /* skip non-significant characters */ while (csa->c == ' ') read_char(csa); return; } static int find_col(struct csa *csa, char *name) { /* find column by its symbolic name */ int j; j = glp_find_col(csa->P, name); if (j == 0) { /* not found; create new column */ j = glp_add_cols(csa->P, 1); glp_set_col_name(csa->P, j, name); /* enlarge working arrays, if necessary */ if (csa->n_max < j) { int n_max = csa->n_max; int *ind = csa->ind; double *val = csa->val; char *flag = csa->flag; double *lb = csa->lb; double *ub = csa->ub; csa->n_max += csa->n_max; csa->ind = xcalloc(1+csa->n_max, sizeof(int)); memcpy(&csa->ind[1], &ind[1], n_max * sizeof(int)); xfree(ind); csa->val = xcalloc(1+csa->n_max, sizeof(double)); memcpy(&csa->val[1], &val[1], n_max * sizeof(double)); xfree(val); csa->flag = xcalloc(1+csa->n_max, sizeof(char)); memset(&csa->flag[1], 0, csa->n_max * sizeof(char)); memcpy(&csa->flag[1], &flag[1], n_max * sizeof(char)); xfree(flag); csa->lb = xcalloc(1+csa->n_max, sizeof(double)); memcpy(&csa->lb[1], &lb[1], n_max * sizeof(double)); xfree(lb); csa->ub = xcalloc(1+csa->n_max, sizeof(double)); memcpy(&csa->ub[1], &ub[1], n_max * sizeof(double)); xfree(ub); } csa->lb[j] = +DBL_MAX, csa->ub[j] = -DBL_MAX; } return j; } /*********************************************************************** * parse_linear_form - parse linear form * * This routine parses the linear form using the following syntax: * * ::= * ::= * ::= | * ::= | + | - | * + | - * * The routine returns the number of terms in the linear form. */ static int parse_linear_form(struct csa *csa) { int j, k, len = 0, newlen; double s, coef; loop: /* parse an optional sign */ if (csa->token == T_PLUS) s = +1.0, scan_token(csa); else if (csa->token == T_MINUS) s = -1.0, scan_token(csa); else s = +1.0; /* parse an optional coefficient */ if (csa->token == T_NUMBER) coef = csa->value, scan_token(csa); else coef = 1.0; /* parse a variable name */ if (csa->token != T_NAME) error(csa, "missing variable name\n"); /* find the corresponding column */ j = find_col(csa, csa->image); /* check if the variable is already used in the linear form */ if (csa->flag[j]) error(csa, "multiple use of variable '%s' not allowed\n", csa->image); /* add new term to the linear form */ len++, csa->ind[len] = j, csa->val[len] = s * coef; /* and mark that the variable is used in the linear form */ csa->flag[j] = 1; scan_token(csa); /* if the next token is a sign, there is another term */ if (csa->token == T_PLUS || csa->token == T_MINUS) goto loop; /* clear marks of the variables used in the linear form */ for (k = 1; k <= len; k++) csa->flag[csa->ind[k]] = 0; /* remove zero coefficients */ newlen = 0; for (k = 1; k <= len; k++) { if (csa->val[k] != 0.0) { newlen++; csa->ind[newlen] = csa->ind[k]; csa->val[newlen] = csa->val[k]; } } return newlen; } /*********************************************************************** * parse_objective - parse objective function * * This routine parses definition of the objective function using the * following syntax: * * ::= minimize | minimum | min | maximize | maximum | max * ::= | : * ::= */ static void parse_objective(struct csa *csa) { /* parse objective sense */ int k, len; /* parse the keyword 'minimize' or 'maximize' */ if (csa->token == T_MINIMIZE) glp_set_obj_dir(csa->P, GLP_MIN); else if (csa->token == T_MAXIMIZE) glp_set_obj_dir(csa->P, GLP_MAX); else xassert(csa != csa); scan_token(csa); /* parse objective name */ if (csa->token == T_NAME && csa->c == ':') { /* objective name is followed by a colon */ glp_set_obj_name(csa->P, csa->image); scan_token(csa); xassert(csa->token == T_COLON); scan_token(csa); } else { /* objective name is not specified; use default */ glp_set_obj_name(csa->P, "obj"); } /* parse linear form */ len = parse_linear_form(csa); for (k = 1; k <= len; k++) glp_set_obj_coef(csa->P, csa->ind[k], csa->val[k]); return; } /*********************************************************************** * parse_constraints - parse constraints section * * This routine parses the constraints section using the following * syntax: * * ::= | : * ::= < | <= | =< | > | >= | => | = * ::= | + | * - * ::= * * ::= subject to | such that | st | s.t. | st. * ::= | * */ static void parse_constraints(struct csa *csa) { int i, len, type; double s; /* parse the keyword 'subject to' */ xassert(csa->token == T_SUBJECT_TO); scan_token(csa); loop: /* create new row (constraint) */ i = glp_add_rows(csa->P, 1); /* parse row name */ if (csa->token == T_NAME && csa->c == ':') { /* row name is followed by a colon */ if (glp_find_row(csa->P, csa->image) != 0) error(csa, "constraint '%s' multiply defined\n", csa->image); glp_set_row_name(csa->P, i, csa->image); scan_token(csa); xassert(csa->token == T_COLON); scan_token(csa); } else { /* row name is not specified; use default */ char name[50]; sprintf(name, "r.%d", csa->count); glp_set_row_name(csa->P, i, name); } /* parse linear form */ len = parse_linear_form(csa); glp_set_mat_row(csa->P, i, len, csa->ind, csa->val); /* parse constraint sense */ if (csa->token == T_LE) type = GLP_UP, scan_token(csa); else if (csa->token == T_GE) type = GLP_LO, scan_token(csa); else if (csa->token == T_EQ) type = GLP_FX, scan_token(csa); else error(csa, "missing constraint sense\n"); /* parse right-hand side */ if (csa->token == T_PLUS) s = +1.0, scan_token(csa); else if (csa->token == T_MINUS) s = -1.0, scan_token(csa); else s = +1.0; if (csa->token != T_NUMBER) error(csa, "missing right-hand side\n"); glp_set_row_bnds(csa->P, i, type, s * csa->value, s * csa->value); /* the rest of the current line must be empty */ if (!(csa->c == '\n' || csa->c == XEOF)) error(csa, "invalid symbol(s) beyond right-hand side\n"); scan_token(csa); /* if the next token is a sign, numeric constant, or a symbolic name, here is another constraint */ if (csa->token == T_PLUS || csa->token == T_MINUS || csa->token == T_NUMBER || csa->token == T_NAME) goto loop; return; } static void set_lower_bound(struct csa *csa, int j, double lb) { /* set lower bound of j-th variable */ if (csa->lb[j] != +DBL_MAX && !csa->lb_warn) { warning(csa, "lower bound of variable '%s' redefined\n", glp_get_col_name(csa->P, j)); csa->lb_warn = 1; } csa->lb[j] = lb; return; } static void set_upper_bound(struct csa *csa, int j, double ub) { /* set upper bound of j-th variable */ if (csa->ub[j] != -DBL_MAX && !csa->ub_warn) { warning(csa, "upper bound of variable '%s' redefined\n", glp_get_col_name(csa->P, j)); csa->ub_warn = 1; } csa->ub[j] = ub; return; } /*********************************************************************** * parse_bounds - parse bounds section * * This routine parses the bounds section using the following syntax: * * ::= * ::= infinity | inf * ::= | + | * - | + | - * ::= < | <= | =< * ::= > | >= | => * ::= | * | | * | = | free * ::= bounds | bound * ::= | * */ static void parse_bounds(struct csa *csa) { int j, lb_flag; double lb, s; /* parse the keyword 'bounds' */ xassert(csa->token == T_BOUNDS); scan_token(csa); loop: /* bound definition can start with a sign, numeric constant, or a symbolic name */ if (!(csa->token == T_PLUS || csa->token == T_MINUS || csa->token == T_NUMBER || csa->token == T_NAME)) goto done; /* parse bound definition */ if (csa->token == T_PLUS || csa->token == T_MINUS) { /* parse signed lower bound */ lb_flag = 1; s = (csa->token == T_PLUS ? +1.0 : -1.0); scan_token(csa); if (csa->token == T_NUMBER) lb = s * csa->value, scan_token(csa); else if (the_same(csa->image, "infinity") || the_same(csa->image, "inf")) { if (s > 0.0) error(csa, "invalid use of '+inf' as lower bound\n"); lb = -DBL_MAX, scan_token(csa); } else error(csa, "missing lower bound\n"); } else if (csa->token == T_NUMBER) { /* parse unsigned lower bound */ lb_flag = 1; lb = csa->value, scan_token(csa); } else { /* lower bound is not specified */ lb_flag = 0; } /* parse the token that should follow the lower bound */ if (lb_flag) { if (csa->token != T_LE) error(csa, "missing '<', '<=', or '=<' after lower bound\n") ; scan_token(csa); } /* parse variable name */ if (csa->token != T_NAME) error(csa, "missing variable name\n"); j = find_col(csa, csa->image); /* set lower bound */ if (lb_flag) set_lower_bound(csa, j, lb); scan_token(csa); /* parse the context that follows the variable name */ if (csa->token == T_LE) { /* parse upper bound */ scan_token(csa); if (csa->token == T_PLUS || csa->token == T_MINUS) { /* parse signed upper bound */ s = (csa->token == T_PLUS ? +1.0 : -1.0); scan_token(csa); if (csa->token == T_NUMBER) { set_upper_bound(csa, j, s * csa->value); scan_token(csa); } else if (the_same(csa->image, "infinity") || the_same(csa->image, "inf")) { if (s < 0.0) error(csa, "invalid use of '-inf' as upper bound\n"); set_upper_bound(csa, j, +DBL_MAX); scan_token(csa); } else error(csa, "missing upper bound\n"); } else if (csa->token == T_NUMBER) { /* parse unsigned upper bound */ set_upper_bound(csa, j, csa->value); scan_token(csa); } else error(csa, "missing upper bound\n"); } else if (csa->token == T_GE) { /* parse lower bound */ if (lb_flag) { /* the context '... <= x >= ...' is invalid */ error(csa, "invalid bound definition\n"); } scan_token(csa); if (csa->token == T_PLUS || csa->token == T_MINUS) { /* parse signed lower bound */ s = (csa->token == T_PLUS ? +1.0 : -1.0); scan_token(csa); if (csa->token == T_NUMBER) { set_lower_bound(csa, j, s * csa->value); scan_token(csa); } else if (the_same(csa->image, "infinity") || the_same(csa->image, "inf") == 0) { if (s > 0.0) error(csa, "invalid use of '+inf' as lower bound\n"); set_lower_bound(csa, j, -DBL_MAX); scan_token(csa); } else error(csa, "missing lower bound\n"); } else if (csa->token == T_NUMBER) { /* parse unsigned lower bound */ set_lower_bound(csa, j, csa->value); scan_token(csa); } else error(csa, "missing lower bound\n"); } else if (csa->token == T_EQ) { /* parse fixed value */ if (lb_flag) { /* the context '... <= x = ...' is invalid */ error(csa, "invalid bound definition\n"); } scan_token(csa); if (csa->token == T_PLUS || csa->token == T_MINUS) { /* parse signed fixed value */ s = (csa->token == T_PLUS ? +1.0 : -1.0); scan_token(csa); if (csa->token == T_NUMBER) { set_lower_bound(csa, j, s * csa->value); set_upper_bound(csa, j, s * csa->value); scan_token(csa); } else error(csa, "missing fixed value\n"); } else if (csa->token == T_NUMBER) { /* parse unsigned fixed value */ set_lower_bound(csa, j, csa->value); set_upper_bound(csa, j, csa->value); scan_token(csa); } else error(csa, "missing fixed value\n"); } else if (the_same(csa->image, "free")) { /* parse the keyword 'free' */ if (lb_flag) { /* the context '... <= x free ...' is invalid */ error(csa, "invalid bound definition\n"); } set_lower_bound(csa, j, -DBL_MAX); set_upper_bound(csa, j, +DBL_MAX); scan_token(csa); } else if (!lb_flag) { /* neither lower nor upper bounds are specified */ error(csa, "invalid bound definition\n"); } goto loop; done: return; } /*********************************************************************** * parse_integer - parse general, integer, or binary section * * ::= * ::= general | generals | gen * ::= integer | integers | int * ::= binary | binaries | bin *
::= * ::=
| * */ static void parse_integer(struct csa *csa) { int j, binary; /* parse the keyword 'general', 'integer', or 'binary' */ if (csa->token == T_GENERAL) binary = 0, scan_token(csa); else if (csa->token == T_INTEGER) binary = 0, scan_token(csa); else if (csa->token == T_BINARY) binary = 1, scan_token(csa); else xassert(csa != csa); /* parse list of variables (may be empty) */ while (csa->token == T_NAME) { /* find the corresponding column */ j = find_col(csa, csa->image); /* change kind of the variable */ glp_set_col_kind(csa->P, j, GLP_IV); /* set 0-1 bounds for the binary variable */ if (binary) { set_lower_bound(csa, j, 0.0); set_upper_bound(csa, j, 1.0); } scan_token(csa); } return; } int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname) { /* read problem data in CPLEX LP format */ glp_cpxcp _parm; struct csa _csa, *csa = &_csa; int ret; xprintf("Reading problem data from '%s'...\n", fname); if (parm == NULL) glp_init_cpxcp(&_parm), parm = &_parm; /* check control parameters */ check_parm("glp_read_lp", parm); /* initialize common storage area */ csa->P = P; csa->parm = parm; csa->fname = fname; csa->fp = NULL; if (setjmp(csa->jump)) { ret = 1; goto done; } csa->count = 0; csa->c = '\n'; csa->token = T_EOF; csa->image[0] = '\0'; csa->imlen = 0; csa->value = 0.0; csa->n_max = 100; csa->ind = xcalloc(1+csa->n_max, sizeof(int)); csa->val = xcalloc(1+csa->n_max, sizeof(double)); csa->flag = xcalloc(1+csa->n_max, sizeof(char)); memset(&csa->flag[1], 0, csa->n_max * sizeof(char)); csa->lb = xcalloc(1+csa->n_max, sizeof(double)); csa->ub = xcalloc(1+csa->n_max, sizeof(double)); #if 1 /* 27/VII-2013 */ csa->lb_warn = csa->ub_warn = 0; #endif /* erase problem object */ glp_erase_prob(P); glp_create_index(P); /* open input CPLEX LP file */ csa->fp = xfopen(fname, "r"); if (csa->fp == NULL) { xprintf("Unable to open '%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } /* scan very first token */ scan_token(csa); /* parse definition of the objective function */ if (!(csa->token == T_MINIMIZE || csa->token == T_MAXIMIZE)) error(csa, "'minimize' or 'maximize' keyword missing\n"); parse_objective(csa); /* parse constraints section */ if (csa->token != T_SUBJECT_TO) error(csa, "constraints section missing\n"); parse_constraints(csa); /* parse optional bounds section */ if (csa->token == T_BOUNDS) parse_bounds(csa); /* parse optional general, integer, and binary sections */ while (csa->token == T_GENERAL || csa->token == T_INTEGER || csa->token == T_BINARY) parse_integer(csa); /* check for the keyword 'end' */ if (csa->token == T_END) scan_token(csa); else if (csa->token == T_EOF) warning(csa, "keyword 'end' missing\n"); else error(csa, "symbol '%s' in wrong position\n", csa->image); /* nothing must follow the keyword 'end' (except comments) */ if (csa->token != T_EOF) error(csa, "extra symbol(s) detected beyond 'end'\n"); /* set bounds of variables */ { int j, type; double lb, ub; for (j = 1; j <= P->n; j++) { lb = csa->lb[j]; ub = csa->ub[j]; if (lb == +DBL_MAX) lb = 0.0; /* default lb */ if (ub == -DBL_MAX) ub = +DBL_MAX; /* default ub */ if (lb == -DBL_MAX && ub == +DBL_MAX) type = GLP_FR; else if (ub == +DBL_MAX) type = GLP_LO; else if (lb == -DBL_MAX) type = GLP_UP; else if (lb != ub) type = GLP_DB; else type = GLP_FX; glp_set_col_bnds(csa->P, j, type, lb, ub); } } /* print some statistics */ xprintf("%d row%s, %d column%s, %d non-zero%s\n", P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s", P->nnz, P->nnz == 1 ? "" : "s"); if (glp_get_num_int(P) > 0) { int ni = glp_get_num_int(P); int nb = glp_get_num_bin(P); if (ni == 1) { if (nb == 0) xprintf("One variable is integer\n"); else xprintf("One variable is binary\n"); } else { xprintf("%d integer variables, ", ni); if (nb == 0) xprintf("none"); else if (nb == 1) xprintf("one"); else if (nb == ni) xprintf("all"); else xprintf("%d", nb); xprintf(" of which %s binary\n", nb == 1 ? "is" : "are"); } } xprintf("%d lines were read\n", csa->count); /* problem data has been successfully read */ glp_delete_index(P); glp_sort_matrix(P); ret = 0; done: if (csa->fp != NULL) xfclose(csa->fp); xfree(csa->ind); xfree(csa->val); xfree(csa->flag); xfree(csa->lb); xfree(csa->ub); if (ret != 0) glp_erase_prob(P); return ret; } /*********************************************************************** * NAME * * glp_write_lp - write problem data in CPLEX LP format * * SYNOPSIS * * int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char * *fname); * * DESCRIPTION * * The routine glp_write_lp writes problem data in CPLEX LP format to * a text file. * * The parameter parm is a pointer to the structure glp_cpxcp, which * specifies control parameters used by the routine. If parm is NULL, * the routine uses default settings. * * The character string fname specifies a name of the text file to be * written. * * RETURNS * * If the operation was successful, the routine glp_write_lp returns * zero. Otherwise, it prints an error message and returns non-zero. */ #define csa csa1 struct csa { /* common storage area */ glp_prob *P; /* pointer to problem object */ const glp_cpxcp *parm; /* pointer to control parameters */ }; static int check_name(char *name) { /* check if specified name is valid for CPLEX LP format */ if (*name == '.') return 1; if (isdigit((unsigned char)*name)) return 1; for (; *name; name++) { if (!isalnum((unsigned char)*name) && strchr(CHAR_SET, (unsigned char)*name) == NULL) return 1; } return 0; /* name is ok */ } static void adjust_name(char *name) { /* attempt to adjust specified name to make it valid for CPLEX LP format */ for (; *name; name++) { if (*name == ' ') *name = '_'; else if (*name == '-') *name = '~'; else if (*name == '[') *name = '('; else if (*name == ']') *name = ')'; } return; } static char *row_name(struct csa *csa, int i, char rname[255+1]) { /* construct symbolic name of i-th row (constraint) */ const char *name; if (i == 0) name = glp_get_obj_name(csa->P); else name = glp_get_row_name(csa->P, i); if (name == NULL) goto fake; strcpy(rname, name); adjust_name(rname); if (check_name(rname)) goto fake; return rname; fake: if (i == 0) strcpy(rname, "obj"); else sprintf(rname, "r_%d", i); return rname; } static char *col_name(struct csa *csa, int j, char cname[255+1]) { /* construct symbolic name of j-th column (variable) */ const char *name; name = glp_get_col_name(csa->P, j); if (name == NULL) goto fake; strcpy(cname, name); adjust_name(cname); if (check_name(cname)) goto fake; return cname; fake: sprintf(cname, "x_%d", j); return cname; } int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname) { /* write problem data in CPLEX LP format */ glp_cpxcp _parm; struct csa _csa, *csa = &_csa; XFILE *fp; GLPROW *row; GLPCOL *col; GLPAIJ *aij; int i, j, len, flag, count, ret; char line[1000+1], term[500+1], name[255+1]; xprintf("Writing problem data to '%s'...\n", fname); if (parm == NULL) glp_init_cpxcp(&_parm), parm = &_parm; /* check control parameters */ check_parm("glp_write_lp", parm); /* initialize common storage area */ csa->P = P; csa->parm = parm; /* create output CPLEX LP file */ fp = xfopen(fname, "w"), count = 0; if (fp == NULL) { xprintf("Unable to create '%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } /* write problem name */ xfprintf(fp, "\\* Problem: %s *\\\n", P->name == NULL ? "Unknown" : P->name), count++; xfprintf(fp, "\n"), count++; /* the problem should contain at least one row and one column */ if (!(P->m > 0 && P->n > 0)) { xprintf("Warning: problem has no rows/columns\n"); xfprintf(fp, "\\* WARNING: PROBLEM HAS NO ROWS/COLUMNS *\\\n"), count++; xfprintf(fp, "\n"), count++; goto skip; } /* write the objective function definition */ if (P->dir == GLP_MIN) xfprintf(fp, "Minimize\n"), count++; else if (P->dir == GLP_MAX) xfprintf(fp, "Maximize\n"), count++; else xassert(P != P); row_name(csa, 0, name); sprintf(line, " %s:", name); len = 0; for (j = 1; j <= P->n; j++) { col = P->col[j]; if (col->coef != 0.0 || col->ptr == NULL) { len++; col_name(csa, j, name); if (col->coef == 0.0) sprintf(term, " + 0 %s", name); /* empty column */ else if (col->coef == +1.0) sprintf(term, " + %s", name); else if (col->coef == -1.0) sprintf(term, " - %s", name); else if (col->coef > 0.0) sprintf(term, " + %.*g %s", DBL_DIG, +col->coef, name); else sprintf(term, " - %.*g %s", DBL_DIG, -col->coef, name); if (strlen(line) + strlen(term) > 72) xfprintf(fp, "%s\n", line), line[0] = '\0', count++; strcat(line, term); } } if (len == 0) { /* empty objective */ sprintf(term, " 0 %s", col_name(csa, 1, name)); strcat(line, term); } xfprintf(fp, "%s\n", line), count++; if (P->c0 != 0.0) xfprintf(fp, "\\* constant term = %.*g *\\\n", DBL_DIG, P->c0), count++; xfprintf(fp, "\n"), count++; /* write the constraints section */ xfprintf(fp, "Subject To\n"), count++; for (i = 1; i <= P->m; i++) { row = P->row[i]; if (row->type == GLP_FR) continue; /* skip free row */ row_name(csa, i, name); sprintf(line, " %s:", name); /* linear form */ for (aij = row->ptr; aij != NULL; aij = aij->r_next) { col_name(csa, aij->col->j, name); if (aij->val == +1.0) sprintf(term, " + %s", name); else if (aij->val == -1.0) sprintf(term, " - %s", name); else if (aij->val > 0.0) sprintf(term, " + %.*g %s", DBL_DIG, +aij->val, name); else sprintf(term, " - %.*g %s", DBL_DIG, -aij->val, name); if (strlen(line) + strlen(term) > 72) xfprintf(fp, "%s\n", line), line[0] = '\0', count++; strcat(line, term); } if (row->type == GLP_DB) { /* double-bounded (ranged) constraint */ sprintf(term, " - ~r_%d", i); if (strlen(line) + strlen(term) > 72) xfprintf(fp, "%s\n", line), line[0] = '\0', count++; strcat(line, term); } else if (row->ptr == NULL) { /* empty constraint */ sprintf(term, " 0 %s", col_name(csa, 1, name)); strcat(line, term); } /* right hand-side */ if (row->type == GLP_LO) sprintf(term, " >= %.*g", DBL_DIG, row->lb); else if (row->type == GLP_UP) sprintf(term, " <= %.*g", DBL_DIG, row->ub); else if (row->type == GLP_DB || row->type == GLP_FX) sprintf(term, " = %.*g", DBL_DIG, row->lb); else xassert(row != row); if (strlen(line) + strlen(term) > 72) xfprintf(fp, "%s\n", line), line[0] = '\0', count++; strcat(line, term); xfprintf(fp, "%s\n", line), count++; } xfprintf(fp, "\n"), count++; /* write the bounds section */ flag = 0; for (i = 1; i <= P->m; i++) { row = P->row[i]; if (row->type != GLP_DB) continue; if (!flag) xfprintf(fp, "Bounds\n"), flag = 1, count++; xfprintf(fp, " 0 <= ~r_%d <= %.*g\n", i, DBL_DIG, row->ub - row->lb), count++; } for (j = 1; j <= P->n; j++) { col = P->col[j]; if (col->type == GLP_LO && col->lb == 0.0) continue; if (!flag) xfprintf(fp, "Bounds\n"), flag = 1, count++; col_name(csa, j, name); if (col->type == GLP_FR) xfprintf(fp, " %s free\n", name), count++; else if (col->type == GLP_LO) xfprintf(fp, " %s >= %.*g\n", name, DBL_DIG, col->lb), count++; else if (col->type == GLP_UP) xfprintf(fp, " -Inf <= %s <= %.*g\n", name, DBL_DIG, col->ub), count++; else if (col->type == GLP_DB) xfprintf(fp, " %.*g <= %s <= %.*g\n", DBL_DIG, col->lb, name, DBL_DIG, col->ub), count++; else if (col->type == GLP_FX) xfprintf(fp, " %s = %.*g\n", name, DBL_DIG, col->lb), count++; else xassert(col != col); } if (flag) xfprintf(fp, "\n"), count++; /* write the integer section */ flag = 0; for (j = 1; j <= P->n; j++) { col = P->col[j]; if (col->kind == GLP_CV) continue; xassert(col->kind == GLP_IV); if (!flag) xfprintf(fp, "Generals\n"), flag = 1, count++; xfprintf(fp, " %s\n", col_name(csa, j, name)), count++; } if (flag) xfprintf(fp, "\n"), count++; skip: /* write the end keyword */ xfprintf(fp, "End\n"), count++; xfflush(fp); if (xferror(fp)) { xprintf("Write error on '%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } /* problem data has been successfully written */ xprintf("%d lines were written\n", count); ret = 0; done: if (fp != NULL) xfclose(fp); return ret; } /* eof */ Rglpk/src/GLPK/ffalg.h0000644000176000001440000000237212245352174014146 0ustar ripleyusers/* ffalg.h (Ford-Fulkerson algorithm) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2009, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef FFALG_H #define FFALG_H #define ffalg _glp_ffalg void ffalg(int nv, int na, const int tail[], const int head[], int s, int t, const int cap[], int x[], char cut[]); /* Ford-Fulkerson algorithm */ #endif /* eof */ Rglpk/src/GLPK/glpdmx.c0000644000176000001440000016110012245352174014350 0ustar ripleyusers/* glpdmx.c (reading/writing data in DIMACS format) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #if 1 /* 11/VI-2013 */ #include "env2.h" #endif #define _GLPSTD_STDIO #include "glpapi.h" #include "glplib.h" struct csa { /* common storage area */ jmp_buf jump; /* label for go to in case of error */ const char *fname; /* name of input text file */ XFILE *fp; /* stream assigned to input text file */ int count; /* line count */ int c; /* current character */ char field[255+1]; /* data field */ int empty; /* warning 'empty line ignored' was printed */ int nonint; /* warning 'non-integer data detected' was printed */ }; static void error(struct csa *csa, const char *fmt, ...) { /* print error message and terminate processing */ va_list arg; xprintf("%s:%d: error: ", csa->fname, csa->count); va_start(arg, fmt); xvprintf(fmt, arg); va_end(arg); xprintf("\n"); longjmp(csa->jump, 1); /* no return */ } static void warning(struct csa *csa, const char *fmt, ...) { /* print warning message and continue processing */ va_list arg; xprintf("%s:%d: warning: ", csa->fname, csa->count); va_start(arg, fmt); xvprintf(fmt, arg); va_end(arg); xprintf("\n"); return; } static void read_char(struct csa *csa) { /* read character from input text file */ int c; if (csa->c == '\n') csa->count++; c = xfgetc(csa->fp); if (c < 0) { if (xferror(csa->fp)) error(csa, "read error - %s", xerrmsg()); else if (csa->c == '\n') error(csa, "unexpected end of file"); else { warning(csa, "missing final end of line"); c = '\n'; } } else if (c == '\n') ; else if (isspace(c)) c = ' '; else if (iscntrl(c)) error(csa, "invalid control character 0x%02X", c); csa->c = c; return; } static void read_designator(struct csa *csa) { /* read one-character line designator */ xassert(csa->c == '\n'); read_char(csa); for (;;) { /* skip preceding white-space characters */ while (csa->c == ' ') read_char(csa); if (csa->c == '\n') { /* ignore empty line */ if (!csa->empty) { warning(csa, "empty line ignored"); csa->empty = 1; } read_char(csa); } else if (csa->c == 'c') { /* skip comment line */ while (csa->c != '\n') read_char(csa); read_char(csa); } else { /* hmm... looks like a line designator */ csa->field[0] = (char)csa->c, csa->field[1] = '\0'; /* check that it is followed by a white-space character */ read_char(csa); if (!(csa->c == ' ' || csa->c == '\n')) error(csa, "line designator missing or invalid"); break; } } return; } static void read_field(struct csa *csa) { /* read data field */ int len = 0; /* skip preceding white-space characters */ while (csa->c == ' ') read_char(csa); /* scan data field */ if (csa->c == '\n') error(csa, "unexpected end of line"); while (!(csa->c == ' ' || csa->c == '\n')) { if (len == sizeof(csa->field)-1) error(csa, "data field `%.15s...' too long", csa->field); csa->field[len++] = (char)csa->c; read_char(csa); } csa->field[len] = '\0'; return; } static void end_of_line(struct csa *csa) { /* skip white-space characters until end of line */ while (csa->c == ' ') read_char(csa); if (csa->c != '\n') error(csa, "too many data fields specified"); return; } static void check_int(struct csa *csa, double num) { /* print a warning if non-integer data are detected */ if (!csa->nonint && num != floor(num)) { warning(csa, "non-integer data detected"); csa->nonint = 1; } return; } /*********************************************************************** * NAME * * glp_read_mincost - read min-cost flow problem data in DIMACS format * * SYNOPSIS * * int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap, * int a_cost, const char *fname); * * DESCRIPTION * * The routine glp_read_mincost reads minimum cost flow problem data in * DIMACS format from a text file. * * RETURNS * * If the operation was successful, the routine returns zero. Otherwise * it prints an error message and returns non-zero. */ int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap, int a_cost, const char *fname) { struct csa _csa, *csa = &_csa; glp_vertex *v; glp_arc *a; int i, j, k, nv, na, ret = 0; double rhs, low, cap, cost; char *flag = NULL; if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double)) xerror("glp_read_mincost: v_rhs = %d; invalid offset\n", v_rhs); if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double)) xerror("glp_read_mincost: a_low = %d; invalid offset\n", a_low); if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) xerror("glp_read_mincost: a_cap = %d; invalid offset\n", a_cap); if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) xerror("glp_read_mincost: a_cost = %d; invalid offset\n", a_cost); glp_erase_graph(G, G->v_size, G->a_size); if (setjmp(csa->jump)) { ret = 1; goto done; } csa->fname = fname; csa->fp = NULL; csa->count = 0; csa->c = '\n'; csa->field[0] = '\0'; csa->empty = csa->nonint = 0; xprintf("Reading min-cost flow problem data from `%s'...\n", fname); csa->fp = xfopen(fname, "r"); if (csa->fp == NULL) { xprintf("Unable to open `%s' - %s\n", fname, xerrmsg()); longjmp(csa->jump, 1); } /* read problem line */ read_designator(csa); if (strcmp(csa->field, "p") != 0) error(csa, "problem line missing or invalid"); read_field(csa); if (strcmp(csa->field, "min") != 0) error(csa, "wrong problem designator; `min' expected"); read_field(csa); if (!(str2int(csa->field, &nv) == 0 && nv >= 0)) error(csa, "number of nodes missing or invalid"); read_field(csa); if (!(str2int(csa->field, &na) == 0 && na >= 0)) error(csa, "number of arcs missing or invalid"); xprintf("Flow network has %d node%s and %d arc%s\n", nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s"); if (nv > 0) glp_add_vertices(G, nv); end_of_line(csa); /* read node descriptor lines */ flag = xcalloc(1+nv, sizeof(char)); memset(&flag[1], 0, nv * sizeof(char)); if (v_rhs >= 0) { rhs = 0.0; for (i = 1; i <= nv; i++) { v = G->v[i]; memcpy((char *)v->data + v_rhs, &rhs, sizeof(double)); } } for (;;) { read_designator(csa); if (strcmp(csa->field, "n") != 0) break; read_field(csa); if (str2int(csa->field, &i) != 0) error(csa, "node number missing or invalid"); if (!(1 <= i && i <= nv)) error(csa, "node number %d out of range", i); if (flag[i]) error(csa, "duplicate descriptor of node %d", i); read_field(csa); if (str2num(csa->field, &rhs) != 0) error(csa, "node supply/demand missing or invalid"); check_int(csa, rhs); if (v_rhs >= 0) { v = G->v[i]; memcpy((char *)v->data + v_rhs, &rhs, sizeof(double)); } flag[i] = 1; end_of_line(csa); } xfree(flag), flag = NULL; /* read arc descriptor lines */ for (k = 1; k <= na; k++) { if (k > 1) read_designator(csa); if (strcmp(csa->field, "a") != 0) error(csa, "wrong line designator; `a' expected"); read_field(csa); if (str2int(csa->field, &i) != 0) error(csa, "starting node number missing or invalid"); if (!(1 <= i && i <= nv)) error(csa, "starting node number %d out of range", i); read_field(csa); if (str2int(csa->field, &j) != 0) error(csa, "ending node number missing or invalid"); if (!(1 <= j && j <= nv)) error(csa, "ending node number %d out of range", j); read_field(csa); if (!(str2num(csa->field, &low) == 0 && low >= 0.0)) error(csa, "lower bound of arc flow missing or invalid"); check_int(csa, low); read_field(csa); if (!(str2num(csa->field, &cap) == 0 && cap >= low)) error(csa, "upper bound of arc flow missing or invalid"); check_int(csa, cap); read_field(csa); if (str2num(csa->field, &cost) != 0) error(csa, "per-unit cost of arc flow missing or invalid"); check_int(csa, cost); a = glp_add_arc(G, i, j); if (a_low >= 0) memcpy((char *)a->data + a_low, &low, sizeof(double)); if (a_cap >= 0) memcpy((char *)a->data + a_cap, &cap, sizeof(double)); if (a_cost >= 0) memcpy((char *)a->data + a_cost, &cost, sizeof(double)); end_of_line(csa); } xprintf("%d lines were read\n", csa->count); done: if (ret) glp_erase_graph(G, G->v_size, G->a_size); if (csa->fp != NULL) xfclose(csa->fp); if (flag != NULL) xfree(flag); return ret; } /*********************************************************************** * NAME * * glp_write_mincost - write min-cost flow problem data in DIMACS format * * SYNOPSIS * * int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap, * int a_cost, const char *fname); * * DESCRIPTION * * The routine glp_write_mincost writes minimum cost flow problem data * in DIMACS format to a text file. * * RETURNS * * If the operation was successful, the routine returns zero. Otherwise * it prints an error message and returns non-zero. */ int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap, int a_cost, const char *fname) { XFILE *fp; glp_vertex *v; glp_arc *a; int i, count = 0, ret; double rhs, low, cap, cost; if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double)) xerror("glp_write_mincost: v_rhs = %d; invalid offset\n", v_rhs); if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double)) xerror("glp_write_mincost: a_low = %d; invalid offset\n", a_low); if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) xerror("glp_write_mincost: a_cap = %d; invalid offset\n", a_cap); if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) xerror("glp_write_mincost: a_cost = %d; invalid offset\n", a_cost); xprintf("Writing min-cost flow problem data to `%s'...\n", fname); fp = xfopen(fname, "w"); if (fp == NULL) { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } xfprintf(fp, "c %s\n", G->name == NULL ? "unknown" : G->name), count++; xfprintf(fp, "p min %d %d\n", G->nv, G->na), count++; if (v_rhs >= 0) { for (i = 1; i <= G->nv; i++) { v = G->v[i]; memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double)); if (rhs != 0.0) xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, rhs), count++; } } for (i = 1; i <= G->nv; i++) { v = G->v[i]; for (a = v->out; a != NULL; a = a->t_next) { if (a_low >= 0) memcpy(&low, (char *)a->data + a_low, sizeof(double)); else low = 0.0; if (a_cap >= 0) memcpy(&cap, (char *)a->data + a_cap, sizeof(double)); else cap = 1.0; if (a_cost >= 0) memcpy(&cost, (char *)a->data + a_cost, sizeof(double)); else cost = 0.0; xfprintf(fp, "a %d %d %.*g %.*g %.*g\n", a->tail->i, a->head->i, DBL_DIG, low, DBL_DIG, cap, DBL_DIG, cost), count++; } } xfprintf(fp, "c eof\n"), count++; xfflush(fp); if (xferror(fp)) { xprintf("Write error on `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } xprintf("%d lines were written\n", count); ret = 0; done: if (fp != NULL) xfclose(fp); return ret; } /*********************************************************************** * NAME * * glp_read_maxflow - read maximum flow problem data in DIMACS format * * SYNOPSIS * * int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap, * const char *fname); * * DESCRIPTION * * The routine glp_read_maxflow reads maximum flow problem data in * DIMACS format from a text file. * * RETURNS * * If the operation was successful, the routine returns zero. Otherwise * it prints an error message and returns non-zero. */ int glp_read_maxflow(glp_graph *G, int *_s, int *_t, int a_cap, const char *fname) { struct csa _csa, *csa = &_csa; glp_arc *a; int i, j, k, s, t, nv, na, ret = 0; double cap; if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) xerror("glp_read_maxflow: a_cap = %d; invalid offset\n", a_cap); glp_erase_graph(G, G->v_size, G->a_size); if (setjmp(csa->jump)) { ret = 1; goto done; } csa->fname = fname; csa->fp = NULL; csa->count = 0; csa->c = '\n'; csa->field[0] = '\0'; csa->empty = csa->nonint = 0; xprintf("Reading maximum flow problem data from `%s'...\n", fname); csa->fp = xfopen(fname, "r"); if (csa->fp == NULL) { xprintf("Unable to open `%s' - %s\n", fname, xerrmsg()); longjmp(csa->jump, 1); } /* read problem line */ read_designator(csa); if (strcmp(csa->field, "p") != 0) error(csa, "problem line missing or invalid"); read_field(csa); if (strcmp(csa->field, "max") != 0) error(csa, "wrong problem designator; `max' expected"); read_field(csa); if (!(str2int(csa->field, &nv) == 0 && nv >= 2)) error(csa, "number of nodes missing or invalid"); read_field(csa); if (!(str2int(csa->field, &na) == 0 && na >= 0)) error(csa, "number of arcs missing or invalid"); xprintf("Flow network has %d node%s and %d arc%s\n", nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s"); if (nv > 0) glp_add_vertices(G, nv); end_of_line(csa); /* read node descriptor lines */ s = t = 0; for (;;) { read_designator(csa); if (strcmp(csa->field, "n") != 0) break; read_field(csa); if (str2int(csa->field, &i) != 0) error(csa, "node number missing or invalid"); if (!(1 <= i && i <= nv)) error(csa, "node number %d out of range", i); read_field(csa); if (strcmp(csa->field, "s") == 0) { if (s > 0) error(csa, "only one source node allowed"); s = i; } else if (strcmp(csa->field, "t") == 0) { if (t > 0) error(csa, "only one sink node allowed"); t = i; } else error(csa, "wrong node designator; `s' or `t' expected"); if (s > 0 && s == t) error(csa, "source and sink nodes must be distinct"); end_of_line(csa); } if (s == 0) error(csa, "source node descriptor missing\n"); if (t == 0) error(csa, "sink node descriptor missing\n"); if (_s != NULL) *_s = s; if (_t != NULL) *_t = t; /* read arc descriptor lines */ for (k = 1; k <= na; k++) { if (k > 1) read_designator(csa); if (strcmp(csa->field, "a") != 0) error(csa, "wrong line designator; `a' expected"); read_field(csa); if (str2int(csa->field, &i) != 0) error(csa, "starting node number missing or invalid"); if (!(1 <= i && i <= nv)) error(csa, "starting node number %d out of range", i); read_field(csa); if (str2int(csa->field, &j) != 0) error(csa, "ending node number missing or invalid"); if (!(1 <= j && j <= nv)) error(csa, "ending node number %d out of range", j); read_field(csa); if (!(str2num(csa->field, &cap) == 0 && cap >= 0.0)) error(csa, "arc capacity missing or invalid"); check_int(csa, cap); a = glp_add_arc(G, i, j); if (a_cap >= 0) memcpy((char *)a->data + a_cap, &cap, sizeof(double)); end_of_line(csa); } xprintf("%d lines were read\n", csa->count); done: if (ret) glp_erase_graph(G, G->v_size, G->a_size); if (csa->fp != NULL) xfclose(csa->fp); return ret; } /*********************************************************************** * NAME * * glp_write_maxflow - write maximum flow problem data in DIMACS format * * SYNOPSIS * * int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap, * const char *fname); * * DESCRIPTION * * The routine glp_write_maxflow writes maximum flow problem data in * DIMACS format to a text file. * * RETURNS * * If the operation was successful, the routine returns zero. Otherwise * it prints an error message and returns non-zero. */ int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap, const char *fname) { XFILE *fp; glp_vertex *v; glp_arc *a; int i, count = 0, ret; double cap; if (!(1 <= s && s <= G->nv)) xerror("glp_write_maxflow: s = %d; source node number out of r" "ange\n", s); if (!(1 <= t && t <= G->nv)) xerror("glp_write_maxflow: t = %d: sink node number out of ran" "ge\n", t); if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) xerror("glp_write_mincost: a_cap = %d; invalid offset\n", a_cap); xprintf("Writing maximum flow problem data to `%s'...\n", fname); fp = xfopen(fname, "w"); if (fp == NULL) { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } xfprintf(fp, "c %s\n", G->name == NULL ? "unknown" : G->name), count++; xfprintf(fp, "p max %d %d\n", G->nv, G->na), count++; xfprintf(fp, "n %d s\n", s), count++; xfprintf(fp, "n %d t\n", t), count++; for (i = 1; i <= G->nv; i++) { v = G->v[i]; for (a = v->out; a != NULL; a = a->t_next) { if (a_cap >= 0) memcpy(&cap, (char *)a->data + a_cap, sizeof(double)); else cap = 1.0; xfprintf(fp, "a %d %d %.*g\n", a->tail->i, a->head->i, DBL_DIG, cap), count++; } } xfprintf(fp, "c eof\n"), count++; xfflush(fp); if (xferror(fp)) { xprintf("Write error on `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } xprintf("%d lines were written\n", count); ret = 0; done: if (fp != NULL) xfclose(fp); return ret; } /*********************************************************************** * NAME * * glp_read_asnprob - read assignment problem data in DIMACS format * * SYNOPSIS * * int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, * const char *fname); * * DESCRIPTION * * The routine glp_read_asnprob reads assignment problem data in DIMACS * format from a text file. * * RETURNS * * If the operation was successful, the routine returns zero. Otherwise * it prints an error message and returns non-zero. */ int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, const char *fname) { struct csa _csa, *csa = &_csa; glp_vertex *v; glp_arc *a; int nv, na, n1, i, j, k, ret = 0; double cost; char *flag = NULL; if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) xerror("glp_read_asnprob: v_set = %d; invalid offset\n", v_set); if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) xerror("glp_read_asnprob: a_cost = %d; invalid offset\n", a_cost); glp_erase_graph(G, G->v_size, G->a_size); if (setjmp(csa->jump)) { ret = 1; goto done; } csa->fname = fname; csa->fp = NULL; csa->count = 0; csa->c = '\n'; csa->field[0] = '\0'; csa->empty = csa->nonint = 0; xprintf("Reading assignment problem data from `%s'...\n", fname); csa->fp = xfopen(fname, "r"); if (csa->fp == NULL) { xprintf("Unable to open `%s' - %s\n", fname, xerrmsg()); longjmp(csa->jump, 1); } /* read problem line */ read_designator(csa); if (strcmp(csa->field, "p") != 0) error(csa, "problem line missing or invalid"); read_field(csa); if (strcmp(csa->field, "asn") != 0) error(csa, "wrong problem designator; `asn' expected"); read_field(csa); if (!(str2int(csa->field, &nv) == 0 && nv >= 0)) error(csa, "number of nodes missing or invalid"); read_field(csa); if (!(str2int(csa->field, &na) == 0 && na >= 0)) error(csa, "number of arcs missing or invalid"); if (nv > 0) glp_add_vertices(G, nv); end_of_line(csa); /* read node descriptor lines */ flag = xcalloc(1+nv, sizeof(char)); memset(&flag[1], 0, nv * sizeof(char)); n1 = 0; for (;;) { read_designator(csa); if (strcmp(csa->field, "n") != 0) break; read_field(csa); if (str2int(csa->field, &i) != 0) error(csa, "node number missing or invalid"); if (!(1 <= i && i <= nv)) error(csa, "node number %d out of range", i); if (flag[i]) error(csa, "duplicate descriptor of node %d", i); flag[i] = 1, n1++; end_of_line(csa); } xprintf( "Assignment problem has %d + %d = %d node%s and %d arc%s\n", n1, nv - n1, nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s"); if (v_set >= 0) { for (i = 1; i <= nv; i++) { v = G->v[i]; k = (flag[i] ? 0 : 1); memcpy((char *)v->data + v_set, &k, sizeof(int)); } } /* read arc descriptor lines */ for (k = 1; k <= na; k++) { if (k > 1) read_designator(csa); if (strcmp(csa->field, "a") != 0) error(csa, "wrong line designator; `a' expected"); read_field(csa); if (str2int(csa->field, &i) != 0) error(csa, "starting node number missing or invalid"); if (!(1 <= i && i <= nv)) error(csa, "starting node number %d out of range", i); if (!flag[i]) error(csa, "node %d cannot be a starting node", i); read_field(csa); if (str2int(csa->field, &j) != 0) error(csa, "ending node number missing or invalid"); if (!(1 <= j && j <= nv)) error(csa, "ending node number %d out of range", j); if (flag[j]) error(csa, "node %d cannot be an ending node", j); read_field(csa); if (str2num(csa->field, &cost) != 0) error(csa, "arc cost missing or invalid"); check_int(csa, cost); a = glp_add_arc(G, i, j); if (a_cost >= 0) memcpy((char *)a->data + a_cost, &cost, sizeof(double)); end_of_line(csa); } xprintf("%d lines were read\n", csa->count); done: if (ret) glp_erase_graph(G, G->v_size, G->a_size); if (csa->fp != NULL) xfclose(csa->fp); if (flag != NULL) xfree(flag); return ret; } /*********************************************************************** * NAME * * glp_write_asnprob - write assignment problem data in DIMACS format * * SYNOPSIS * * int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, * const char *fname); * * DESCRIPTION * * The routine glp_write_asnprob writes assignment problem data in * DIMACS format to a text file. * * RETURNS * * If the operation was successful, the routine returns zero. Otherwise * it prints an error message and returns non-zero. */ int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, const char *fname) { XFILE *fp; glp_vertex *v; glp_arc *a; int i, k, count = 0, ret; double cost; if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) xerror("glp_write_asnprob: v_set = %d; invalid offset\n", v_set); if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) xerror("glp_write_asnprob: a_cost = %d; invalid offset\n", a_cost); xprintf("Writing assignment problem data to `%s'...\n", fname); fp = xfopen(fname, "w"); if (fp == NULL) { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } xfprintf(fp, "c %s\n", G->name == NULL ? "unknown" : G->name), count++; xfprintf(fp, "p asn %d %d\n", G->nv, G->na), count++; for (i = 1; i <= G->nv; i++) { v = G->v[i]; if (v_set >= 0) memcpy(&k, (char *)v->data + v_set, sizeof(int)); else k = (v->out != NULL ? 0 : 1); if (k == 0) xfprintf(fp, "n %d\n", i), count++; } for (i = 1; i <= G->nv; i++) { v = G->v[i]; for (a = v->out; a != NULL; a = a->t_next) { if (a_cost >= 0) memcpy(&cost, (char *)a->data + a_cost, sizeof(double)); else cost = 1.0; xfprintf(fp, "a %d %d %.*g\n", a->tail->i, a->head->i, DBL_DIG, cost), count++; } } xfprintf(fp, "c eof\n"), count++; xfflush(fp); if (xferror(fp)) { xprintf("Write error on `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } xprintf("%d lines were written\n", count); ret = 0; done: if (fp != NULL) xfclose(fp); return ret; } /*********************************************************************** * NAME * * glp_read_ccdata - read graph in DIMACS clique/coloring format * * SYNOPSIS * * int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname); * * DESCRIPTION * * The routine glp_read_ccdata reads an (undirected) graph in DIMACS * clique/coloring format from a text file. * * RETURNS * * If the operation was successful, the routine returns zero. Otherwise * it prints an error message and returns non-zero. */ int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname) { struct csa _csa, *csa = &_csa; glp_vertex *v; int i, j, k, nv, ne, ret = 0; double w; char *flag = NULL; if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double)) xerror("glp_read_ccdata: v_wgt = %d; invalid offset\n", v_wgt); glp_erase_graph(G, G->v_size, G->a_size); if (setjmp(csa->jump)) { ret = 1; goto done; } csa->fname = fname; csa->fp = NULL; csa->count = 0; csa->c = '\n'; csa->field[0] = '\0'; csa->empty = csa->nonint = 0; xprintf("Reading graph from `%s'...\n", fname); csa->fp = xfopen(fname, "r"); if (csa->fp == NULL) { xprintf("Unable to open `%s' - %s\n", fname, xerrmsg()); longjmp(csa->jump, 1); } /* read problem line */ read_designator(csa); if (strcmp(csa->field, "p") != 0) error(csa, "problem line missing or invalid"); read_field(csa); if (strcmp(csa->field, "edge") != 0) error(csa, "wrong problem designator; `edge' expected"); read_field(csa); if (!(str2int(csa->field, &nv) == 0 && nv >= 0)) error(csa, "number of vertices missing or invalid"); read_field(csa); if (!(str2int(csa->field, &ne) == 0 && ne >= 0)) error(csa, "number of edges missing or invalid"); xprintf("Graph has %d vert%s and %d edge%s\n", nv, nv == 1 ? "ex" : "ices", ne, ne == 1 ? "" : "s"); if (nv > 0) glp_add_vertices(G, nv); end_of_line(csa); /* read node descriptor lines */ flag = xcalloc(1+nv, sizeof(char)); memset(&flag[1], 0, nv * sizeof(char)); if (v_wgt >= 0) { w = 1.0; for (i = 1; i <= nv; i++) { v = G->v[i]; memcpy((char *)v->data + v_wgt, &w, sizeof(double)); } } for (;;) { read_designator(csa); if (strcmp(csa->field, "n") != 0) break; read_field(csa); if (str2int(csa->field, &i) != 0) error(csa, "vertex number missing or invalid"); if (!(1 <= i && i <= nv)) error(csa, "vertex number %d out of range", i); if (flag[i]) error(csa, "duplicate descriptor of vertex %d", i); read_field(csa); if (str2num(csa->field, &w) != 0) error(csa, "vertex weight missing or invalid"); check_int(csa, w); if (v_wgt >= 0) { v = G->v[i]; memcpy((char *)v->data + v_wgt, &w, sizeof(double)); } flag[i] = 1; end_of_line(csa); } xfree(flag), flag = NULL; /* read edge descriptor lines */ for (k = 1; k <= ne; k++) { if (k > 1) read_designator(csa); if (strcmp(csa->field, "e") != 0) error(csa, "wrong line designator; `e' expected"); read_field(csa); if (str2int(csa->field, &i) != 0) error(csa, "first vertex number missing or invalid"); if (!(1 <= i && i <= nv)) error(csa, "first vertex number %d out of range", i); read_field(csa); if (str2int(csa->field, &j) != 0) error(csa, "second vertex number missing or invalid"); if (!(1 <= j && j <= nv)) error(csa, "second vertex number %d out of range", j); glp_add_arc(G, i, j); end_of_line(csa); } xprintf("%d lines were read\n", csa->count); done: if (ret) glp_erase_graph(G, G->v_size, G->a_size); if (csa->fp != NULL) xfclose(csa->fp); if (flag != NULL) xfree(flag); return ret; } /*********************************************************************** * NAME * * glp_write_ccdata - write graph in DIMACS clique/coloring format * * SYNOPSIS * * int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname); * * DESCRIPTION * * The routine glp_write_ccdata writes the specified graph in DIMACS * clique/coloring format to a text file. * * RETURNS * * If the operation was successful, the routine returns zero. Otherwise * it prints an error message and returns non-zero. */ int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname) { XFILE *fp; glp_vertex *v; glp_arc *e; int i, count = 0, ret; double w; if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double)) xerror("glp_write_ccdata: v_wgt = %d; invalid offset\n", v_wgt); xprintf("Writing graph to `%s'\n", fname); fp = xfopen(fname, "w"); if (fp == NULL) { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } xfprintf(fp, "c %s\n", G->name == NULL ? "unknown" : G->name), count++; xfprintf(fp, "p edge %d %d\n", G->nv, G->na), count++; if (v_wgt >= 0) { for (i = 1; i <= G->nv; i++) { v = G->v[i]; memcpy(&w, (char *)v->data + v_wgt, sizeof(double)); if (w != 1.0) xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, w), count++; } } for (i = 1; i <= G->nv; i++) { v = G->v[i]; for (e = v->out; e != NULL; e = e->t_next) xfprintf(fp, "e %d %d\n", e->tail->i, e->head->i), count++; } xfprintf(fp, "c eof\n"), count++; xfflush(fp); if (xferror(fp)) { xprintf("Write error on `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } xprintf("%d lines were written\n", count); ret = 0; done: if (fp != NULL) xfclose(fp); return ret; } /*********************************************************************** * NAME * * glp_read_prob - read problem data in GLPK format * * SYNOPSIS * * int glp_read_prob(glp_prob *P, int flags, const char *fname); * * The routine glp_read_prob reads problem data in GLPK LP/MIP format * from a text file. * * RETURNS * * If the operation was successful, the routine returns zero. Otherwise * it prints an error message and returns non-zero. */ int glp_read_prob(glp_prob *P, int flags, const char *fname) { struct csa _csa, *csa = &_csa; int mip, m, n, nnz, ne, i, j, k, type, kind, ret, *ln = NULL, *ia = NULL, *ja = NULL; double lb, ub, temp, *ar = NULL; char *rf = NULL, *cf = NULL; if (P == NULL || P->magic != GLP_PROB_MAGIC) xerror("glp_read_prob: P = %p; invalid problem object\n", P); if (flags != 0) xerror("glp_read_prob: flags = %d; invalid parameter\n", flags); if (fname == NULL) xerror("glp_read_prob: fname = %d; invalid parameter\n", fname); glp_erase_prob(P); if (setjmp(csa->jump)) { ret = 1; goto done; } csa->fname = fname; csa->fp = NULL; csa->count = 0; csa->c = '\n'; csa->field[0] = '\0'; csa->empty = csa->nonint = 0; xprintf("Reading problem data from `%s'...\n", fname); csa->fp = xfopen(fname, "r"); if (csa->fp == NULL) { xprintf("Unable to open `%s' - %s\n", fname, xerrmsg()); longjmp(csa->jump, 1); } /* read problem line */ read_designator(csa); if (strcmp(csa->field, "p") != 0) error(csa, "problem line missing or invalid"); read_field(csa); if (strcmp(csa->field, "lp") == 0) mip = 0; else if (strcmp(csa->field, "mip") == 0) mip = 1; else error(csa, "wrong problem designator; `lp' or `mip' expected\n" ); read_field(csa); if (strcmp(csa->field, "min") == 0) glp_set_obj_dir(P, GLP_MIN); else if (strcmp(csa->field, "max") == 0) glp_set_obj_dir(P, GLP_MAX); else error(csa, "objective sense missing or invalid"); read_field(csa); if (!(str2int(csa->field, &m) == 0 && m >= 0)) error(csa, "number of rows missing or invalid"); read_field(csa); if (!(str2int(csa->field, &n) == 0 && n >= 0)) error(csa, "number of columns missing or invalid"); read_field(csa); if (!(str2int(csa->field, &nnz) == 0 && nnz >= 0)) error(csa, "number of constraint coefficients missing or inval" "id"); if (m > 0) { glp_add_rows(P, m); for (i = 1; i <= m; i++) glp_set_row_bnds(P, i, GLP_FX, 0.0, 0.0); } if (n > 0) { glp_add_cols(P, n); for (j = 1; j <= n; j++) { if (!mip) glp_set_col_bnds(P, j, GLP_LO, 0.0, 0.0); else glp_set_col_kind(P, j, GLP_BV); } } end_of_line(csa); /* allocate working arrays */ rf = xcalloc(1+m, sizeof(char)); memset(rf, 0, 1+m); cf = xcalloc(1+n, sizeof(char)); memset(cf, 0, 1+n); ln = xcalloc(1+nnz, sizeof(int)); ia = xcalloc(1+nnz, sizeof(int)); ja = xcalloc(1+nnz, sizeof(int)); ar = xcalloc(1+nnz, sizeof(double)); /* read descriptor lines */ ne = 0; for (;;) { read_designator(csa); if (strcmp(csa->field, "i") == 0) { /* row descriptor */ read_field(csa); if (str2int(csa->field, &i) != 0) error(csa, "row number missing or invalid"); if (!(1 <= i && i <= m)) error(csa, "row number out of range"); read_field(csa); if (strcmp(csa->field, "f") == 0) type = GLP_FR; else if (strcmp(csa->field, "l") == 0) type = GLP_LO; else if (strcmp(csa->field, "u") == 0) type = GLP_UP; else if (strcmp(csa->field, "d") == 0) type = GLP_DB; else if (strcmp(csa->field, "s") == 0) type = GLP_FX; else error(csa, "row type missing or invalid"); if (type == GLP_LO || type == GLP_DB || type == GLP_FX) { read_field(csa); if (str2num(csa->field, &lb) != 0) error(csa, "row lower bound/fixed value missing or in" "valid"); } else lb = 0.0; if (type == GLP_UP || type == GLP_DB) { read_field(csa); if (str2num(csa->field, &ub) != 0) error(csa, "row upper bound missing or invalid"); } else ub = 0.0; if (rf[i] & 0x01) error(csa, "duplicate row descriptor"); glp_set_row_bnds(P, i, type, lb, ub), rf[i] |= 0x01; } else if (strcmp(csa->field, "j") == 0) { /* column descriptor */ read_field(csa); if (str2int(csa->field, &j) != 0) error(csa, "column number missing or invalid"); if (!(1 <= j && j <= n)) error(csa, "column number out of range"); if (!mip) kind = GLP_CV; else { read_field(csa); if (strcmp(csa->field, "c") == 0) kind = GLP_CV; else if (strcmp(csa->field, "i") == 0) kind = GLP_IV; else if (strcmp(csa->field, "b") == 0) { kind = GLP_IV; type = GLP_DB, lb = 0.0, ub = 1.0; goto skip; } else error(csa, "column kind missing or invalid"); } read_field(csa); if (strcmp(csa->field, "f") == 0) type = GLP_FR; else if (strcmp(csa->field, "l") == 0) type = GLP_LO; else if (strcmp(csa->field, "u") == 0) type = GLP_UP; else if (strcmp(csa->field, "d") == 0) type = GLP_DB; else if (strcmp(csa->field, "s") == 0) type = GLP_FX; else error(csa, "column type missing or invalid"); if (type == GLP_LO || type == GLP_DB || type == GLP_FX) { read_field(csa); if (str2num(csa->field, &lb) != 0) error(csa, "column lower bound/fixed value missing or" " invalid"); } else lb = 0.0; if (type == GLP_UP || type == GLP_DB) { read_field(csa); if (str2num(csa->field, &ub) != 0) error(csa, "column upper bound missing or invalid"); } else ub = 0.0; skip: if (cf[j] & 0x01) error(csa, "duplicate column descriptor"); glp_set_col_kind(P, j, kind); glp_set_col_bnds(P, j, type, lb, ub), cf[j] |= 0x01; } else if (strcmp(csa->field, "a") == 0) { /* coefficient descriptor */ read_field(csa); if (str2int(csa->field, &i) != 0) error(csa, "row number missing or invalid"); if (!(0 <= i && i <= m)) error(csa, "row number out of range"); read_field(csa); if (str2int(csa->field, &j) != 0) error(csa, "column number missing or invalid"); if (!((i == 0 ? 0 : 1) <= j && j <= n)) error(csa, "column number out of range"); read_field(csa); if (i == 0) { if (str2num(csa->field, &temp) != 0) error(csa, "objective %s missing or invalid", j == 0 ? "constant term" : "coefficient"); if (cf[j] & 0x10) error(csa, "duplicate objective %s", j == 0 ? "constant term" : "coefficient"); glp_set_obj_coef(P, j, temp), cf[j] |= 0x10; } else { if (str2num(csa->field, &temp) != 0) error(csa, "constraint coefficient missing or invalid" ); if (ne == nnz) error(csa, "too many constraint coefficient descripto" "rs"); ln[++ne] = csa->count; ia[ne] = i, ja[ne] = j, ar[ne] = temp; } } else if (strcmp(csa->field, "n") == 0) { /* symbolic name descriptor */ read_field(csa); if (strcmp(csa->field, "p") == 0) { /* problem name */ read_field(csa); if (P->name != NULL) error(csa, "duplicate problem name"); glp_set_prob_name(P, csa->field); } else if (strcmp(csa->field, "z") == 0) { /* objective name */ read_field(csa); if (P->obj != NULL) error(csa, "duplicate objective name"); glp_set_obj_name(P, csa->field); } else if (strcmp(csa->field, "i") == 0) { /* row name */ read_field(csa); if (str2int(csa->field, &i) != 0) error(csa, "row number missing or invalid"); if (!(1 <= i && i <= m)) error(csa, "row number out of range"); read_field(csa); if (P->row[i]->name != NULL) error(csa, "duplicate row name"); glp_set_row_name(P, i, csa->field); } else if (strcmp(csa->field, "j") == 0) { /* column name */ read_field(csa); if (str2int(csa->field, &j) != 0) error(csa, "column number missing or invalid"); if (!(1 <= j && j <= n)) error(csa, "column number out of range"); read_field(csa); if (P->col[j]->name != NULL) error(csa, "duplicate column name"); glp_set_col_name(P, j, csa->field); } else error(csa, "object designator missing or invalid"); } else if (strcmp(csa->field, "e") == 0) break; else error(csa, "line designator missing or invalid"); end_of_line(csa); } if (ne < nnz) error(csa, "too few constraint coefficient descriptors"); xassert(ne == nnz); k = glp_check_dup(m, n, ne, ia, ja); xassert(0 <= k && k <= nnz); if (k > 0) { csa->count = ln[k]; error(csa, "duplicate constraint coefficient"); } glp_load_matrix(P, ne, ia, ja, ar); /* print some statistics */ if (P->name != NULL) xprintf("Problem: %s\n", P->name); if (P->obj != NULL) xprintf("Objective: %s\n", P->obj); xprintf("%d row%s, %d column%s, %d non-zero%s\n", m, m == 1 ? "" : "s", n, n == 1 ? "" : "s", nnz, nnz == 1 ? "" : "s"); if (glp_get_num_int(P) > 0) { int ni = glp_get_num_int(P); int nb = glp_get_num_bin(P); if (ni == 1) { if (nb == 0) xprintf("One variable is integer\n"); else xprintf("One variable is binary\n"); } else { xprintf("%d integer variables, ", ni); if (nb == 0) xprintf("none"); else if (nb == 1) xprintf("one"); else if (nb == ni) xprintf("all"); else xprintf("%d", nb); xprintf(" of which %s binary\n", nb == 1 ? "is" : "are"); } } xprintf("%d lines were read\n", csa->count); /* problem data has been successfully read */ glp_sort_matrix(P); ret = 0; done: if (csa->fp != NULL) xfclose(csa->fp); if (rf != NULL) xfree(rf); if (cf != NULL) xfree(cf); if (ln != NULL) xfree(ln); if (ia != NULL) xfree(ia); if (ja != NULL) xfree(ja); if (ar != NULL) xfree(ar); if (ret) glp_erase_prob(P); return ret; } /*********************************************************************** * NAME * * glp_write_prob - write problem data in GLPK format * * SYNOPSIS * * int glp_write_prob(glp_prob *P, int flags, const char *fname); * * The routine glp_write_prob writes problem data in GLPK LP/MIP format * to a text file. * * RETURNS * * If the operation was successful, the routine returns zero. Otherwise * it prints an error message and returns non-zero. */ int glp_write_prob(glp_prob *P, int flags, const char *fname) { XFILE *fp; GLPROW *row; GLPCOL *col; GLPAIJ *aij; int mip, i, j, count, ret; if (P == NULL || P->magic != GLP_PROB_MAGIC) xerror("glp_write_prob: P = %p; invalid problem object\n", P); if (flags != 0) xerror("glp_write_prob: flags = %d; invalid parameter\n", flags); if (fname == NULL) xerror("glp_write_prob: fname = %d; invalid parameter\n", fname); xprintf("Writing problem data to `%s'...\n", fname); fp = xfopen(fname, "w"), count = 0; if (fp == NULL) { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } /* write problem line */ mip = (glp_get_num_int(P) > 0); xfprintf(fp, "p %s %s %d %d %d\n", !mip ? "lp" : "mip", P->dir == GLP_MIN ? "min" : P->dir == GLP_MAX ? "max" : "???", P->m, P->n, P->nnz), count++; if (P->name != NULL) xfprintf(fp, "n p %s\n", P->name), count++; if (P->obj != NULL) xfprintf(fp, "n z %s\n", P->obj), count++; /* write row descriptors */ for (i = 1; i <= P->m; i++) { row = P->row[i]; if (row->type == GLP_FX && row->lb == 0.0) goto skip1; xfprintf(fp, "i %d ", i), count++; if (row->type == GLP_FR) xfprintf(fp, "f\n"); else if (row->type == GLP_LO) xfprintf(fp, "l %.*g\n", DBL_DIG, row->lb); else if (row->type == GLP_UP) xfprintf(fp, "u %.*g\n", DBL_DIG, row->ub); else if (row->type == GLP_DB) xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, row->lb, DBL_DIG, row->ub); else if (row->type == GLP_FX) xfprintf(fp, "s %.*g\n", DBL_DIG, row->lb); else xassert(row != row); skip1: if (row->name != NULL) xfprintf(fp, "n i %d %s\n", i, row->name), count++; } /* write column descriptors */ for (j = 1; j <= P->n; j++) { col = P->col[j]; if (!mip && col->type == GLP_LO && col->lb == 0.0) goto skip2; if (mip && col->kind == GLP_IV && col->type == GLP_DB && col->lb == 0.0 && col->ub == 1.0) goto skip2; xfprintf(fp, "j %d ", j), count++; if (mip) { if (col->kind == GLP_CV) xfprintf(fp, "c "); else if (col->kind == GLP_IV) xfprintf(fp, "i "); else xassert(col != col); } if (col->type == GLP_FR) xfprintf(fp, "f\n"); else if (col->type == GLP_LO) xfprintf(fp, "l %.*g\n", DBL_DIG, col->lb); else if (col->type == GLP_UP) xfprintf(fp, "u %.*g\n", DBL_DIG, col->ub); else if (col->type == GLP_DB) xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, col->lb, DBL_DIG, col->ub); else if (col->type == GLP_FX) xfprintf(fp, "s %.*g\n", DBL_DIG, col->lb); else xassert(col != col); skip2: if (col->name != NULL) xfprintf(fp, "n j %d %s\n", j, col->name), count++; } /* write objective coefficient descriptors */ if (P->c0 != 0.0) xfprintf(fp, "a 0 0 %.*g\n", DBL_DIG, P->c0), count++; for (j = 1; j <= P->n; j++) { col = P->col[j]; if (col->coef != 0.0) xfprintf(fp, "a 0 %d %.*g\n", j, DBL_DIG, col->coef), count++; } /* write constraint coefficient descriptors */ for (i = 1; i <= P->m; i++) { row = P->row[i]; for (aij = row->ptr; aij != NULL; aij = aij->r_next) xfprintf(fp, "a %d %d %.*g\n", i, aij->col->j, DBL_DIG, aij->val), count++; } /* write end line */ xfprintf(fp, "e o f\n"), count++; xfflush(fp); if (xferror(fp)) { xprintf("Write error on `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } xprintf("%d lines were written\n", count); ret = 0; done: if (fp != NULL) xfclose(fp); return ret; } /**********************************************************************/ int glp_read_cnfsat(glp_prob *P, const char *fname) { /* read CNF-SAT problem data in DIMACS format */ struct csa _csa, *csa = &_csa; int m, n, i, j, len, neg, rhs, ret = 0, *ind = NULL; double *val = NULL; char *map = NULL; if (P == NULL || P->magic != GLP_PROB_MAGIC) xerror("glp_read_cnfsat: P = %p; invalid problem object\n", P); if (fname == NULL) xerror("glp_read_cnfsat: fname = %p; invalid parameter\n", fname); glp_erase_prob(P); if (setjmp(csa->jump)) { ret = 1; goto done; } csa->fname = fname; csa->fp = NULL; csa->count = 0; csa->c = '\n'; csa->field[0] = '\0'; csa->empty = csa->nonint = 0; xprintf("Reading CNF-SAT problem data from `%s'...\n", fname); csa->fp = xfopen(fname, "r"); if (csa->fp == NULL) { xprintf("Unable to open `%s' - %s\n", fname, xerrmsg()); longjmp(csa->jump, 1); } /* read problem line */ read_designator(csa); if (strcmp(csa->field, "p") != 0) error(csa, "problem line missing or invalid"); read_field(csa); if (strcmp(csa->field, "cnf") != 0) error(csa, "wrong problem designator; `cnf' expected\n"); read_field(csa); if (!(str2int(csa->field, &n) == 0 && n >= 0)) error(csa, "number of variables missing or invalid\n"); read_field(csa); if (!(str2int(csa->field, &m) == 0 && m >= 0)) error(csa, "number of clauses missing or invalid\n"); xprintf("Instance has %d variable%s and %d clause%s\n", n, n == 1 ? "" : "s", m, m == 1 ? "" : "s"); end_of_line(csa); if (m > 0) glp_add_rows(P, m); if (n > 0) { glp_add_cols(P, n); for (j = 1; j <= n; j++) glp_set_col_kind(P, j, GLP_BV); } /* allocate working arrays */ ind = xcalloc(1+n, sizeof(int)); val = xcalloc(1+n, sizeof(double)); map = xcalloc(1+n, sizeof(char)); for (j = 1; j <= n; j++) map[j] = 0; /* read clauses */ for (i = 1; i <= m; i++) { /* read i-th clause */ len = 0, rhs = 1; for (;;) { /* skip white-space characters */ while (csa->c == ' ' || csa->c == '\n') read_char(csa); /* read term */ read_field(csa); if (str2int(csa->field, &j) != 0) error(csa, "variable number missing or invalid\n"); if (j > 0) neg = 0; else if (j < 0) neg = 1, j = -j, rhs--; else break; if (!(1 <= j && j <= n)) error(csa, "variable number out of range\n"); if (map[j]) error(csa, "duplicate variable number\n"); len++, ind[len] = j, val[len] = (neg ? -1.0 : +1.0); map[j] = 1; } glp_set_row_bnds(P, i, GLP_LO, (double)rhs, 0.0); glp_set_mat_row(P, i, len, ind, val); while (len > 0) map[ind[len--]] = 0; } xprintf("%d lines were read\n", csa->count); /* problem data has been successfully read */ glp_sort_matrix(P); done: if (csa->fp != NULL) xfclose(csa->fp); if (ind != NULL) xfree(ind); if (val != NULL) xfree(val); if (map != NULL) xfree(map); if (ret) glp_erase_prob(P); return ret; } /**********************************************************************/ int glp_check_cnfsat(glp_prob *P) { /* check for CNF-SAT problem instance */ int m = P->m; int n = P->n; GLPROW *row; GLPCOL *col; GLPAIJ *aij; int i, j, neg; if (P == NULL || P->magic != GLP_PROB_MAGIC) xerror("glp_check_cnfsat: P = %p; invalid problem object\n", P); /* check columns */ for (j = 1; j <= n; j++) { col = P->col[j]; /* the variable should be binary */ if (!(col->kind == GLP_IV && col->type == GLP_DB && col->lb == 0.0 && col->ub == 1.0)) return 1; } /* objective function should be zero */ if (P->c0 != 0.0) return 2; for (j = 1; j <= n; j++) { col = P->col[j]; if (col->coef != 0.0) return 3; } /* check rows */ for (i = 1; i <= m; i++) { row = P->row[i]; /* the row should be of ">=" type */ if (row->type != GLP_LO) return 4; /* check constraint coefficients */ neg = 0; for (aij = row->ptr; aij != NULL; aij = aij->r_next) { /* the constraint coefficient should be +1 or -1 */ if (aij->val == +1.0) ; else if (aij->val == -1.0) neg++; else return 5; } /* the right-hand side should be (1 - neg), where neg is the number of negative constraint coefficients in the row */ if (row->lb != (double)(1 - neg)) return 6; } /* congratulations; this is CNF-SAT */ return 0; } /**********************************************************************/ int glp_write_cnfsat(glp_prob *P, const char *fname) { /* write CNF-SAT problem data in DIMACS format */ XFILE *fp = NULL; GLPAIJ *aij; int i, j, len, count = 0, ret; char s[50]; if (P == NULL || P->magic != GLP_PROB_MAGIC) xerror("glp_write_cnfsat: P = %p; invalid problem object\n", P); if (glp_check_cnfsat(P) != 0) { xprintf("glp_write_cnfsat: problem object does not encode CNF-" "SAT instance\n"); ret = 1; goto done; } xprintf("Writing CNF-SAT problem data to `%s'...\n", fname); fp = xfopen(fname, "w"); if (fp == NULL) { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } xfprintf(fp, "c %s\n", P->name == NULL ? "unknown" : P->name), count++; xfprintf(fp, "p cnf %d %d\n", P->n, P->m), count++; for (i = 1; i <= P->m; i++) { len = 0; for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next) { j = aij->col->j; if (aij->val < 0.0) j = -j; sprintf(s, "%d", j); if (len > 0 && len + 1 + strlen(s) > 72) xfprintf(fp, "\n"), count++, len = 0; xfprintf(fp, "%s%s", len == 0 ? "" : " ", s); if (len > 0) len++; len += strlen(s); } if (len > 0 && len + 1 + 1 > 72) xfprintf(fp, "\n"), count++, len = 0; xfprintf(fp, "%s0\n", len == 0 ? "" : " "), count++; } xfprintf(fp, "c eof\n"), count++; xfflush(fp); if (xferror(fp)) { xprintf("Write error on `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } xprintf("%d lines were written\n", count); ret = 0; done: if (fp != NULL) xfclose(fp); return ret; } /* eof */ Rglpk/src/GLPK/okalg.c0000644000176000001440000003051512245352174014157 0ustar ripleyusers/* okalg.c (out-of-kilter algorithm) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2009, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #include "okalg.h" /*********************************************************************** * NAME * * okalg - out-of-kilter algorithm * * SYNOPSIS * * #include "okalg.h" * int okalg(int nv, int na, const int tail[], const int head[], * const int low[], const int cap[], const int cost[], int x[], * int pi[]); * * DESCRIPTION * * The routine okalg implements the out-of-kilter algorithm to find a * minimal-cost circulation in the specified flow network. * * INPUT PARAMETERS * * nv is the number of nodes, nv >= 0. * * na is the number of arcs, na >= 0. * * tail[a], a = 1,...,na, is the index of tail node of arc a. * * head[a], a = 1,...,na, is the index of head node of arc a. * * low[a], a = 1,...,na, is an lower bound to the flow through arc a. * * cap[a], a = 1,...,na, is an upper bound to the flow through arc a, * which is the capacity of the arc. * * cost[a], a = 1,...,na, is a per-unit cost of the flow through arc a. * * NOTES * * 1. Multiple arcs are allowed, but self-loops are not allowed. * * 2. It is required that 0 <= low[a] <= cap[a] for all arcs. * * 3. Arc costs may have any sign. * * OUTPUT PARAMETERS * * x[a], a = 1,...,na, is optimal value of the flow through arc a. * * pi[i], i = 1,...,nv, is Lagrange multiplier for flow conservation * equality constraint corresponding to node i (the node potential). * * RETURNS * * 0 optimal circulation found; * * 1 there is no feasible circulation; * * 2 integer overflow occured; * * 3 optimality test failed (logic error). * * REFERENCES * * L.R.Ford, Jr., and D.R.Fulkerson, "Flows in Networks," The RAND * Corp., Report R-375-PR (August 1962), Chap. III "Minimal Cost Flow * Problems," pp.113-26. */ static int overflow(int u, int v) { /* check for integer overflow on computing u + v */ if (u > 0 && v > 0 && u + v < 0) return 1; if (u < 0 && v < 0 && u + v > 0) return 1; return 0; } int okalg(int nv, int na, const int tail[], const int head[], const int low[], const int cap[], const int cost[], int x[], int pi[]) { int a, aok, delta, i, j, k, lambda, pos1, pos2, s, t, temp, ret, *ptr, *arc, *link, *list; /* sanity checks */ xassert(nv >= 0); xassert(na >= 0); for (a = 1; a <= na; a++) { i = tail[a], j = head[a]; xassert(1 <= i && i <= nv); xassert(1 <= j && j <= nv); xassert(i != j); xassert(0 <= low[a] && low[a] <= cap[a]); } /* allocate working arrays */ ptr = xcalloc(1+nv+1, sizeof(int)); arc = xcalloc(1+na+na, sizeof(int)); link = xcalloc(1+nv, sizeof(int)); list = xcalloc(1+nv, sizeof(int)); /* ptr[i] := (degree of node i) */ for (i = 1; i <= nv; i++) ptr[i] = 0; for (a = 1; a <= na; a++) { ptr[tail[a]]++; ptr[head[a]]++; } /* initialize arc pointers */ ptr[1]++; for (i = 1; i < nv; i++) ptr[i+1] += ptr[i]; ptr[nv+1] = ptr[nv]; /* build arc lists */ for (a = 1; a <= na; a++) { arc[--ptr[tail[a]]] = a; arc[--ptr[head[a]]] = a; } xassert(ptr[1] == 1); xassert(ptr[nv+1] == na+na+1); /* now the indices of arcs incident to node i are stored in * locations arc[ptr[i]], arc[ptr[i]+1], ..., arc[ptr[i+1]-1] */ /* initialize arc flows and node potentials */ for (a = 1; a <= na; a++) x[a] = 0; for (i = 1; i <= nv; i++) pi[i] = 0; loop: /* main loop starts here */ /* find out-of-kilter arc */ aok = 0; for (a = 1; a <= na; a++) { i = tail[a], j = head[a]; if (overflow(cost[a], pi[i] - pi[j])) { ret = 2; goto done; } lambda = cost[a] + (pi[i] - pi[j]); if (x[a] < low[a] || (lambda < 0 && x[a] < cap[a])) { /* arc a = i->j is out of kilter, and we need to increase * the flow through this arc */ aok = a, s = j, t = i; break; } if (x[a] > cap[a] || (lambda > 0 && x[a] > low[a])) { /* arc a = i->j is out of kilter, and we need to decrease * the flow through this arc */ aok = a, s = i, t = j; break; } } if (aok == 0) { /* all arcs are in kilter */ /* check for feasibility */ for (a = 1; a <= na; a++) { if (!(low[a] <= x[a] && x[a] <= cap[a])) { ret = 3; goto done; } } for (i = 1; i <= nv; i++) { temp = 0; for (k = ptr[i]; k < ptr[i+1]; k++) { a = arc[k]; if (tail[a] == i) { /* a is outgoing arc */ temp += x[a]; } else if (head[a] == i) { /* a is incoming arc */ temp -= x[a]; } else xassert(a != a); } if (temp != 0) { ret = 3; goto done; } } /* check for optimality */ for (a = 1; a <= na; a++) { i = tail[a], j = head[a]; lambda = cost[a] + (pi[i] - pi[j]); if ((lambda > 0 && x[a] != low[a]) || (lambda < 0 && x[a] != cap[a])) { ret = 3; goto done; } } /* current circulation is optimal */ ret = 0; goto done; } /* now we need to find a cycle (t, a, s, ..., t), which allows * increasing the flow along it, where a is the out-of-kilter arc * just found */ /* link[i] = 0 means that node i is not labelled yet; * link[i] = a means that arc a immediately precedes node i */ /* initially only node s is labelled */ for (i = 1; i <= nv; i++) link[i] = 0; link[s] = aok, list[1] = s, pos1 = pos2 = 1; /* breadth first search */ while (pos1 <= pos2) { /* dequeue node i */ i = list[pos1++]; /* consider all arcs incident to node i */ for (k = ptr[i]; k < ptr[i+1]; k++) { a = arc[k]; if (tail[a] == i) { /* a = i->j is a forward arc from s to t */ j = head[a]; /* if node j has been labelled, skip the arc */ if (link[j] != 0) continue; /* if the arc does not allow increasing the flow through * it, skip the arc */ if (x[a] >= cap[a]) continue; if (overflow(cost[a], pi[i] - pi[j])) { ret = 2; goto done; } lambda = cost[a] + (pi[i] - pi[j]); if (lambda > 0 && x[a] >= low[a]) continue; } else if (head[a] == i) { /* a = i<-j is a backward arc from s to t */ j = tail[a]; /* if node j has been labelled, skip the arc */ if (link[j] != 0) continue; /* if the arc does not allow decreasing the flow through * it, skip the arc */ if (x[a] <= low[a]) continue; if (overflow(cost[a], pi[j] - pi[i])) { ret = 2; goto done; } lambda = cost[a] + (pi[j] - pi[i]); if (lambda < 0 && x[a] <= cap[a]) continue; } else xassert(a != a); /* label node j and enqueue it */ link[j] = a, list[++pos2] = j; /* check for breakthrough */ if (j == t) goto brkt; } } /* NONBREAKTHROUGH */ /* consider all arcs, whose one endpoint is labelled and other is * not, and determine maximal change of node potentials */ delta = 0; for (a = 1; a <= na; a++) { i = tail[a], j = head[a]; if (link[i] != 0 && link[j] == 0) { /* a = i->j, where node i is labelled, node j is not */ if (overflow(cost[a], pi[i] - pi[j])) { ret = 2; goto done; } lambda = cost[a] + (pi[i] - pi[j]); if (x[a] <= cap[a] && lambda > 0) if (delta == 0 || delta > + lambda) delta = + lambda; } else if (link[i] == 0 && link[j] != 0) { /* a = j<-i, where node j is labelled, node i is not */ if (overflow(cost[a], pi[i] - pi[j])) { ret = 2; goto done; } lambda = cost[a] + (pi[i] - pi[j]); if (x[a] >= low[a] && lambda < 0) if (delta == 0 || delta > - lambda) delta = - lambda; } } if (delta == 0) { /* there is no feasible circulation */ ret = 1; goto done; } /* increase potentials of all unlabelled nodes */ for (i = 1; i <= nv; i++) { if (link[i] == 0) { if (overflow(pi[i], delta)) { ret = 2; goto done; } pi[i] += delta; } } goto loop; brkt: /* BREAKTHROUGH */ /* walk through arcs of the cycle (t, a, s, ..., t) found in the * reverse order and determine maximal change of the flow */ delta = 0; for (j = t;; j = i) { /* arc a immediately precedes node j in the cycle */ a = link[j]; if (head[a] == j) { /* a = i->j is a forward arc of the cycle */ i = tail[a]; lambda = cost[a] + (pi[i] - pi[j]); if (lambda > 0 && x[a] < low[a]) { /* x[a] may be increased until its lower bound */ temp = low[a] - x[a]; } else if (lambda <= 0 && x[a] < cap[a]) { /* x[a] may be increased until its upper bound */ temp = cap[a] - x[a]; } else xassert(a != a); } else if (tail[a] == j) { /* a = i<-j is a backward arc of the cycle */ i = head[a]; lambda = cost[a] + (pi[j] - pi[i]); if (lambda < 0 && x[a] > cap[a]) { /* x[a] may be decreased until its upper bound */ temp = x[a] - cap[a]; } else if (lambda >= 0 && x[a] > low[a]) { /* x[a] may be decreased until its lower bound */ temp = x[a] - low[a]; } else xassert(a != a); } else xassert(a != a); if (delta == 0 || delta > temp) delta = temp; /* check for end of the cycle */ if (i == t) break; } xassert(delta > 0); /* increase the flow along the cycle */ for (j = t;; j = i) { /* arc a immediately precedes node j in the cycle */ a = link[j]; if (head[a] == j) { /* a = i->j is a forward arc of the cycle */ i = tail[a]; /* overflow cannot occur */ x[a] += delta; } else if (tail[a] == j) { /* a = i<-j is a backward arc of the cycle */ i = head[a]; /* overflow cannot occur */ x[a] -= delta; } else xassert(a != a); /* check for end of the cycle */ if (i == t) break; } goto loop; done: /* free working arrays */ xfree(ptr); xfree(arc); xfree(link); xfree(list); return ret; } /* eof */ Rglpk/src/GLPK/glpapi10.c0000644000176000001440000002433212245352174014477 0ustar ripleyusers/* glpapi10.c (solution checking routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpapi.h" void glp_check_kkt(glp_prob *P, int sol, int cond, double *_ae_max, int *_ae_ind, double *_re_max, int *_re_ind) { /* check feasibility and optimality conditions */ int m = P->m; int n = P->n; GLPROW *row; GLPCOL *col; GLPAIJ *aij; int i, j, ae_ind, re_ind; double e, sp, sn, t, ae_max, re_max; if (!(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP)) xerror("glp_check_kkt: sol = %d; invalid solution indicator\n", sol); if (!(cond == GLP_KKT_PE || cond == GLP_KKT_PB || cond == GLP_KKT_DE || cond == GLP_KKT_DB || cond == GLP_KKT_CS)) xerror("glp_check_kkt: cond = %d; invalid condition indicator " "\n", cond); ae_max = re_max = 0.0; ae_ind = re_ind = 0; if (cond == GLP_KKT_PE) { /* xR - A * xS = 0 */ for (i = 1; i <= m; i++) { row = P->row[i]; sp = sn = 0.0; /* t := xR[i] */ if (sol == GLP_SOL) t = row->prim; else if (sol == GLP_IPT) t = row->pval; else if (sol == GLP_MIP) t = row->mipx; else xassert(sol != sol); if (t >= 0.0) sp += t; else sn -= t; for (aij = row->ptr; aij != NULL; aij = aij->r_next) { col = aij->col; /* t := - a[i,j] * xS[j] */ if (sol == GLP_SOL) t = - aij->val * col->prim; else if (sol == GLP_IPT) t = - aij->val * col->pval; else if (sol == GLP_MIP) t = - aij->val * col->mipx; else xassert(sol != sol); if (t >= 0.0) sp += t; else sn -= t; } /* absolute error */ e = fabs(sp - sn); if (ae_max < e) ae_max = e, ae_ind = i; /* relative error */ e /= (1.0 + sp + sn); if (re_max < e) re_max = e, re_ind = i; } } else if (cond == GLP_KKT_PB) { /* lR <= xR <= uR */ for (i = 1; i <= m; i++) { row = P->row[i]; /* t := xR[i] */ if (sol == GLP_SOL) t = row->prim; else if (sol == GLP_IPT) t = row->pval; else if (sol == GLP_MIP) t = row->mipx; else xassert(sol != sol); /* check lower bound */ if (row->type == GLP_LO || row->type == GLP_DB || row->type == GLP_FX) { if (t < row->lb) { /* absolute error */ e = row->lb - t; if (ae_max < e) ae_max = e, ae_ind = i; /* relative error */ e /= (1.0 + fabs(row->lb)); if (re_max < e) re_max = e, re_ind = i; } } /* check upper bound */ if (row->type == GLP_UP || row->type == GLP_DB || row->type == GLP_FX) { if (t > row->ub) { /* absolute error */ e = t - row->ub; if (ae_max < e) ae_max = e, ae_ind = i; /* relative error */ e /= (1.0 + fabs(row->ub)); if (re_max < e) re_max = e, re_ind = i; } } } /* lS <= xS <= uS */ for (j = 1; j <= n; j++) { col = P->col[j]; /* t := xS[j] */ if (sol == GLP_SOL) t = col->prim; else if (sol == GLP_IPT) t = col->pval; else if (sol == GLP_MIP) t = col->mipx; else xassert(sol != sol); /* check lower bound */ if (col->type == GLP_LO || col->type == GLP_DB || col->type == GLP_FX) { if (t < col->lb) { /* absolute error */ e = col->lb - t; if (ae_max < e) ae_max = e, ae_ind = m+j; /* relative error */ e /= (1.0 + fabs(col->lb)); if (re_max < e) re_max = e, re_ind = m+j; } } /* check upper bound */ if (col->type == GLP_UP || col->type == GLP_DB || col->type == GLP_FX) { if (t > col->ub) { /* absolute error */ e = t - col->ub; if (ae_max < e) ae_max = e, ae_ind = m+j; /* relative error */ e /= (1.0 + fabs(col->ub)); if (re_max < e) re_max = e, re_ind = m+j; } } } } else if (cond == GLP_KKT_DE) { /* A' * (lambdaR - cR) + (lambdaS - cS) = 0 */ for (j = 1; j <= n; j++) { col = P->col[j]; sp = sn = 0.0; /* t := lambdaS[j] - cS[j] */ if (sol == GLP_SOL) t = col->dual - col->coef; else if (sol == GLP_IPT) t = col->dval - col->coef; else xassert(sol != sol); if (t >= 0.0) sp += t; else sn -= t; for (aij = col->ptr; aij != NULL; aij = aij->c_next) { row = aij->row; /* t := a[i,j] * (lambdaR[i] - cR[i]) */ if (sol == GLP_SOL) t = aij->val * row->dual; else if (sol == GLP_IPT) t = aij->val * row->dval; else xassert(sol != sol); if (t >= 0.0) sp += t; else sn -= t; } /* absolute error */ e = fabs(sp - sn); if (ae_max < e) ae_max = e, ae_ind = m+j; /* relative error */ e /= (1.0 + sp + sn); if (re_max < e) re_max = e, re_ind = m+j; } } else if (cond == GLP_KKT_DB) { /* check lambdaR */ for (i = 1; i <= m; i++) { row = P->row[i]; /* t := lambdaR[i] */ if (sol == GLP_SOL) t = row->dual; else if (sol == GLP_IPT) t = row->dval; else xassert(sol != sol); /* correct sign */ if (P->dir == GLP_MIN) t = + t; else if (P->dir == GLP_MAX) t = - t; else xassert(P != P); /* check for positivity */ #if 1 /* 08/III-2013 */ /* the former check was correct */ /* the bug reported by David Price is related to violation of complementarity slackness, not to this condition */ if (row->type == GLP_FR || row->type == GLP_LO) #else if (row->stat == GLP_NF || row->stat == GLP_NL) #endif { if (t < 0.0) { e = - t; if (ae_max < e) ae_max = re_max = e, ae_ind = re_ind = i; } } /* check for negativity */ #if 1 /* 08/III-2013 */ /* see comment above */ if (row->type == GLP_FR || row->type == GLP_UP) #else if (row->stat == GLP_NF || row->stat == GLP_NU) #endif { if (t > 0.0) { e = + t; if (ae_max < e) ae_max = re_max = e, ae_ind = re_ind = i; } } } /* check lambdaS */ for (j = 1; j <= n; j++) { col = P->col[j]; /* t := lambdaS[j] */ if (sol == GLP_SOL) t = col->dual; else if (sol == GLP_IPT) t = col->dval; else xassert(sol != sol); /* correct sign */ if (P->dir == GLP_MIN) t = + t; else if (P->dir == GLP_MAX) t = - t; else xassert(P != P); /* check for positivity */ #if 1 /* 08/III-2013 */ /* see comment above */ if (col->type == GLP_FR || col->type == GLP_LO) #else if (col->stat == GLP_NF || col->stat == GLP_NL) #endif { if (t < 0.0) { e = - t; if (ae_max < e) ae_max = re_max = e, ae_ind = re_ind = m+j; } } /* check for negativity */ #if 1 /* 08/III-2013 */ /* see comment above */ if (col->type == GLP_FR || col->type == GLP_UP) #else if (col->stat == GLP_NF || col->stat == GLP_NU) #endif { if (t > 0.0) { e = + t; if (ae_max < e) ae_max = re_max = e, ae_ind = re_ind = m+j; } } } } else xassert(cond != cond); if (_ae_max != NULL) *_ae_max = ae_max; if (_ae_ind != NULL) *_ae_ind = ae_ind; if (_re_max != NULL) *_re_max = re_max; if (_re_ind != NULL) *_re_ind = re_ind; return; } /* eof */ Rglpk/src/GLPK/glpspx01.c0000644000176000001440000030210112245352174014531 0ustar ripleyusers/* glpspx01.c (primal simplex method) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpspx.h" struct csa { /* common storage area */ /*--------------------------------------------------------------*/ /* LP data */ int m; /* number of rows (auxiliary variables), m > 0 */ int n; /* number of columns (structural variables), n > 0 */ char *type; /* char type[1+m+n]; */ /* type[0] is not used; type[k], 1 <= k <= m+n, is the type of variable x[k]: GLP_FR - free variable GLP_LO - variable with lower bound GLP_UP - variable with upper bound GLP_DB - double-bounded variable GLP_FX - fixed variable */ double *lb; /* double lb[1+m+n]; */ /* lb[0] is not used; lb[k], 1 <= k <= m+n, is an lower bound of variable x[k]; if x[k] has no lower bound, lb[k] is zero */ double *ub; /* double ub[1+m+n]; */ /* ub[0] is not used; ub[k], 1 <= k <= m+n, is an upper bound of variable x[k]; if x[k] has no upper bound, ub[k] is zero; if x[k] is of fixed type, ub[k] is the same as lb[k] */ double *coef; /* double coef[1+m+n]; */ /* coef[0] is not used; coef[k], 1 <= k <= m+n, is an objective coefficient at variable x[k] (note that on phase I auxiliary variables also may have non-zero objective coefficients) */ /*--------------------------------------------------------------*/ /* original objective function */ double *obj; /* double obj[1+n]; */ /* obj[0] is a constant term of the original objective function; obj[j], 1 <= j <= n, is an original objective coefficient at structural variable x[m+j] */ double zeta; /* factor used to scale original objective coefficients; its sign defines original optimization direction: zeta > 0 means minimization, zeta < 0 means maximization */ /*--------------------------------------------------------------*/ /* constraint matrix A; it has m rows and n columns and is stored by columns */ int *A_ptr; /* int A_ptr[1+n+1]; */ /* A_ptr[0] is not used; A_ptr[j], 1 <= j <= n, is starting position of j-th column in arrays A_ind and A_val; note that A_ptr[1] is always 1; A_ptr[n+1] indicates the position after the last element in arrays A_ind and A_val */ int *A_ind; /* int A_ind[A_ptr[n+1]]; */ /* row indices */ double *A_val; /* double A_val[A_ptr[n+1]]; */ /* non-zero element values */ /*--------------------------------------------------------------*/ /* basis header */ int *head; /* int head[1+m+n]; */ /* head[0] is not used; head[i], 1 <= i <= m, is the ordinal number of basic variable xB[i]; head[i] = k means that xB[i] = x[k] and i-th column of matrix B is k-th column of matrix (I|-A); head[m+j], 1 <= j <= n, is the ordinal number of non-basic variable xN[j]; head[m+j] = k means that xN[j] = x[k] and j-th column of matrix N is k-th column of matrix (I|-A) */ char *stat; /* char stat[1+n]; */ /* stat[0] is not used; stat[j], 1 <= j <= n, is the status of non-basic variable xN[j], which defines its active bound: GLP_NL - lower bound is active GLP_NU - upper bound is active GLP_NF - free variable GLP_NS - fixed variable */ /*--------------------------------------------------------------*/ /* matrix B is the basis matrix; it is composed from columns of the augmented constraint matrix (I|-A) corresponding to basic variables and stored in a factorized (invertable) form */ int valid; /* factorization is valid only if this flag is set */ BFD *bfd; /* BFD bfd[1:m,1:m]; */ /* factorized (invertable) form of the basis matrix */ /*--------------------------------------------------------------*/ /* matrix N is a matrix composed from columns of the augmented constraint matrix (I|-A) corresponding to non-basic variables except fixed ones; it is stored by rows and changes every time the basis changes */ int *N_ptr; /* int N_ptr[1+m+1]; */ /* N_ptr[0] is not used; N_ptr[i], 1 <= i <= m, is starting position of i-th row in arrays N_ind and N_val; note that N_ptr[1] is always 1; N_ptr[m+1] indicates the position after the last element in arrays N_ind and N_val */ int *N_len; /* int N_len[1+m]; */ /* N_len[0] is not used; N_len[i], 1 <= i <= m, is length of i-th row (0 to n) */ int *N_ind; /* int N_ind[N_ptr[m+1]]; */ /* column indices */ double *N_val; /* double N_val[N_ptr[m+1]]; */ /* non-zero element values */ /*--------------------------------------------------------------*/ /* working parameters */ int phase; /* search phase: 0 - not determined yet 1 - search for primal feasible solution 2 - search for optimal solution */ #if 0 /* 10/VI-2013 */ glp_long tm_beg; /* time value at the beginning of the search */ #else double tm_beg; #endif int it_beg; /* simplex iteration count at the beginning of the search */ int it_cnt; /* simplex iteration count; it increases by one every time the basis changes (including the case when a non-basic variable jumps to its opposite bound) */ int it_dpy; /* simplex iteration count at the most recent display output */ /*--------------------------------------------------------------*/ /* basic solution components */ double *bbar; /* double bbar[1+m]; */ /* bbar[0] is not used; bbar[i], 1 <= i <= m, is primal value of basic variable xB[i] (if xB[i] is free, its primal value is not updated) */ double *cbar; /* double cbar[1+n]; */ /* cbar[0] is not used; cbar[j], 1 <= j <= n, is reduced cost of non-basic variable xN[j] (if xN[j] is fixed, its reduced cost is not updated) */ /*--------------------------------------------------------------*/ /* the following pricing technique options may be used: GLP_PT_STD - standard ("textbook") pricing; GLP_PT_PSE - projected steepest edge; GLP_PT_DVX - Devex pricing (not implemented yet); in case of GLP_PT_STD the reference space is not used, and all steepest edge coefficients are set to 1 */ int refct; /* this count is set to an initial value when the reference space is defined and decreases by one every time the basis changes; once this count reaches zero, the reference space is redefined again */ char *refsp; /* char refsp[1+m+n]; */ /* refsp[0] is not used; refsp[k], 1 <= k <= m+n, is the flag which means that variable x[k] belongs to the current reference space */ double *gamma; /* double gamma[1+n]; */ /* gamma[0] is not used; gamma[j], 1 <= j <= n, is the steepest edge coefficient for non-basic variable xN[j]; if xN[j] is fixed, gamma[j] is not used and just set to 1 */ /*--------------------------------------------------------------*/ /* non-basic variable xN[q] chosen to enter the basis */ int q; /* index of the non-basic variable xN[q] chosen, 1 <= q <= n; if the set of eligible non-basic variables is empty and thus no variable has been chosen, q is set to 0 */ /*--------------------------------------------------------------*/ /* pivot column of the simplex table corresponding to non-basic variable xN[q] chosen is the following vector: T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q], where B is the current basis matrix, N[q] is a column of the matrix (I|-A) corresponding to xN[q] */ int tcol_nnz; /* number of non-zero components, 0 <= nnz <= m */ int *tcol_ind; /* int tcol_ind[1+m]; */ /* tcol_ind[0] is not used; tcol_ind[t], 1 <= t <= nnz, is an index of non-zero component, i.e. tcol_ind[t] = i means that tcol_vec[i] != 0 */ double *tcol_vec; /* double tcol_vec[1+m]; */ /* tcol_vec[0] is not used; tcol_vec[i], 1 <= i <= m, is a numeric value of i-th component of the column */ double tcol_max; /* infinity (maximum) norm of the column (max |tcol_vec[i]|) */ int tcol_num; /* number of significant non-zero components, which means that: |tcol_vec[i]| >= eps for i in tcol_ind[1,...,num], |tcol_vec[i]| < eps for i in tcol_ind[num+1,...,nnz], where eps is a pivot tolerance */ /*--------------------------------------------------------------*/ /* basic variable xB[p] chosen to leave the basis */ int p; /* index of the basic variable xB[p] chosen, 1 <= p <= m; p = 0 means that no basic variable reaches its bound; p < 0 means that non-basic variable xN[q] reaches its opposite bound before any basic variable */ int p_stat; /* new status (GLP_NL, GLP_NU, or GLP_NS) to be assigned to xB[p] once it has left the basis */ double teta; /* change of non-basic variable xN[q] (see above), on which xB[p] (or, if p < 0, xN[q] itself) reaches its bound */ /*--------------------------------------------------------------*/ /* pivot row of the simplex table corresponding to basic variable xB[p] chosen is the following vector: T' * e[p] = - N' * inv(B') * e[p] = - N' * rho, where B' is a matrix transposed to the current basis matrix, N' is a matrix, whose rows are columns of the matrix (I|-A) corresponding to non-basic non-fixed variables */ int trow_nnz; /* number of non-zero components, 0 <= nnz <= n */ int *trow_ind; /* int trow_ind[1+n]; */ /* trow_ind[0] is not used; trow_ind[t], 1 <= t <= nnz, is an index of non-zero component, i.e. trow_ind[t] = j means that trow_vec[j] != 0 */ double *trow_vec; /* int trow_vec[1+n]; */ /* trow_vec[0] is not used; trow_vec[j], 1 <= j <= n, is a numeric value of j-th component of the row */ /*--------------------------------------------------------------*/ /* working arrays */ double *work1; /* double work1[1+m]; */ double *work2; /* double work2[1+m]; */ double *work3; /* double work3[1+m]; */ double *work4; /* double work4[1+m]; */ }; static const double kappa = 0.10; /*********************************************************************** * alloc_csa - allocate common storage area * * This routine allocates all arrays in the common storage area (CSA) * and returns a pointer to the CSA. */ static struct csa *alloc_csa(glp_prob *lp) { struct csa *csa; int m = lp->m; int n = lp->n; int nnz = lp->nnz; csa = xmalloc(sizeof(struct csa)); xassert(m > 0 && n > 0); csa->m = m; csa->n = n; csa->type = xcalloc(1+m+n, sizeof(char)); csa->lb = xcalloc(1+m+n, sizeof(double)); csa->ub = xcalloc(1+m+n, sizeof(double)); csa->coef = xcalloc(1+m+n, sizeof(double)); csa->obj = xcalloc(1+n, sizeof(double)); csa->A_ptr = xcalloc(1+n+1, sizeof(int)); csa->A_ind = xcalloc(1+nnz, sizeof(int)); csa->A_val = xcalloc(1+nnz, sizeof(double)); csa->head = xcalloc(1+m+n, sizeof(int)); csa->stat = xcalloc(1+n, sizeof(char)); csa->N_ptr = xcalloc(1+m+1, sizeof(int)); csa->N_len = xcalloc(1+m, sizeof(int)); csa->N_ind = NULL; /* will be allocated later */ csa->N_val = NULL; /* will be allocated later */ csa->bbar = xcalloc(1+m, sizeof(double)); csa->cbar = xcalloc(1+n, sizeof(double)); csa->refsp = xcalloc(1+m+n, sizeof(char)); csa->gamma = xcalloc(1+n, sizeof(double)); csa->tcol_ind = xcalloc(1+m, sizeof(int)); csa->tcol_vec = xcalloc(1+m, sizeof(double)); csa->trow_ind = xcalloc(1+n, sizeof(int)); csa->trow_vec = xcalloc(1+n, sizeof(double)); csa->work1 = xcalloc(1+m, sizeof(double)); csa->work2 = xcalloc(1+m, sizeof(double)); csa->work3 = xcalloc(1+m, sizeof(double)); csa->work4 = xcalloc(1+m, sizeof(double)); return csa; } /*********************************************************************** * init_csa - initialize common storage area * * This routine initializes all data structures in the common storage * area (CSA). */ static void alloc_N(struct csa *csa); static void build_N(struct csa *csa); static void init_csa(struct csa *csa, glp_prob *lp) { int m = csa->m; int n = csa->n; char *type = csa->type; double *lb = csa->lb; double *ub = csa->ub; double *coef = csa->coef; double *obj = csa->obj; int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int *head = csa->head; char *stat = csa->stat; char *refsp = csa->refsp; double *gamma = csa->gamma; int i, j, k, loc; double cmax; /* auxiliary variables */ for (i = 1; i <= m; i++) { GLPROW *row = lp->row[i]; type[i] = (char)row->type; lb[i] = row->lb * row->rii; ub[i] = row->ub * row->rii; coef[i] = 0.0; } /* structural variables */ for (j = 1; j <= n; j++) { GLPCOL *col = lp->col[j]; type[m+j] = (char)col->type; lb[m+j] = col->lb / col->sjj; ub[m+j] = col->ub / col->sjj; coef[m+j] = col->coef * col->sjj; } /* original objective function */ obj[0] = lp->c0; memcpy(&obj[1], &coef[m+1], n * sizeof(double)); /* factor used to scale original objective coefficients */ cmax = 0.0; for (j = 1; j <= n; j++) if (cmax < fabs(obj[j])) cmax = fabs(obj[j]); if (cmax == 0.0) cmax = 1.0; switch (lp->dir) { case GLP_MIN: csa->zeta = + 1.0 / cmax; break; case GLP_MAX: csa->zeta = - 1.0 / cmax; break; default: xassert(lp != lp); } #if 1 if (fabs(csa->zeta) < 1.0) csa->zeta *= 1000.0; #endif /* matrix A (by columns) */ loc = 1; for (j = 1; j <= n; j++) { GLPAIJ *aij; A_ptr[j] = loc; for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next) { A_ind[loc] = aij->row->i; A_val[loc] = aij->row->rii * aij->val * aij->col->sjj; loc++; } } A_ptr[n+1] = loc; xassert(loc == lp->nnz+1); /* basis header */ xassert(lp->valid); memcpy(&head[1], &lp->head[1], m * sizeof(int)); k = 0; for (i = 1; i <= m; i++) { GLPROW *row = lp->row[i]; if (row->stat != GLP_BS) { k++; xassert(k <= n); head[m+k] = i; stat[k] = (char)row->stat; } } for (j = 1; j <= n; j++) { GLPCOL *col = lp->col[j]; if (col->stat != GLP_BS) { k++; xassert(k <= n); head[m+k] = m + j; stat[k] = (char)col->stat; } } xassert(k == n); /* factorization of matrix B */ csa->valid = 1, lp->valid = 0; csa->bfd = lp->bfd, lp->bfd = NULL; /* matrix N (by rows) */ alloc_N(csa); build_N(csa); /* working parameters */ csa->phase = 0; csa->tm_beg = xtime(); csa->it_beg = csa->it_cnt = lp->it_cnt; csa->it_dpy = -1; /* reference space and steepest edge coefficients */ csa->refct = 0; memset(&refsp[1], 0, (m+n) * sizeof(char)); for (j = 1; j <= n; j++) gamma[j] = 1.0; return; } /*********************************************************************** * invert_B - compute factorization of the basis matrix * * This routine computes factorization of the current basis matrix B. * * If the operation is successful, the routine returns zero, otherwise * non-zero. */ static int inv_col(void *info, int i, int ind[], double val[]) { /* this auxiliary routine returns row indices and numeric values of non-zero elements of i-th column of the basis matrix */ struct csa *csa = info; int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int *head = csa->head; int k, len, ptr, t; #ifdef GLP_DEBUG xassert(1 <= i && i <= m); #endif k = head[i]; /* B[i] is k-th column of (I|-A) */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (k <= m) { /* B[i] is k-th column of submatrix I */ len = 1; ind[1] = k; val[1] = 1.0; } else { /* B[i] is (k-m)-th column of submatrix (-A) */ ptr = A_ptr[k-m]; len = A_ptr[k-m+1] - ptr; memcpy(&ind[1], &A_ind[ptr], len * sizeof(int)); memcpy(&val[1], &A_val[ptr], len * sizeof(double)); for (t = 1; t <= len; t++) val[t] = - val[t]; } return len; } static int invert_B(struct csa *csa) { int ret; ret = bfd_factorize(csa->bfd, csa->m, NULL, inv_col, csa); csa->valid = (ret == 0); return ret; } /*********************************************************************** * update_B - update factorization of the basis matrix * * This routine replaces i-th column of the basis matrix B by k-th * column of the augmented constraint matrix (I|-A) and then updates * the factorization of B. * * If the factorization has been successfully updated, the routine * returns zero, otherwise non-zero. */ static int update_B(struct csa *csa, int i, int k) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif int ret; #ifdef GLP_DEBUG xassert(1 <= i && i <= m); xassert(1 <= k && k <= m+n); #endif if (k <= m) { /* new i-th column of B is k-th column of I */ int ind[1+1]; double val[1+1]; ind[1] = k; val[1] = 1.0; xassert(csa->valid); ret = bfd_update_it(csa->bfd, i, 0, 1, ind, val); } else { /* new i-th column of B is (k-m)-th column of (-A) */ int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; double *val = csa->work1; int beg, end, ptr, len; beg = A_ptr[k-m]; end = A_ptr[k-m+1]; len = 0; for (ptr = beg; ptr < end; ptr++) val[++len] = - A_val[ptr]; xassert(csa->valid); ret = bfd_update_it(csa->bfd, i, 0, len, &A_ind[beg-1], val); } csa->valid = (ret == 0); return ret; } /*********************************************************************** * error_ftran - compute residual vector r = h - B * x * * This routine computes the residual vector r = h - B * x, where B is * the current basis matrix, h is the vector of right-hand sides, x is * the solution vector. */ static void error_ftran(struct csa *csa, double h[], double x[], double r[]) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int *head = csa->head; int i, k, beg, end, ptr; double temp; /* compute the residual vector: r = h - B * x = h - B[1] * x[1] - ... - B[m] * x[m], where B[1], ..., B[m] are columns of matrix B */ memcpy(&r[1], &h[1], m * sizeof(double)); for (i = 1; i <= m; i++) { temp = x[i]; if (temp == 0.0) continue; k = head[i]; /* B[i] is k-th column of (I|-A) */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (k <= m) { /* B[i] is k-th column of submatrix I */ r[k] -= temp; } else { /* B[i] is (k-m)-th column of submatrix (-A) */ beg = A_ptr[k-m]; end = A_ptr[k-m+1]; for (ptr = beg; ptr < end; ptr++) r[A_ind[ptr]] += A_val[ptr] * temp; } } return; } /*********************************************************************** * refine_ftran - refine solution of B * x = h * * This routine performs one iteration to refine the solution of * the system B * x = h, where B is the current basis matrix, h is the * vector of right-hand sides, x is the solution vector. */ static void refine_ftran(struct csa *csa, double h[], double x[]) { int m = csa->m; double *r = csa->work1; double *d = csa->work1; int i; /* compute the residual vector r = h - B * x */ error_ftran(csa, h, x, r); /* compute the correction vector d = inv(B) * r */ xassert(csa->valid); bfd_ftran(csa->bfd, d); /* refine the solution vector (new x) = (old x) + d */ for (i = 1; i <= m; i++) x[i] += d[i]; return; } /*********************************************************************** * error_btran - compute residual vector r = h - B'* x * * This routine computes the residual vector r = h - B'* x, where B' * is a matrix transposed to the current basis matrix, h is the vector * of right-hand sides, x is the solution vector. */ static void error_btran(struct csa *csa, double h[], double x[], double r[]) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int *head = csa->head; int i, k, beg, end, ptr; double temp; /* compute the residual vector r = b - B'* x */ for (i = 1; i <= m; i++) { /* r[i] := b[i] - (i-th column of B)'* x */ k = head[i]; /* B[i] is k-th column of (I|-A) */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif temp = h[i]; if (k <= m) { /* B[i] is k-th column of submatrix I */ temp -= x[k]; } else { /* B[i] is (k-m)-th column of submatrix (-A) */ beg = A_ptr[k-m]; end = A_ptr[k-m+1]; for (ptr = beg; ptr < end; ptr++) temp += A_val[ptr] * x[A_ind[ptr]]; } r[i] = temp; } return; } /*********************************************************************** * refine_btran - refine solution of B'* x = h * * This routine performs one iteration to refine the solution of the * system B'* x = h, where B' is a matrix transposed to the current * basis matrix, h is the vector of right-hand sides, x is the solution * vector. */ static void refine_btran(struct csa *csa, double h[], double x[]) { int m = csa->m; double *r = csa->work1; double *d = csa->work1; int i; /* compute the residual vector r = h - B'* x */ error_btran(csa, h, x, r); /* compute the correction vector d = inv(B') * r */ xassert(csa->valid); bfd_btran(csa->bfd, d); /* refine the solution vector (new x) = (old x) + d */ for (i = 1; i <= m; i++) x[i] += d[i]; return; } /*********************************************************************** * alloc_N - allocate matrix N * * This routine determines maximal row lengths of matrix N, sets its * row pointers, and then allocates arrays N_ind and N_val. * * Note that some fixed structural variables may temporarily become * double-bounded, so corresponding columns of matrix A should not be * ignored on calculating maximal row lengths of matrix N. */ static void alloc_N(struct csa *csa) { int m = csa->m; int n = csa->n; int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; int *N_ptr = csa->N_ptr; int *N_len = csa->N_len; int i, j, beg, end, ptr; /* determine number of non-zeros in each row of the augmented constraint matrix (I|-A) */ for (i = 1; i <= m; i++) N_len[i] = 1; for (j = 1; j <= n; j++) { beg = A_ptr[j]; end = A_ptr[j+1]; for (ptr = beg; ptr < end; ptr++) N_len[A_ind[ptr]]++; } /* determine maximal row lengths of matrix N and set its row pointers */ N_ptr[1] = 1; for (i = 1; i <= m; i++) { /* row of matrix N cannot have more than n non-zeros */ if (N_len[i] > n) N_len[i] = n; N_ptr[i+1] = N_ptr[i] + N_len[i]; } /* now maximal number of non-zeros in matrix N is known */ csa->N_ind = xcalloc(N_ptr[m+1], sizeof(int)); csa->N_val = xcalloc(N_ptr[m+1], sizeof(double)); return; } /*********************************************************************** * add_N_col - add column of matrix (I|-A) to matrix N * * This routine adds j-th column to matrix N which is k-th column of * the augmented constraint matrix (I|-A). (It is assumed that old j-th * column was previously removed from matrix N.) */ static void add_N_col(struct csa *csa, int j, int k) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif int *N_ptr = csa->N_ptr; int *N_len = csa->N_len; int *N_ind = csa->N_ind; double *N_val = csa->N_val; int pos; #ifdef GLP_DEBUG xassert(1 <= j && j <= n); xassert(1 <= k && k <= m+n); #endif if (k <= m) { /* N[j] is k-th column of submatrix I */ pos = N_ptr[k] + (N_len[k]++); #ifdef GLP_DEBUG xassert(pos < N_ptr[k+1]); #endif N_ind[pos] = j; N_val[pos] = 1.0; } else { /* N[j] is (k-m)-th column of submatrix (-A) */ int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int i, beg, end, ptr; beg = A_ptr[k-m]; end = A_ptr[k-m+1]; for (ptr = beg; ptr < end; ptr++) { i = A_ind[ptr]; /* row number */ pos = N_ptr[i] + (N_len[i]++); #ifdef GLP_DEBUG xassert(pos < N_ptr[i+1]); #endif N_ind[pos] = j; N_val[pos] = - A_val[ptr]; } } return; } /*********************************************************************** * del_N_col - remove column of matrix (I|-A) from matrix N * * This routine removes j-th column from matrix N which is k-th column * of the augmented constraint matrix (I|-A). */ static void del_N_col(struct csa *csa, int j, int k) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif int *N_ptr = csa->N_ptr; int *N_len = csa->N_len; int *N_ind = csa->N_ind; double *N_val = csa->N_val; int pos, head, tail; #ifdef GLP_DEBUG xassert(1 <= j && j <= n); xassert(1 <= k && k <= m+n); #endif if (k <= m) { /* N[j] is k-th column of submatrix I */ /* find element in k-th row of N */ head = N_ptr[k]; for (pos = head; N_ind[pos] != j; pos++) /* nop */; /* and remove it from the row list */ tail = head + (--N_len[k]); #ifdef GLP_DEBUG xassert(pos <= tail); #endif N_ind[pos] = N_ind[tail]; N_val[pos] = N_val[tail]; } else { /* N[j] is (k-m)-th column of submatrix (-A) */ int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; int i, beg, end, ptr; beg = A_ptr[k-m]; end = A_ptr[k-m+1]; for (ptr = beg; ptr < end; ptr++) { i = A_ind[ptr]; /* row number */ /* find element in i-th row of N */ head = N_ptr[i]; for (pos = head; N_ind[pos] != j; pos++) /* nop */; /* and remove it from the row list */ tail = head + (--N_len[i]); #ifdef GLP_DEBUG xassert(pos <= tail); #endif N_ind[pos] = N_ind[tail]; N_val[pos] = N_val[tail]; } } return; } /*********************************************************************** * build_N - build matrix N for current basis * * This routine builds matrix N for the current basis from columns * of the augmented constraint matrix (I|-A) corresponding to non-basic * non-fixed variables. */ static void build_N(struct csa *csa) { int m = csa->m; int n = csa->n; int *head = csa->head; char *stat = csa->stat; int *N_len = csa->N_len; int j, k; /* N := empty matrix */ memset(&N_len[1], 0, m * sizeof(int)); /* go through non-basic columns of matrix (I|-A) */ for (j = 1; j <= n; j++) { if (stat[j] != GLP_NS) { /* xN[j] is non-fixed; add j-th column to matrix N which is k-th column of matrix (I|-A) */ k = head[m+j]; /* x[k] = xN[j] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif add_N_col(csa, j, k); } } return; } /*********************************************************************** * get_xN - determine current value of non-basic variable xN[j] * * This routine returns the current value of non-basic variable xN[j], * which is a value of its active bound. */ static double get_xN(struct csa *csa, int j) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif double *lb = csa->lb; double *ub = csa->ub; int *head = csa->head; char *stat = csa->stat; int k; double xN; #ifdef GLP_DEBUG xassert(1 <= j && j <= n); #endif k = head[m+j]; /* x[k] = xN[j] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif switch (stat[j]) { case GLP_NL: /* x[k] is on its lower bound */ xN = lb[k]; break; case GLP_NU: /* x[k] is on its upper bound */ xN = ub[k]; break; case GLP_NF: /* x[k] is free non-basic variable */ xN = 0.0; break; case GLP_NS: /* x[k] is fixed non-basic variable */ xN = lb[k]; break; default: xassert(stat != stat); } return xN; } /*********************************************************************** * eval_beta - compute primal values of basic variables * * This routine computes current primal values of all basic variables: * * beta = - inv(B) * N * xN, * * where B is the current basis matrix, N is a matrix built of columns * of matrix (I|-A) corresponding to non-basic variables, and xN is the * vector of current values of non-basic variables. */ static void eval_beta(struct csa *csa, double beta[]) { int m = csa->m; int n = csa->n; int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int *head = csa->head; double *h = csa->work2; int i, j, k, beg, end, ptr; double xN; /* compute the right-hand side vector: h := - N * xN = - N[1] * xN[1] - ... - N[n] * xN[n], where N[1], ..., N[n] are columns of matrix N */ for (i = 1; i <= m; i++) h[i] = 0.0; for (j = 1; j <= n; j++) { k = head[m+j]; /* x[k] = xN[j] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif /* determine current value of xN[j] */ xN = get_xN(csa, j); if (xN == 0.0) continue; if (k <= m) { /* N[j] is k-th column of submatrix I */ h[k] -= xN; } else { /* N[j] is (k-m)-th column of submatrix (-A) */ beg = A_ptr[k-m]; end = A_ptr[k-m+1]; for (ptr = beg; ptr < end; ptr++) h[A_ind[ptr]] += xN * A_val[ptr]; } } /* solve system B * beta = h */ memcpy(&beta[1], &h[1], m * sizeof(double)); xassert(csa->valid); bfd_ftran(csa->bfd, beta); /* and refine the solution */ refine_ftran(csa, h, beta); return; } /*********************************************************************** * eval_pi - compute vector of simplex multipliers * * This routine computes the vector of current simplex multipliers: * * pi = inv(B') * cB, * * where B' is a matrix transposed to the current basis matrix, cB is * a subvector of objective coefficients at basic variables. */ static void eval_pi(struct csa *csa, double pi[]) { int m = csa->m; double *c = csa->coef; int *head = csa->head; double *cB = csa->work2; int i; /* construct the right-hand side vector cB */ for (i = 1; i <= m; i++) cB[i] = c[head[i]]; /* solve system B'* pi = cB */ memcpy(&pi[1], &cB[1], m * sizeof(double)); xassert(csa->valid); bfd_btran(csa->bfd, pi); /* and refine the solution */ refine_btran(csa, cB, pi); return; } /*********************************************************************** * eval_cost - compute reduced cost of non-basic variable xN[j] * * This routine computes the current reduced cost of non-basic variable * xN[j]: * * d[j] = cN[j] - N'[j] * pi, * * where cN[j] is the objective coefficient at variable xN[j], N[j] is * a column of the augmented constraint matrix (I|-A) corresponding to * xN[j], pi is the vector of simplex multipliers. */ static double eval_cost(struct csa *csa, double pi[], int j) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif double *coef = csa->coef; int *head = csa->head; int k; double dj; #ifdef GLP_DEBUG xassert(1 <= j && j <= n); #endif k = head[m+j]; /* x[k] = xN[j] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif dj = coef[k]; if (k <= m) { /* N[j] is k-th column of submatrix I */ dj -= pi[k]; } else { /* N[j] is (k-m)-th column of submatrix (-A) */ int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int beg, end, ptr; beg = A_ptr[k-m]; end = A_ptr[k-m+1]; for (ptr = beg; ptr < end; ptr++) dj += A_val[ptr] * pi[A_ind[ptr]]; } return dj; } /*********************************************************************** * eval_bbar - compute and store primal values of basic variables * * This routine computes primal values of all basic variables and then * stores them in the solution array. */ static void eval_bbar(struct csa *csa) { eval_beta(csa, csa->bbar); return; } /*********************************************************************** * eval_cbar - compute and store reduced costs of non-basic variables * * This routine computes reduced costs of all non-basic variables and * then stores them in the solution array. */ static void eval_cbar(struct csa *csa) { #ifdef GLP_DEBUG int m = csa->m; #endif int n = csa->n; #ifdef GLP_DEBUG int *head = csa->head; #endif double *cbar = csa->cbar; double *pi = csa->work3; int j; #ifdef GLP_DEBUG int k; #endif /* compute simplex multipliers */ eval_pi(csa, pi); /* compute and store reduced costs */ for (j = 1; j <= n; j++) { #ifdef GLP_DEBUG k = head[m+j]; /* x[k] = xN[j] */ xassert(1 <= k && k <= m+n); #endif cbar[j] = eval_cost(csa, pi, j); } return; } /*********************************************************************** * reset_refsp - reset the reference space * * This routine resets (redefines) the reference space used in the * projected steepest edge pricing algorithm. */ static void reset_refsp(struct csa *csa) { int m = csa->m; int n = csa->n; int *head = csa->head; char *refsp = csa->refsp; double *gamma = csa->gamma; int j, k; xassert(csa->refct == 0); csa->refct = 1000; memset(&refsp[1], 0, (m+n) * sizeof(char)); for (j = 1; j <= n; j++) { k = head[m+j]; /* x[k] = xN[j] */ refsp[k] = 1; gamma[j] = 1.0; } return; } /*********************************************************************** * eval_gamma - compute steepest edge coefficient * * This routine computes the steepest edge coefficient for non-basic * variable xN[j] using its direct definition: * * gamma[j] = delta[j] + sum alfa[i,j]^2, * i in R * * where delta[j] = 1, if xN[j] is in the current reference space, * and 0 otherwise; R is a set of basic variables xB[i], which are in * the current reference space; alfa[i,j] are elements of the current * simplex table. * * NOTE: The routine is intended only for debugginig purposes. */ static double eval_gamma(struct csa *csa, int j) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif int *head = csa->head; char *refsp = csa->refsp; double *alfa = csa->work3; double *h = csa->work3; int i, k; double gamma; #ifdef GLP_DEBUG xassert(1 <= j && j <= n); #endif k = head[m+j]; /* x[k] = xN[j] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif /* construct the right-hand side vector h = - N[j] */ for (i = 1; i <= m; i++) h[i] = 0.0; if (k <= m) { /* N[j] is k-th column of submatrix I */ h[k] = -1.0; } else { /* N[j] is (k-m)-th column of submatrix (-A) */ int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int beg, end, ptr; beg = A_ptr[k-m]; end = A_ptr[k-m+1]; for (ptr = beg; ptr < end; ptr++) h[A_ind[ptr]] = A_val[ptr]; } /* solve system B * alfa = h */ xassert(csa->valid); bfd_ftran(csa->bfd, alfa); /* compute gamma */ gamma = (refsp[k] ? 1.0 : 0.0); for (i = 1; i <= m; i++) { k = head[i]; #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (refsp[k]) gamma += alfa[i] * alfa[i]; } return gamma; } /*********************************************************************** * chuzc - choose non-basic variable (column of the simplex table) * * This routine chooses non-basic variable xN[q], which has largest * weighted reduced cost: * * |d[q]| / sqrt(gamma[q]) = max |d[j]| / sqrt(gamma[j]), * j in J * * where J is a subset of eligible non-basic variables xN[j], d[j] is * reduced cost of xN[j], gamma[j] is the steepest edge coefficient. * * The working objective function is always minimized, so the sign of * d[q] determines direction, in which xN[q] has to change: * * if d[q] < 0, xN[q] has to increase; * * if d[q] > 0, xN[q] has to decrease. * * If |d[j]| <= tol_dj, where tol_dj is a specified tolerance, xN[j] * is not included in J and therefore ignored. (It is assumed that the * working objective row is appropriately scaled, i.e. max|c[k]| = 1.) * * If J is empty and no variable has been chosen, q is set to 0. */ static void chuzc(struct csa *csa, double tol_dj) { int n = csa->n; char *stat = csa->stat; double *cbar = csa->cbar; double *gamma = csa->gamma; int j, q; double dj, best, temp; /* nothing is chosen so far */ q = 0, best = 0.0; /* look through the list of non-basic variables */ for (j = 1; j <= n; j++) { dj = cbar[j]; switch (stat[j]) { case GLP_NL: /* xN[j] can increase */ if (dj >= - tol_dj) continue; break; case GLP_NU: /* xN[j] can decrease */ if (dj <= + tol_dj) continue; break; case GLP_NF: /* xN[j] can change in any direction */ if (- tol_dj <= dj && dj <= + tol_dj) continue; break; case GLP_NS: /* xN[j] cannot change at all */ continue; default: xassert(stat != stat); } /* xN[j] is eligible non-basic variable; choose one which has largest weighted reduced cost */ #ifdef GLP_DEBUG xassert(gamma[j] > 0.0); #endif temp = (dj * dj) / gamma[j]; if (best < temp) q = j, best = temp; } /* store the index of non-basic variable xN[q] chosen */ csa->q = q; return; } /*********************************************************************** * eval_tcol - compute pivot column of the simplex table * * This routine computes the pivot column of the simplex table, which * corresponds to non-basic variable xN[q] chosen. * * The pivot column is the following vector: * * tcol = T * e[q] = - inv(B) * N * e[q] = - inv(B) * N[q], * * where B is the current basis matrix, N[q] is a column of the matrix * (I|-A) corresponding to variable xN[q]. */ static void eval_tcol(struct csa *csa) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif int *head = csa->head; int q = csa->q; int *tcol_ind = csa->tcol_ind; double *tcol_vec = csa->tcol_vec; double *h = csa->tcol_vec; int i, k, nnz; #ifdef GLP_DEBUG xassert(1 <= q && q <= n); #endif k = head[m+q]; /* x[k] = xN[q] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif /* construct the right-hand side vector h = - N[q] */ for (i = 1; i <= m; i++) h[i] = 0.0; if (k <= m) { /* N[q] is k-th column of submatrix I */ h[k] = -1.0; } else { /* N[q] is (k-m)-th column of submatrix (-A) */ int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int beg, end, ptr; beg = A_ptr[k-m]; end = A_ptr[k-m+1]; for (ptr = beg; ptr < end; ptr++) h[A_ind[ptr]] = A_val[ptr]; } /* solve system B * tcol = h */ xassert(csa->valid); bfd_ftran(csa->bfd, tcol_vec); /* construct sparse pattern of the pivot column */ nnz = 0; for (i = 1; i <= m; i++) { if (tcol_vec[i] != 0.0) tcol_ind[++nnz] = i; } csa->tcol_nnz = nnz; return; } /*********************************************************************** * refine_tcol - refine pivot column of the simplex table * * This routine refines the pivot column of the simplex table assuming * that it was previously computed by the routine eval_tcol. */ static void refine_tcol(struct csa *csa) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif int *head = csa->head; int q = csa->q; int *tcol_ind = csa->tcol_ind; double *tcol_vec = csa->tcol_vec; double *h = csa->work3; int i, k, nnz; #ifdef GLP_DEBUG xassert(1 <= q && q <= n); #endif k = head[m+q]; /* x[k] = xN[q] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif /* construct the right-hand side vector h = - N[q] */ for (i = 1; i <= m; i++) h[i] = 0.0; if (k <= m) { /* N[q] is k-th column of submatrix I */ h[k] = -1.0; } else { /* N[q] is (k-m)-th column of submatrix (-A) */ int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int beg, end, ptr; beg = A_ptr[k-m]; end = A_ptr[k-m+1]; for (ptr = beg; ptr < end; ptr++) h[A_ind[ptr]] = A_val[ptr]; } /* refine solution of B * tcol = h */ refine_ftran(csa, h, tcol_vec); /* construct sparse pattern of the pivot column */ nnz = 0; for (i = 1; i <= m; i++) { if (tcol_vec[i] != 0.0) tcol_ind[++nnz] = i; } csa->tcol_nnz = nnz; return; } /*********************************************************************** * sort_tcol - sort pivot column of the simplex table * * This routine reorders the list of non-zero elements of the pivot * column to put significant elements, whose magnitude is not less than * a specified tolerance, in front of the list, and stores the number * of significant elements in tcol_num. */ static void sort_tcol(struct csa *csa, double tol_piv) { #ifdef GLP_DEBUG int m = csa->m; #endif int nnz = csa->tcol_nnz; int *tcol_ind = csa->tcol_ind; double *tcol_vec = csa->tcol_vec; int i, num, pos; double big, eps, temp; /* compute infinity (maximum) norm of the column */ big = 0.0; for (pos = 1; pos <= nnz; pos++) { #ifdef GLP_DEBUG i = tcol_ind[pos]; xassert(1 <= i && i <= m); #endif temp = fabs(tcol_vec[tcol_ind[pos]]); if (big < temp) big = temp; } csa->tcol_max = big; /* determine absolute pivot tolerance */ eps = tol_piv * (1.0 + 0.01 * big); /* move significant column components to front of the list */ for (num = 0; num < nnz; ) { i = tcol_ind[nnz]; if (fabs(tcol_vec[i]) < eps) nnz--; else { num++; tcol_ind[nnz] = tcol_ind[num]; tcol_ind[num] = i; } } csa->tcol_num = num; return; } /*********************************************************************** * chuzr - choose basic variable (row of the simplex table) * * This routine chooses basic variable xB[p], which reaches its bound * first on changing non-basic variable xN[q] in valid direction. * * The parameter rtol is a relative tolerance used to relax bounds of * basic variables. If rtol = 0, the routine implements the standard * ratio test. Otherwise, if rtol > 0, the routine implements Harris' * two-pass ratio test. In the latter case rtol should be about three * times less than a tolerance used to check primal feasibility. */ static void chuzr(struct csa *csa, double rtol) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif char *type = csa->type; double *lb = csa->lb; double *ub = csa->ub; double *coef = csa->coef; int *head = csa->head; int phase = csa->phase; double *bbar = csa->bbar; double *cbar = csa->cbar; int q = csa->q; int *tcol_ind = csa->tcol_ind; double *tcol_vec = csa->tcol_vec; int tcol_num = csa->tcol_num; int i, i_stat, k, p, p_stat, pos; double alfa, big, delta, s, t, teta, tmax; #ifdef GLP_DEBUG xassert(1 <= q && q <= n); #endif /* s := - sign(d[q]), where d[q] is reduced cost of xN[q] */ #ifdef GLP_DEBUG xassert(cbar[q] != 0.0); #endif s = (cbar[q] > 0.0 ? -1.0 : +1.0); /*** FIRST PASS ***/ k = head[m+q]; /* x[k] = xN[q] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (type[k] == GLP_DB) { /* xN[q] has both lower and upper bounds */ p = -1, p_stat = 0, teta = ub[k] - lb[k], big = 1.0; } else { /* xN[q] has no opposite bound */ p = 0, p_stat = 0, teta = DBL_MAX, big = 0.0; } /* walk through significant elements of the pivot column */ for (pos = 1; pos <= tcol_num; pos++) { i = tcol_ind[pos]; #ifdef GLP_DEBUG xassert(1 <= i && i <= m); #endif k = head[i]; /* x[k] = xB[i] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif alfa = s * tcol_vec[i]; #ifdef GLP_DEBUG xassert(alfa != 0.0); #endif /* xB[i] = ... + alfa * xN[q] + ..., and due to s we need to consider the only case when xN[q] is increasing */ if (alfa > 0.0) { /* xB[i] is increasing */ if (phase == 1 && coef[k] < 0.0) { /* xB[i] violates its lower bound, which plays the role of an upper bound on phase I */ delta = rtol * (1.0 + kappa * fabs(lb[k])); t = ((lb[k] + delta) - bbar[i]) / alfa; i_stat = GLP_NL; } else if (phase == 1 && coef[k] > 0.0) { /* xB[i] violates its upper bound, which plays the role of an lower bound on phase I */ continue; } else if (type[k] == GLP_UP || type[k] == GLP_DB || type[k] == GLP_FX) { /* xB[i] is within its bounds and has an upper bound */ delta = rtol * (1.0 + kappa * fabs(ub[k])); t = ((ub[k] + delta) - bbar[i]) / alfa; i_stat = GLP_NU; } else { /* xB[i] is within its bounds and has no upper bound */ continue; } } else { /* xB[i] is decreasing */ if (phase == 1 && coef[k] > 0.0) { /* xB[i] violates its upper bound, which plays the role of an lower bound on phase I */ delta = rtol * (1.0 + kappa * fabs(ub[k])); t = ((ub[k] - delta) - bbar[i]) / alfa; i_stat = GLP_NU; } else if (phase == 1 && coef[k] < 0.0) { /* xB[i] violates its lower bound, which plays the role of an upper bound on phase I */ continue; } else if (type[k] == GLP_LO || type[k] == GLP_DB || type[k] == GLP_FX) { /* xB[i] is within its bounds and has an lower bound */ delta = rtol * (1.0 + kappa * fabs(lb[k])); t = ((lb[k] - delta) - bbar[i]) / alfa; i_stat = GLP_NL; } else { /* xB[i] is within its bounds and has no lower bound */ continue; } } /* t is a change of xN[q], on which xB[i] reaches its bound (possibly relaxed); since the basic solution is assumed to be primal feasible (or pseudo feasible on phase I), t has to be non-negative by definition; however, it may happen that xB[i] slightly (i.e. within a tolerance) violates its bound, that leads to negative t; in the latter case, if xB[i] is chosen, negative t means that xN[q] changes in wrong direction; if pivot alfa[i,q] is close to zero, even small bound violation of xB[i] may lead to a large change of xN[q] in wrong direction; let, for example, xB[i] >= 0 and in the current basis its value be -5e-9; let also xN[q] be on its zero bound and should increase; from the ratio test rule it follows that the pivot alfa[i,q] < 0; however, if alfa[i,q] is, say, -1e-9, the change of xN[q] in wrong direction is 5e-9 / (-1e-9) = -5, and using it for updating values of other basic variables will give absolutely wrong results; therefore, if t is negative, we should replace it by exact zero assuming that xB[i] is exactly on its bound, and the violation appears due to round-off errors */ if (t < 0.0) t = 0.0; /* apply minimal ratio test */ if (teta > t || teta == t && big < fabs(alfa)) p = i, p_stat = i_stat, teta = t, big = fabs(alfa); } /* the second pass is skipped in the following cases: */ /* if the standard ratio test is used */ if (rtol == 0.0) goto done; /* if xN[q] reaches its opposite bound or if no basic variable has been chosen on the first pass */ if (p <= 0) goto done; /* if xB[p] is a blocking variable, i.e. if it prevents xN[q] from any change */ if (teta == 0.0) goto done; /*** SECOND PASS ***/ /* here tmax is a maximal change of xN[q], on which the solution remains primal feasible (or pseudo feasible on phase I) within a tolerance */ #if 0 tmax = (1.0 + 10.0 * DBL_EPSILON) * teta; #else tmax = teta; #endif /* nothing is chosen so far */ p = 0, p_stat = 0, teta = DBL_MAX, big = 0.0; /* walk through significant elements of the pivot column */ for (pos = 1; pos <= tcol_num; pos++) { i = tcol_ind[pos]; #ifdef GLP_DEBUG xassert(1 <= i && i <= m); #endif k = head[i]; /* x[k] = xB[i] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif alfa = s * tcol_vec[i]; #ifdef GLP_DEBUG xassert(alfa != 0.0); #endif /* xB[i] = ... + alfa * xN[q] + ..., and due to s we need to consider the only case when xN[q] is increasing */ if (alfa > 0.0) { /* xB[i] is increasing */ if (phase == 1 && coef[k] < 0.0) { /* xB[i] violates its lower bound, which plays the role of an upper bound on phase I */ t = (lb[k] - bbar[i]) / alfa; i_stat = GLP_NL; } else if (phase == 1 && coef[k] > 0.0) { /* xB[i] violates its upper bound, which plays the role of an lower bound on phase I */ continue; } else if (type[k] == GLP_UP || type[k] == GLP_DB || type[k] == GLP_FX) { /* xB[i] is within its bounds and has an upper bound */ t = (ub[k] - bbar[i]) / alfa; i_stat = GLP_NU; } else { /* xB[i] is within its bounds and has no upper bound */ continue; } } else { /* xB[i] is decreasing */ if (phase == 1 && coef[k] > 0.0) { /* xB[i] violates its upper bound, which plays the role of an lower bound on phase I */ t = (ub[k] - bbar[i]) / alfa; i_stat = GLP_NU; } else if (phase == 1 && coef[k] < 0.0) { /* xB[i] violates its lower bound, which plays the role of an upper bound on phase I */ continue; } else if (type[k] == GLP_LO || type[k] == GLP_DB || type[k] == GLP_FX) { /* xB[i] is within its bounds and has an lower bound */ t = (lb[k] - bbar[i]) / alfa; i_stat = GLP_NL; } else { /* xB[i] is within its bounds and has no lower bound */ continue; } } /* (see comments for the first pass) */ if (t < 0.0) t = 0.0; /* t is a change of xN[q], on which xB[i] reaches its bound; if t <= tmax, all basic variables can violate their bounds only within relaxation tolerance delta; we can use this freedom and choose basic variable having largest influence coefficient to avoid possible numeric instability */ if (t <= tmax && big < fabs(alfa)) p = i, p_stat = i_stat, teta = t, big = fabs(alfa); } /* something must be chosen on the second pass */ xassert(p != 0); done: /* store the index and status of basic variable xB[p] chosen */ csa->p = p; if (p > 0 && type[head[p]] == GLP_FX) csa->p_stat = GLP_NS; else csa->p_stat = p_stat; /* store corresponding change of non-basic variable xN[q] */ #ifdef GLP_DEBUG xassert(teta >= 0.0); #endif csa->teta = s * teta; return; } /*********************************************************************** * eval_rho - compute pivot row of the inverse * * This routine computes the pivot (p-th) row of the inverse inv(B), * which corresponds to basic variable xB[p] chosen: * * rho = inv(B') * e[p], * * where B' is a matrix transposed to the current basis matrix, e[p] * is unity vector. */ static void eval_rho(struct csa *csa, double rho[]) { int m = csa->m; int p = csa->p; double *e = rho; int i; #ifdef GLP_DEBUG xassert(1 <= p && p <= m); #endif /* construct the right-hand side vector e[p] */ for (i = 1; i <= m; i++) e[i] = 0.0; e[p] = 1.0; /* solve system B'* rho = e[p] */ xassert(csa->valid); bfd_btran(csa->bfd, rho); return; } /*********************************************************************** * refine_rho - refine pivot row of the inverse * * This routine refines the pivot row of the inverse inv(B) assuming * that it was previously computed by the routine eval_rho. */ static void refine_rho(struct csa *csa, double rho[]) { int m = csa->m; int p = csa->p; double *e = csa->work3; int i; #ifdef GLP_DEBUG xassert(1 <= p && p <= m); #endif /* construct the right-hand side vector e[p] */ for (i = 1; i <= m; i++) e[i] = 0.0; e[p] = 1.0; /* refine solution of B'* rho = e[p] */ refine_btran(csa, e, rho); return; } /*********************************************************************** * eval_trow - compute pivot row of the simplex table * * This routine computes the pivot row of the simplex table, which * corresponds to basic variable xB[p] chosen. * * The pivot row is the following vector: * * trow = T'* e[p] = - N'* inv(B') * e[p] = - N' * rho, * * where rho is the pivot row of the inverse inv(B) previously computed * by the routine eval_rho. * * Note that elements of the pivot row corresponding to fixed non-basic * variables are not computed. */ static void eval_trow(struct csa *csa, double rho[]) { int m = csa->m; int n = csa->n; #ifdef GLP_DEBUG char *stat = csa->stat; #endif int *N_ptr = csa->N_ptr; int *N_len = csa->N_len; int *N_ind = csa->N_ind; double *N_val = csa->N_val; int *trow_ind = csa->trow_ind; double *trow_vec = csa->trow_vec; int i, j, beg, end, ptr, nnz; double temp; /* clear the pivot row */ for (j = 1; j <= n; j++) trow_vec[j] = 0.0; /* compute the pivot row as a linear combination of rows of the matrix N: trow = - rho[1] * N'[1] - ... - rho[m] * N'[m] */ for (i = 1; i <= m; i++) { temp = rho[i]; if (temp == 0.0) continue; /* trow := trow - rho[i] * N'[i] */ beg = N_ptr[i]; end = beg + N_len[i]; for (ptr = beg; ptr < end; ptr++) { #ifdef GLP_DEBUG j = N_ind[ptr]; xassert(1 <= j && j <= n); xassert(stat[j] != GLP_NS); #endif trow_vec[N_ind[ptr]] -= temp * N_val[ptr]; } } /* construct sparse pattern of the pivot row */ nnz = 0; for (j = 1; j <= n; j++) { if (trow_vec[j] != 0.0) trow_ind[++nnz] = j; } csa->trow_nnz = nnz; return; } /*********************************************************************** * update_bbar - update values of basic variables * * This routine updates values of all basic variables for the adjacent * basis. */ static void update_bbar(struct csa *csa) { #ifdef GLP_DEBUG int m = csa->m; int n = csa->n; #endif double *bbar = csa->bbar; int q = csa->q; int tcol_nnz = csa->tcol_nnz; int *tcol_ind = csa->tcol_ind; double *tcol_vec = csa->tcol_vec; int p = csa->p; double teta = csa->teta; int i, pos; #ifdef GLP_DEBUG xassert(1 <= q && q <= n); xassert(p < 0 || 1 <= p && p <= m); #endif /* if xN[q] leaves the basis, compute its value in the adjacent basis, where it will replace xB[p] */ if (p > 0) bbar[p] = get_xN(csa, q) + teta; /* update values of other basic variables (except xB[p], because it will be replaced by xN[q]) */ if (teta == 0.0) goto done; for (pos = 1; pos <= tcol_nnz; pos++) { i = tcol_ind[pos]; /* skip xB[p] */ if (i == p) continue; /* (change of xB[i]) = alfa[i,q] * (change of xN[q]) */ bbar[i] += tcol_vec[i] * teta; } done: return; } /*********************************************************************** * reeval_cost - recompute reduced cost of non-basic variable xN[q] * * This routine recomputes reduced cost of non-basic variable xN[q] for * the current basis more accurately using its direct definition: * * d[q] = cN[q] - N'[q] * pi = * * = cN[q] - N'[q] * (inv(B') * cB) = * * = cN[q] - (cB' * inv(B) * N[q]) = * * = cN[q] + cB' * (pivot column). * * It is assumed that the pivot column of the simplex table is already * computed. */ static double reeval_cost(struct csa *csa) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif double *coef = csa->coef; int *head = csa->head; int q = csa->q; int tcol_nnz = csa->tcol_nnz; int *tcol_ind = csa->tcol_ind; double *tcol_vec = csa->tcol_vec; int i, pos; double dq; #ifdef GLP_DEBUG xassert(1 <= q && q <= n); #endif dq = coef[head[m+q]]; for (pos = 1; pos <= tcol_nnz; pos++) { i = tcol_ind[pos]; #ifdef GLP_DEBUG xassert(1 <= i && i <= m); #endif dq += coef[head[i]] * tcol_vec[i]; } return dq; } /*********************************************************************** * update_cbar - update reduced costs of non-basic variables * * This routine updates reduced costs of all (except fixed) non-basic * variables for the adjacent basis. */ static void update_cbar(struct csa *csa) { #ifdef GLP_DEBUG int n = csa->n; #endif double *cbar = csa->cbar; int q = csa->q; int trow_nnz = csa->trow_nnz; int *trow_ind = csa->trow_ind; double *trow_vec = csa->trow_vec; int j, pos; double new_dq; #ifdef GLP_DEBUG xassert(1 <= q && q <= n); #endif /* compute reduced cost of xB[p] in the adjacent basis, where it will replace xN[q] */ #ifdef GLP_DEBUG xassert(trow_vec[q] != 0.0); #endif new_dq = (cbar[q] /= trow_vec[q]); /* update reduced costs of other non-basic variables (except xN[q], because it will be replaced by xB[p]) */ for (pos = 1; pos <= trow_nnz; pos++) { j = trow_ind[pos]; /* skip xN[q] */ if (j == q) continue; cbar[j] -= trow_vec[j] * new_dq; } return; } /*********************************************************************** * update_gamma - update steepest edge coefficients * * This routine updates steepest-edge coefficients for the adjacent * basis. */ static void update_gamma(struct csa *csa) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif char *type = csa->type; int *A_ptr = csa->A_ptr; int *A_ind = csa->A_ind; double *A_val = csa->A_val; int *head = csa->head; char *refsp = csa->refsp; double *gamma = csa->gamma; int q = csa->q; int tcol_nnz = csa->tcol_nnz; int *tcol_ind = csa->tcol_ind; double *tcol_vec = csa->tcol_vec; int p = csa->p; int trow_nnz = csa->trow_nnz; int *trow_ind = csa->trow_ind; double *trow_vec = csa->trow_vec; double *u = csa->work3; int i, j, k, pos, beg, end, ptr; double gamma_q, delta_q, pivot, s, t, t1, t2; #ifdef GLP_DEBUG xassert(1 <= p && p <= m); xassert(1 <= q && q <= n); #endif /* the basis changes, so decrease the count */ xassert(csa->refct > 0); csa->refct--; /* recompute gamma[q] for the current basis more accurately and compute auxiliary vector u */ gamma_q = delta_q = (refsp[head[m+q]] ? 1.0 : 0.0); for (i = 1; i <= m; i++) u[i] = 0.0; for (pos = 1; pos <= tcol_nnz; pos++) { i = tcol_ind[pos]; if (refsp[head[i]]) { u[i] = t = tcol_vec[i]; gamma_q += t * t; } else u[i] = 0.0; } xassert(csa->valid); bfd_btran(csa->bfd, u); /* update gamma[k] for other non-basic variables (except fixed variables and xN[q], because it will be replaced by xB[p]) */ pivot = trow_vec[q]; #ifdef GLP_DEBUG xassert(pivot != 0.0); #endif for (pos = 1; pos <= trow_nnz; pos++) { j = trow_ind[pos]; /* skip xN[q] */ if (j == q) continue; /* compute t */ t = trow_vec[j] / pivot; /* compute inner product s = N'[j] * u */ k = head[m+j]; /* x[k] = xN[j] */ if (k <= m) s = u[k]; else { s = 0.0; beg = A_ptr[k-m]; end = A_ptr[k-m+1]; for (ptr = beg; ptr < end; ptr++) s -= A_val[ptr] * u[A_ind[ptr]]; } /* compute gamma[k] for the adjacent basis */ t1 = gamma[j] + t * t * gamma_q + 2.0 * t * s; t2 = (refsp[k] ? 1.0 : 0.0) + delta_q * t * t; gamma[j] = (t1 >= t2 ? t1 : t2); if (gamma[j] < DBL_EPSILON) gamma[j] = DBL_EPSILON; } /* compute gamma[q] for the adjacent basis */ if (type[head[p]] == GLP_FX) gamma[q] = 1.0; else { gamma[q] = gamma_q / (pivot * pivot); if (gamma[q] < DBL_EPSILON) gamma[q] = DBL_EPSILON; } return; } /*********************************************************************** * err_in_bbar - compute maximal relative error in primal solution * * This routine returns maximal relative error: * * max |beta[i] - bbar[i]| / (1 + |beta[i]|), * * where beta and bbar are, respectively, directly computed and the * current (updated) values of basic variables. * * NOTE: The routine is intended only for debugginig purposes. */ static double err_in_bbar(struct csa *csa) { int m = csa->m; double *bbar = csa->bbar; int i; double e, emax, *beta; beta = xcalloc(1+m, sizeof(double)); eval_beta(csa, beta); emax = 0.0; for (i = 1; i <= m; i++) { e = fabs(beta[i] - bbar[i]) / (1.0 + fabs(beta[i])); if (emax < e) emax = e; } xfree(beta); return emax; } /*********************************************************************** * err_in_cbar - compute maximal relative error in dual solution * * This routine returns maximal relative error: * * max |cost[j] - cbar[j]| / (1 + |cost[j]|), * * where cost and cbar are, respectively, directly computed and the * current (updated) reduced costs of non-basic non-fixed variables. * * NOTE: The routine is intended only for debugginig purposes. */ static double err_in_cbar(struct csa *csa) { int m = csa->m; int n = csa->n; char *stat = csa->stat; double *cbar = csa->cbar; int j; double e, emax, cost, *pi; pi = xcalloc(1+m, sizeof(double)); eval_pi(csa, pi); emax = 0.0; for (j = 1; j <= n; j++) { if (stat[j] == GLP_NS) continue; cost = eval_cost(csa, pi, j); e = fabs(cost - cbar[j]) / (1.0 + fabs(cost)); if (emax < e) emax = e; } xfree(pi); return emax; } /*********************************************************************** * err_in_gamma - compute maximal relative error in steepest edge cff. * * This routine returns maximal relative error: * * max |gamma'[j] - gamma[j]| / (1 + |gamma'[j]), * * where gamma'[j] and gamma[j] are, respectively, directly computed * and the current (updated) steepest edge coefficients for non-basic * non-fixed variable x[j]. * * NOTE: The routine is intended only for debugginig purposes. */ static double err_in_gamma(struct csa *csa) { int n = csa->n; char *stat = csa->stat; double *gamma = csa->gamma; int j; double e, emax, temp; emax = 0.0; for (j = 1; j <= n; j++) { if (stat[j] == GLP_NS) { xassert(gamma[j] == 1.0); continue; } temp = eval_gamma(csa, j); e = fabs(temp - gamma[j]) / (1.0 + fabs(temp)); if (emax < e) emax = e; } return emax; } /*********************************************************************** * change_basis - change basis header * * This routine changes the basis header to make it corresponding to * the adjacent basis. */ static void change_basis(struct csa *csa) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; char *type = csa->type; #endif int *head = csa->head; char *stat = csa->stat; int q = csa->q; int p = csa->p; int p_stat = csa->p_stat; int k; #ifdef GLP_DEBUG xassert(1 <= q && q <= n); #endif if (p < 0) { /* xN[q] goes to its opposite bound */ #ifdef GLP_DEBUG k = head[m+q]; /* x[k] = xN[q] */ xassert(1 <= k && k <= m+n); xassert(type[k] == GLP_DB); #endif switch (stat[q]) { case GLP_NL: /* xN[q] increases */ stat[q] = GLP_NU; break; case GLP_NU: /* xN[q] decreases */ stat[q] = GLP_NL; break; default: xassert(stat != stat); } } else { /* xB[p] leaves the basis, xN[q] enters the basis */ #ifdef GLP_DEBUG xassert(1 <= p && p <= m); k = head[p]; /* x[k] = xB[p] */ switch (p_stat) { case GLP_NL: /* xB[p] goes to its lower bound */ xassert(type[k] == GLP_LO || type[k] == GLP_DB); break; case GLP_NU: /* xB[p] goes to its upper bound */ xassert(type[k] == GLP_UP || type[k] == GLP_DB); break; case GLP_NS: /* xB[p] goes to its fixed value */ xassert(type[k] == GLP_NS); break; default: xassert(p_stat != p_stat); } #endif /* xB[p] <-> xN[q] */ k = head[p], head[p] = head[m+q], head[m+q] = k; stat[q] = (char)p_stat; } return; } /*********************************************************************** * set_aux_obj - construct auxiliary objective function * * The auxiliary objective function is a separable piecewise linear * convex function, which is the sum of primal infeasibilities: * * z = t[1] + ... + t[m+n] -> minimize, * * where: * * / lb[k] - x[k], if x[k] < lb[k] * | * t[k] = < 0, if lb[k] <= x[k] <= ub[k] * | * \ x[k] - ub[k], if x[k] > ub[k] * * This routine computes objective coefficients for the current basis * and returns the number of non-zero terms t[k]. */ static int set_aux_obj(struct csa *csa, double tol_bnd) { int m = csa->m; int n = csa->n; char *type = csa->type; double *lb = csa->lb; double *ub = csa->ub; double *coef = csa->coef; int *head = csa->head; double *bbar = csa->bbar; int i, k, cnt = 0; double eps; /* use a bit more restrictive tolerance */ tol_bnd *= 0.90; /* clear all objective coefficients */ for (k = 1; k <= m+n; k++) coef[k] = 0.0; /* walk through the list of basic variables */ for (i = 1; i <= m; i++) { k = head[i]; /* x[k] = xB[i] */ if (type[k] == GLP_LO || type[k] == GLP_DB || type[k] == GLP_FX) { /* x[k] has lower bound */ eps = tol_bnd * (1.0 + kappa * fabs(lb[k])); if (bbar[i] < lb[k] - eps) { /* and violates it */ coef[k] = -1.0; cnt++; } } if (type[k] == GLP_UP || type[k] == GLP_DB || type[k] == GLP_FX) { /* x[k] has upper bound */ eps = tol_bnd * (1.0 + kappa * fabs(ub[k])); if (bbar[i] > ub[k] + eps) { /* and violates it */ coef[k] = +1.0; cnt++; } } } return cnt; } /*********************************************************************** * set_orig_obj - restore original objective function * * This routine assigns scaled original objective coefficients to the * working objective function. */ static void set_orig_obj(struct csa *csa) { int m = csa->m; int n = csa->n; double *coef = csa->coef; double *obj = csa->obj; double zeta = csa->zeta; int i, j; for (i = 1; i <= m; i++) coef[i] = 0.0; for (j = 1; j <= n; j++) coef[m+j] = zeta * obj[j]; return; } /*********************************************************************** * check_stab - check numerical stability of basic solution * * If the current basic solution is primal feasible (or pseudo feasible * on phase I) within a tolerance, this routine returns zero, otherwise * it returns non-zero. */ static int check_stab(struct csa *csa, double tol_bnd) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif char *type = csa->type; double *lb = csa->lb; double *ub = csa->ub; double *coef = csa->coef; int *head = csa->head; int phase = csa->phase; double *bbar = csa->bbar; int i, k; double eps; /* walk through the list of basic variables */ for (i = 1; i <= m; i++) { k = head[i]; /* x[k] = xB[i] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (phase == 1 && coef[k] < 0.0) { /* x[k] must not be greater than its lower bound */ #ifdef GLP_DEBUG xassert(type[k] == GLP_LO || type[k] == GLP_DB || type[k] == GLP_FX); #endif eps = tol_bnd * (1.0 + kappa * fabs(lb[k])); if (bbar[i] > lb[k] + eps) return 1; } else if (phase == 1 && coef[k] > 0.0) { /* x[k] must not be less than its upper bound */ #ifdef GLP_DEBUG xassert(type[k] == GLP_UP || type[k] == GLP_DB || type[k] == GLP_FX); #endif eps = tol_bnd * (1.0 + kappa * fabs(ub[k])); if (bbar[i] < ub[k] - eps) return 1; } else { /* either phase = 1 and coef[k] = 0, or phase = 2 */ if (type[k] == GLP_LO || type[k] == GLP_DB || type[k] == GLP_FX) { /* x[k] must not be less than its lower bound */ eps = tol_bnd * (1.0 + kappa * fabs(lb[k])); if (bbar[i] < lb[k] - eps) return 1; } if (type[k] == GLP_UP || type[k] == GLP_DB || type[k] == GLP_FX) { /* x[k] must not be greater then its upper bound */ eps = tol_bnd * (1.0 + kappa * fabs(ub[k])); if (bbar[i] > ub[k] + eps) return 1; } } } /* basic solution is primal feasible within a tolerance */ return 0; } /*********************************************************************** * check_feas - check primal feasibility of basic solution * * If the current basic solution is primal feasible within a tolerance, * this routine returns zero, otherwise it returns non-zero. */ static int check_feas(struct csa *csa, double tol_bnd) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; char *type = csa->type; #endif double *lb = csa->lb; double *ub = csa->ub; double *coef = csa->coef; int *head = csa->head; double *bbar = csa->bbar; int i, k; double eps; xassert(csa->phase == 1); /* walk through the list of basic variables */ for (i = 1; i <= m; i++) { k = head[i]; /* x[k] = xB[i] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (coef[k] < 0.0) { /* check if x[k] still violates its lower bound */ #ifdef GLP_DEBUG xassert(type[k] == GLP_LO || type[k] == GLP_DB || type[k] == GLP_FX); #endif eps = tol_bnd * (1.0 + kappa * fabs(lb[k])); if (bbar[i] < lb[k] - eps) return 1; } else if (coef[k] > 0.0) { /* check if x[k] still violates its upper bound */ #ifdef GLP_DEBUG xassert(type[k] == GLP_UP || type[k] == GLP_DB || type[k] == GLP_FX); #endif eps = tol_bnd * (1.0 + kappa * fabs(ub[k])); if (bbar[i] > ub[k] + eps) return 1; } } /* basic solution is primal feasible within a tolerance */ return 0; } /*********************************************************************** * eval_obj - compute original objective function * * This routine computes the current value of the original objective * function. */ static double eval_obj(struct csa *csa) { int m = csa->m; int n = csa->n; double *obj = csa->obj; int *head = csa->head; double *bbar = csa->bbar; int i, j, k; double sum; sum = obj[0]; /* walk through the list of basic variables */ for (i = 1; i <= m; i++) { k = head[i]; /* x[k] = xB[i] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (k > m) sum += obj[k-m] * bbar[i]; } /* walk through the list of non-basic variables */ for (j = 1; j <= n; j++) { k = head[m+j]; /* x[k] = xN[j] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (k > m) sum += obj[k-m] * get_xN(csa, j); } return sum; } /*********************************************************************** * display - display the search progress * * This routine displays some information about the search progress * that includes: * * the search phase; * * the number of simplex iterations performed by the solver; * * the original objective value; * * the sum of (scaled) primal infeasibilities; * * the number of basic fixed variables. */ static void display(struct csa *csa, const glp_smcp *parm, int spec) { int m = csa->m; #ifdef GLP_DEBUG int n = csa->n; #endif char *type = csa->type; double *lb = csa->lb; double *ub = csa->ub; int phase = csa->phase; int *head = csa->head; double *bbar = csa->bbar; int i, k, cnt; double sum; if (parm->msg_lev < GLP_MSG_ON) goto skip; if (parm->out_dly > 0 && 1000.0 * xdifftime(xtime(), csa->tm_beg) < parm->out_dly) goto skip; if (csa->it_cnt == csa->it_dpy) goto skip; if (!spec && csa->it_cnt % parm->out_frq != 0) goto skip; /* compute the sum of primal infeasibilities and determine the number of basic fixed variables */ sum = 0.0, cnt = 0; for (i = 1; i <= m; i++) { k = head[i]; /* x[k] = xB[i] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (type[k] == GLP_LO || type[k] == GLP_DB || type[k] == GLP_FX) { /* x[k] has lower bound */ if (bbar[i] < lb[k]) sum += (lb[k] - bbar[i]); } if (type[k] == GLP_UP || type[k] == GLP_DB || type[k] == GLP_FX) { /* x[k] has upper bound */ if (bbar[i] > ub[k]) sum += (bbar[i] - ub[k]); } if (type[k] == GLP_FX) cnt++; } xprintf("%c%6d: obj = %17.9e infeas = %10.3e (%d)\n", phase == 1 ? ' ' : '*', csa->it_cnt, eval_obj(csa), sum, cnt); csa->it_dpy = csa->it_cnt; skip: return; } /*********************************************************************** * store_sol - store basic solution back to the problem object * * This routine stores basic solution components back to the problem * object. */ static void store_sol(struct csa *csa, glp_prob *lp, int p_stat, int d_stat, int ray) { int m = csa->m; int n = csa->n; double zeta = csa->zeta; int *head = csa->head; char *stat = csa->stat; double *bbar = csa->bbar; double *cbar = csa->cbar; int i, j, k; #ifdef GLP_DEBUG xassert(lp->m == m); xassert(lp->n == n); #endif /* basis factorization */ #ifdef GLP_DEBUG xassert(!lp->valid && lp->bfd == NULL); xassert(csa->valid && csa->bfd != NULL); #endif lp->valid = 1, csa->valid = 0; lp->bfd = csa->bfd, csa->bfd = NULL; memcpy(&lp->head[1], &head[1], m * sizeof(int)); /* basic solution status */ lp->pbs_stat = p_stat; lp->dbs_stat = d_stat; /* objective function value */ lp->obj_val = eval_obj(csa); /* simplex iteration count */ lp->it_cnt = csa->it_cnt; /* unbounded ray */ lp->some = ray; /* basic variables */ for (i = 1; i <= m; i++) { k = head[i]; /* x[k] = xB[i] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (k <= m) { GLPROW *row = lp->row[k]; row->stat = GLP_BS; row->bind = i; row->prim = bbar[i] / row->rii; row->dual = 0.0; } else { GLPCOL *col = lp->col[k-m]; col->stat = GLP_BS; col->bind = i; col->prim = bbar[i] * col->sjj; col->dual = 0.0; } } /* non-basic variables */ for (j = 1; j <= n; j++) { k = head[m+j]; /* x[k] = xN[j] */ #ifdef GLP_DEBUG xassert(1 <= k && k <= m+n); #endif if (k <= m) { GLPROW *row = lp->row[k]; row->stat = stat[j]; row->bind = 0; #if 0 row->prim = get_xN(csa, j) / row->rii; #else switch (stat[j]) { case GLP_NL: row->prim = row->lb; break; case GLP_NU: row->prim = row->ub; break; case GLP_NF: row->prim = 0.0; break; case GLP_NS: row->prim = row->lb; break; default: xassert(stat != stat); } #endif row->dual = (cbar[j] * row->rii) / zeta; } else { GLPCOL *col = lp->col[k-m]; col->stat = stat[j]; col->bind = 0; #if 0 col->prim = get_xN(csa, j) * col->sjj; #else switch (stat[j]) { case GLP_NL: col->prim = col->lb; break; case GLP_NU: col->prim = col->ub; break; case GLP_NF: col->prim = 0.0; break; case GLP_NS: col->prim = col->lb; break; default: xassert(stat != stat); } #endif col->dual = (cbar[j] / col->sjj) / zeta; } } return; } /*********************************************************************** * free_csa - deallocate common storage area * * This routine frees all the memory allocated to arrays in the common * storage area (CSA). */ static void free_csa(struct csa *csa) { xfree(csa->type); xfree(csa->lb); xfree(csa->ub); xfree(csa->coef); xfree(csa->obj); xfree(csa->A_ptr); xfree(csa->A_ind); xfree(csa->A_val); xfree(csa->head); xfree(csa->stat); xfree(csa->N_ptr); xfree(csa->N_len); xfree(csa->N_ind); xfree(csa->N_val); xfree(csa->bbar); xfree(csa->cbar); xfree(csa->refsp); xfree(csa->gamma); xfree(csa->tcol_ind); xfree(csa->tcol_vec); xfree(csa->trow_ind); xfree(csa->trow_vec); xfree(csa->work1); xfree(csa->work2); xfree(csa->work3); xfree(csa->work4); xfree(csa); return; } /*********************************************************************** * spx_primal - core LP solver based on the primal simplex method * * SYNOPSIS * * #include "glpspx.h" * int spx_primal(glp_prob *lp, const glp_smcp *parm); * * DESCRIPTION * * The routine spx_primal is a core LP solver based on the two-phase * primal simplex method. * * RETURNS * * 0 LP instance has been successfully solved. * * GLP_EITLIM * Iteration limit has been exhausted. * * GLP_ETMLIM * Time limit has been exhausted. * * GLP_EFAIL * The solver failed to solve LP instance. */ int spx_primal(glp_prob *lp, const glp_smcp *parm) { struct csa *csa; int binv_st = 2; /* status of basis matrix factorization: 0 - invalid; 1 - just computed; 2 - updated */ int bbar_st = 0; /* status of primal values of basic variables: 0 - invalid; 1 - just computed; 2 - updated */ int cbar_st = 0; /* status of reduced costs of non-basic variables: 0 - invalid; 1 - just computed; 2 - updated */ int rigorous = 0; /* rigorous mode flag; this flag is used to enable iterative refinement on computing pivot rows and columns of the simplex table */ int check = 0; int p_stat, d_stat, ret; /* allocate and initialize the common storage area */ csa = alloc_csa(lp); init_csa(csa, lp); if (parm->msg_lev >= GLP_MSG_DBG) xprintf("Objective scale factor = %g\n", csa->zeta); loop: /* main loop starts here */ /* compute factorization of the basis matrix */ if (binv_st == 0) { ret = invert_B(csa); if (ret != 0) { if (parm->msg_lev >= GLP_MSG_ERR) { xprintf("Error: unable to factorize the basis matrix (%d" ")\n", ret); xprintf("Sorry, basis recovery procedure not implemented" " yet\n"); } xassert(!lp->valid && lp->bfd == NULL); lp->bfd = csa->bfd, csa->bfd = NULL; lp->pbs_stat = lp->dbs_stat = GLP_UNDEF; lp->obj_val = 0.0; lp->it_cnt = csa->it_cnt; lp->some = 0; ret = GLP_EFAIL; goto done; } csa->valid = 1; binv_st = 1; /* just computed */ /* invalidate basic solution components */ bbar_st = cbar_st = 0; } /* compute primal values of basic variables */ if (bbar_st == 0) { eval_bbar(csa); bbar_st = 1; /* just computed */ /* determine the search phase, if not determined yet */ if (csa->phase == 0) { if (set_aux_obj(csa, parm->tol_bnd) > 0) { /* current basic solution is primal infeasible */ /* start to minimize the sum of infeasibilities */ csa->phase = 1; } else { /* current basic solution is primal feasible */ /* start to minimize the original objective function */ set_orig_obj(csa); csa->phase = 2; } xassert(check_stab(csa, parm->tol_bnd) == 0); /* working objective coefficients have been changed, so invalidate reduced costs */ cbar_st = 0; display(csa, parm, 1); } /* make sure that the current basic solution remains primal feasible (or pseudo feasible on phase I) */ if (check_stab(csa, parm->tol_bnd)) { /* there are excessive bound violations due to round-off errors */ if (parm->msg_lev >= GLP_MSG_ERR) xprintf("Warning: numerical instability (primal simplex," " phase %s)\n", csa->phase == 1 ? "I" : "II"); /* restart the search */ csa->phase = 0; binv_st = 0; rigorous = 5; goto loop; } } xassert(csa->phase == 1 || csa->phase == 2); /* on phase I we do not need to wait until the current basic solution becomes dual feasible; it is sufficient to make sure that no basic variable violates its bounds */ if (csa->phase == 1 && !check_feas(csa, parm->tol_bnd)) { /* the current basis is primal feasible; switch to phase II */ csa->phase = 2; set_orig_obj(csa); cbar_st = 0; display(csa, parm, 1); } /* compute reduced costs of non-basic variables */ if (cbar_st == 0) { eval_cbar(csa); cbar_st = 1; /* just computed */ } /* redefine the reference space, if required */ switch (parm->pricing) { case GLP_PT_STD: break; case GLP_PT_PSE: if (csa->refct == 0) reset_refsp(csa); break; default: xassert(parm != parm); } /* at this point the basis factorization and all basic solution components are valid */ xassert(binv_st && bbar_st && cbar_st); /* check accuracy of current basic solution components (only for debugging) */ if (check) { double e_bbar = err_in_bbar(csa); double e_cbar = err_in_cbar(csa); double e_gamma = (parm->pricing == GLP_PT_PSE ? err_in_gamma(csa) : 0.0); xprintf("e_bbar = %10.3e; e_cbar = %10.3e; e_gamma = %10.3e\n", e_bbar, e_cbar, e_gamma); xassert(e_bbar <= 1e-5 && e_cbar <= 1e-5 && e_gamma <= 1e-3); } /* check if the iteration limit has been exhausted */ if (parm->it_lim < INT_MAX && csa->it_cnt - csa->it_beg >= parm->it_lim) { if (bbar_st != 1 || csa->phase == 2 && cbar_st != 1) { if (bbar_st != 1) bbar_st = 0; if (csa->phase == 2 && cbar_st != 1) cbar_st = 0; goto loop; } display(csa, parm, 1); if (parm->msg_lev >= GLP_MSG_ALL) xprintf("ITERATION LIMIT EXCEEDED; SEARCH TERMINATED\n"); switch (csa->phase) { case 1: p_stat = GLP_INFEAS; set_orig_obj(csa); eval_cbar(csa); break; case 2: p_stat = GLP_FEAS; break; default: xassert(csa != csa); } chuzc(csa, parm->tol_dj); d_stat = (csa->q == 0 ? GLP_FEAS : GLP_INFEAS); store_sol(csa, lp, p_stat, d_stat, 0); ret = GLP_EITLIM; goto done; } /* check if the time limit has been exhausted */ if (parm->tm_lim < INT_MAX && 1000.0 * xdifftime(xtime(), csa->tm_beg) >= parm->tm_lim) { if (bbar_st != 1 || csa->phase == 2 && cbar_st != 1) { if (bbar_st != 1) bbar_st = 0; if (csa->phase == 2 && cbar_st != 1) cbar_st = 0; goto loop; } display(csa, parm, 1); if (parm->msg_lev >= GLP_MSG_ALL) xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n"); switch (csa->phase) { case 1: p_stat = GLP_INFEAS; set_orig_obj(csa); eval_cbar(csa); break; case 2: p_stat = GLP_FEAS; break; default: xassert(csa != csa); } chuzc(csa, parm->tol_dj); d_stat = (csa->q == 0 ? GLP_FEAS : GLP_INFEAS); store_sol(csa, lp, p_stat, d_stat, 0); ret = GLP_ETMLIM; goto done; } /* display the search progress */ display(csa, parm, 0); /* choose non-basic variable xN[q] */ chuzc(csa, parm->tol_dj); if (csa->q == 0) { if (bbar_st != 1 || cbar_st != 1) { if (bbar_st != 1) bbar_st = 0; if (cbar_st != 1) cbar_st = 0; goto loop; } display(csa, parm, 1); switch (csa->phase) { case 1: if (parm->msg_lev >= GLP_MSG_ALL) #if 0 /* 13/VII-2013; suggested by Prof. Fischetti */ xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n"); #else xprintf("LP HAS NO PRIMAL FEASIBLE SOLUTION\n"); #endif p_stat = GLP_NOFEAS; set_orig_obj(csa); eval_cbar(csa); chuzc(csa, parm->tol_dj); d_stat = (csa->q == 0 ? GLP_FEAS : GLP_INFEAS); break; case 2: if (parm->msg_lev >= GLP_MSG_ALL) #if 0 /* 13/VII-2013; suggested by Prof. Fischetti */ xprintf("OPTIMAL SOLUTION FOUND\n"); #else xprintf("OPTIMAL LP SOLUTION FOUND\n"); #endif p_stat = d_stat = GLP_FEAS; break; default: xassert(csa != csa); } store_sol(csa, lp, p_stat, d_stat, 0); ret = 0; goto done; } /* compute pivot column of the simplex table */ eval_tcol(csa); if (rigorous) refine_tcol(csa); sort_tcol(csa, parm->tol_piv); /* check accuracy of the reduced cost of xN[q] */ { double d1 = csa->cbar[csa->q]; /* less accurate */ double d2 = reeval_cost(csa); /* more accurate */ xassert(d1 != 0.0); if (fabs(d1 - d2) > 1e-5 * (1.0 + fabs(d2)) || !(d1 < 0.0 && d2 < 0.0 || d1 > 0.0 && d2 > 0.0)) { if (parm->msg_lev >= GLP_MSG_DBG) xprintf("d1 = %.12g; d2 = %.12g\n", d1, d2); if (cbar_st != 1 || !rigorous) { if (cbar_st != 1) cbar_st = 0; rigorous = 5; goto loop; } } /* replace cbar[q] by more accurate value keeping its sign */ if (d1 > 0.0) csa->cbar[csa->q] = (d2 > 0.0 ? d2 : +DBL_EPSILON); else csa->cbar[csa->q] = (d2 < 0.0 ? d2 : -DBL_EPSILON); } /* choose basic variable xB[p] */ switch (parm->r_test) { case GLP_RT_STD: chuzr(csa, 0.0); break; case GLP_RT_HAR: chuzr(csa, 0.30 * parm->tol_bnd); break; default: xassert(parm != parm); } if (csa->p == 0) { if (bbar_st != 1 || cbar_st != 1 || !rigorous) { if (bbar_st != 1) bbar_st = 0; if (cbar_st != 1) cbar_st = 0; rigorous = 1; goto loop; } display(csa, parm, 1); switch (csa->phase) { case 1: if (parm->msg_lev >= GLP_MSG_ERR) xprintf("Error: unable to choose basic variable on ph" "ase I\n"); xassert(!lp->valid && lp->bfd == NULL); lp->bfd = csa->bfd, csa->bfd = NULL; lp->pbs_stat = lp->dbs_stat = GLP_UNDEF; lp->obj_val = 0.0; lp->it_cnt = csa->it_cnt; lp->some = 0; ret = GLP_EFAIL; break; case 2: if (parm->msg_lev >= GLP_MSG_ALL) #if 0 /* 13/VII-2013; suggested by Prof. Fischetti */ xprintf("PROBLEM HAS UNBOUNDED SOLUTION\n"); #else xprintf("LP HAS UNBOUNDED PRIMAL SOLUTION\n"); #endif store_sol(csa, lp, GLP_FEAS, GLP_NOFEAS, csa->head[csa->m+csa->q]); ret = 0; break; default: xassert(csa != csa); } goto done; } /* check if the pivot element is acceptable */ if (csa->p > 0) { double piv = csa->tcol_vec[csa->p]; double eps = 1e-5 * (1.0 + 0.01 * csa->tcol_max); if (fabs(piv) < eps) { if (parm->msg_lev >= GLP_MSG_DBG) xprintf("piv = %.12g; eps = %g\n", piv, eps); if (!rigorous) { rigorous = 5; goto loop; } } } /* now xN[q] and xB[p] have been chosen anyhow */ /* compute pivot row of the simplex table */ if (csa->p > 0) { double *rho = csa->work4; eval_rho(csa, rho); if (rigorous) refine_rho(csa, rho); eval_trow(csa, rho); } /* accuracy check based on the pivot element */ if (csa->p > 0) { double piv1 = csa->tcol_vec[csa->p]; /* more accurate */ double piv2 = csa->trow_vec[csa->q]; /* less accurate */ xassert(piv1 != 0.0); if (fabs(piv1 - piv2) > 1e-8 * (1.0 + fabs(piv1)) || !(piv1 > 0.0 && piv2 > 0.0 || piv1 < 0.0 && piv2 < 0.0)) { if (parm->msg_lev >= GLP_MSG_DBG) xprintf("piv1 = %.12g; piv2 = %.12g\n", piv1, piv2); if (binv_st != 1 || !rigorous) { if (binv_st != 1) binv_st = 0; rigorous = 5; goto loop; } /* use more accurate version in the pivot row */ if (csa->trow_vec[csa->q] == 0.0) { csa->trow_nnz++; xassert(csa->trow_nnz <= csa->n); csa->trow_ind[csa->trow_nnz] = csa->q; } csa->trow_vec[csa->q] = piv1; } } /* update primal values of basic variables */ update_bbar(csa); bbar_st = 2; /* updated */ /* update reduced costs of non-basic variables */ if (csa->p > 0) { update_cbar(csa); cbar_st = 2; /* updated */ /* on phase I objective coefficient of xB[p] in the adjacent basis becomes zero */ if (csa->phase == 1) { int k = csa->head[csa->p]; /* x[k] = xB[p] -> xN[q] */ csa->cbar[csa->q] -= csa->coef[k]; csa->coef[k] = 0.0; } } /* update steepest edge coefficients */ if (csa->p > 0) { switch (parm->pricing) { case GLP_PT_STD: break; case GLP_PT_PSE: if (csa->refct > 0) update_gamma(csa); break; default: xassert(parm != parm); } } /* update factorization of the basis matrix */ if (csa->p > 0) { ret = update_B(csa, csa->p, csa->head[csa->m+csa->q]); if (ret == 0) binv_st = 2; /* updated */ else { csa->valid = 0; binv_st = 0; /* invalid */ } } /* update matrix N */ if (csa->p > 0) { del_N_col(csa, csa->q, csa->head[csa->m+csa->q]); if (csa->type[csa->head[csa->p]] != GLP_FX) add_N_col(csa, csa->q, csa->head[csa->p]); } /* change the basis header */ change_basis(csa); /* iteration complete */ csa->it_cnt++; if (rigorous > 0) rigorous--; goto loop; done: /* deallocate the common storage area */ free_csa(csa); /* return to the calling program */ return ret; } /* eof */ Rglpk/src/GLPK/relax4.h0000644000176000001440000000775212245352174014275 0ustar ripleyusers/* relax4.h */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef RELAX4_H #define RELAX4_H struct relax4_csa { /* common storage area */ /* input parameters --------------------------------------------*/ int n; /* number of nodes */ int na; /* number of arcs */ int large; /* very large int to represent infinity */ int repeat; /* true if initialization is to be skipped (false otherwise) */ int crash; /* 0 if default initialization is used * 1 if auction initialization is used */ int *startn; /* int startn[1+na]; */ /* startn[j] = starting node for arc j, j = 1,...,na */ int *endn; /* int endn[1+na] */ /* endn[j] = ending node for arc j, j = 1,...,na */ int *fou; /* int fou[1+n]; */ /* fou[i] = first arc out of node i, i = 1,...,n */ int *nxtou; /* int nxtou[1+na]; */ /* nxtou[j] = next arc out of the starting node of arc j, * j = 1,...,na */ int *fin; /* int fin[1+n]; */ /* fin[i] = first arc into node i, i = 1,...,n */ int *nxtin; /* int nxtin[1+na]; */ /* nxtin[j] = next arc into the ending node of arc j, * j = 1,...,na */ /* updated parameters ------------------------------------------*/ int *rc; /* int rc[1+na]; */ /* rc[j] = reduced cost of arc j, j = 1,...,na */ int *u; /* int u[1+na]; */ /* u[j] = capacity of arc j on input * and (capacity of arc j) - x(j) on output, j = 1,...,na */ int *dfct; /* int dfct[1+n]; */ /* dfct[i] = demand at node i on input * and zero on output, i = 1,...,n */ /* output parameters -------------------------------------------*/ int *x; /* int x[1+na]; */ /* x[j] = flow on arc j, j = 1,...,na */ int nmultinode; /* number of multinode relaxation iterations in RELAX4 */ int iter; /* number of relaxation iterations in RELAX4 */ int num_augm; /* number of flow augmentation steps in RELAX4 */ int num_ascnt; /* number of multinode ascent steps in RELAX4 */ int nsp; /* number of auction/shortest path iterations */ /* working parameters ------------------------------------------*/ int *label; /* int label, tempin, p[1+n]; */ int *prdcsr; /* int prdcsr, tempou, price[1+n]; */ int *save; /* int save[1+na]; */ int *tfstou; /* int tfstou, fpushf[1+n]; */ int *tnxtou; /* int tnxtou, nxtpushf[1+na]; */ int *tfstin; /* int tfstin, fpushb[1+n]; */ int *tnxtin; /* int tnxtin, nxtpushb[1+na]; */ int *nxtqueue; /* int nxtqueue[1+n]; */ char *scan; /* bool scan[1+n]; */ char *mark; /* bool mark, path_id[1+n]; */ /* working parameters used by routine auction only -------------*/ int *extend_arc; /* int extend_arc[1+n]; */ int *sb_level; /* int sb_level[1+n]; */ int *sb_arc; /* int sb_arc[1+n]; */ }; #define relax4 _glp_relax4 int relax4(struct relax4_csa *csa); #define relax4_inidat _glp_relax4_inidat void relax4_inidat(struct relax4_csa *csa); #endif /* eof */ Rglpk/src/GLPK/glpapi13.c0000644000176000001440000005456312245352174014513 0ustar ripleyusers/* glpapi13.c (branch-and-bound interface routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpios.h" /*********************************************************************** * NAME * * glp_ios_reason - determine reason for calling the callback routine * * SYNOPSIS * * glp_ios_reason(glp_tree *tree); * * RETURNS * * The routine glp_ios_reason returns a code, which indicates why the * user-defined callback routine is being called. */ int glp_ios_reason(glp_tree *tree) { return tree->reason; } /*********************************************************************** * NAME * * glp_ios_get_prob - access the problem object * * SYNOPSIS * * glp_prob *glp_ios_get_prob(glp_tree *tree); * * DESCRIPTION * * The routine glp_ios_get_prob can be called from the user-defined * callback routine to access the problem object, which is used by the * MIP solver. It is the original problem object passed to the routine * glp_intopt if the MIP presolver is not used; otherwise it is an * internal problem object built by the presolver. If the current * subproblem exists, LP segment of the problem object corresponds to * its LP relaxation. * * RETURNS * * The routine glp_ios_get_prob returns a pointer to the problem object * used by the MIP solver. */ glp_prob *glp_ios_get_prob(glp_tree *tree) { return tree->mip; } /*********************************************************************** * NAME * * glp_ios_tree_size - determine size of the branch-and-bound tree * * SYNOPSIS * * void glp_ios_tree_size(glp_tree *tree, int *a_cnt, int *n_cnt, * int *t_cnt); * * DESCRIPTION * * The routine glp_ios_tree_size stores the following three counts which * characterize the current size of the branch-and-bound tree: * * a_cnt is the current number of active nodes, i.e. the current size of * the active list; * * n_cnt is the current number of all (active and inactive) nodes; * * t_cnt is the total number of nodes including those which have been * already removed from the tree. This count is increased whenever * a new node appears in the tree and never decreased. * * If some of the parameters a_cnt, n_cnt, t_cnt is a null pointer, the * corresponding count is not stored. */ void glp_ios_tree_size(glp_tree *tree, int *a_cnt, int *n_cnt, int *t_cnt) { if (a_cnt != NULL) *a_cnt = tree->a_cnt; if (n_cnt != NULL) *n_cnt = tree->n_cnt; if (t_cnt != NULL) *t_cnt = tree->t_cnt; return; } /*********************************************************************** * NAME * * glp_ios_curr_node - determine current active subproblem * * SYNOPSIS * * int glp_ios_curr_node(glp_tree *tree); * * RETURNS * * The routine glp_ios_curr_node returns the reference number of the * current active subproblem. However, if the current subproblem does * not exist, the routine returns zero. */ int glp_ios_curr_node(glp_tree *tree) { IOSNPD *node; /* obtain pointer to the current subproblem */ node = tree->curr; /* return its reference number */ return node == NULL ? 0 : node->p; } /*********************************************************************** * NAME * * glp_ios_next_node - determine next active subproblem * * SYNOPSIS * * int glp_ios_next_node(glp_tree *tree, int p); * * RETURNS * * If the parameter p is zero, the routine glp_ios_next_node returns * the reference number of the first active subproblem. However, if the * tree is empty, zero is returned. * * If the parameter p is not zero, it must specify the reference number * of some active subproblem, in which case the routine returns the * reference number of the next active subproblem. However, if there is * no next active subproblem in the list, zero is returned. * * All subproblems in the active list are ordered chronologically, i.e. * subproblem A precedes subproblem B if A was created before B. */ int glp_ios_next_node(glp_tree *tree, int p) { IOSNPD *node; if (p == 0) { /* obtain pointer to the first active subproblem */ node = tree->head; } else { /* obtain pointer to the specified subproblem */ if (!(1 <= p && p <= tree->nslots)) err: xerror("glp_ios_next_node: p = %d; invalid subproblem refer" "ence number\n", p); node = tree->slot[p].node; if (node == NULL) goto err; /* the specified subproblem must be active */ if (node->count != 0) xerror("glp_ios_next_node: p = %d; subproblem not in the ac" "tive list\n", p); /* obtain pointer to the next active subproblem */ node = node->next; } /* return the reference number */ return node == NULL ? 0 : node->p; } /*********************************************************************** * NAME * * glp_ios_prev_node - determine previous active subproblem * * SYNOPSIS * * int glp_ios_prev_node(glp_tree *tree, int p); * * RETURNS * * If the parameter p is zero, the routine glp_ios_prev_node returns * the reference number of the last active subproblem. However, if the * tree is empty, zero is returned. * * If the parameter p is not zero, it must specify the reference number * of some active subproblem, in which case the routine returns the * reference number of the previous active subproblem. However, if there * is no previous active subproblem in the list, zero is returned. * * All subproblems in the active list are ordered chronologically, i.e. * subproblem A precedes subproblem B if A was created before B. */ int glp_ios_prev_node(glp_tree *tree, int p) { IOSNPD *node; if (p == 0) { /* obtain pointer to the last active subproblem */ node = tree->tail; } else { /* obtain pointer to the specified subproblem */ if (!(1 <= p && p <= tree->nslots)) err: xerror("glp_ios_prev_node: p = %d; invalid subproblem refer" "ence number\n", p); node = tree->slot[p].node; if (node == NULL) goto err; /* the specified subproblem must be active */ if (node->count != 0) xerror("glp_ios_prev_node: p = %d; subproblem not in the ac" "tive list\n", p); /* obtain pointer to the previous active subproblem */ node = node->prev; } /* return the reference number */ return node == NULL ? 0 : node->p; } /*********************************************************************** * NAME * * glp_ios_up_node - determine parent subproblem * * SYNOPSIS * * int glp_ios_up_node(glp_tree *tree, int p); * * RETURNS * * The parameter p must specify the reference number of some (active or * inactive) subproblem, in which case the routine iet_get_up_node * returns the reference number of its parent subproblem. However, if * the specified subproblem is the root of the tree and, therefore, has * no parent, the routine returns zero. */ int glp_ios_up_node(glp_tree *tree, int p) { IOSNPD *node; /* obtain pointer to the specified subproblem */ if (!(1 <= p && p <= tree->nslots)) err: xerror("glp_ios_up_node: p = %d; invalid subproblem reference " "number\n", p); node = tree->slot[p].node; if (node == NULL) goto err; /* obtain pointer to the parent subproblem */ node = node->up; /* return the reference number */ return node == NULL ? 0 : node->p; } /*********************************************************************** * NAME * * glp_ios_node_level - determine subproblem level * * SYNOPSIS * * int glp_ios_node_level(glp_tree *tree, int p); * * RETURNS * * The routine glp_ios_node_level returns the level of the subproblem, * whose reference number is p, in the branch-and-bound tree. (The root * subproblem has level 0, and the level of any other subproblem is the * level of its parent plus one.) */ int glp_ios_node_level(glp_tree *tree, int p) { IOSNPD *node; /* obtain pointer to the specified subproblem */ if (!(1 <= p && p <= tree->nslots)) err: xerror("glp_ios_node_level: p = %d; invalid subproblem referen" "ce number\n", p); node = tree->slot[p].node; if (node == NULL) goto err; /* return the node level */ return node->level; } /*********************************************************************** * NAME * * glp_ios_node_bound - determine subproblem local bound * * SYNOPSIS * * double glp_ios_node_bound(glp_tree *tree, int p); * * RETURNS * * The routine glp_ios_node_bound returns the local bound for (active or * inactive) subproblem, whose reference number is p. * * COMMENTS * * The local bound for subproblem p is an lower (minimization) or upper * (maximization) bound for integer optimal solution to this subproblem * (not to the original problem). This bound is local in the sense that * only subproblems in the subtree rooted at node p cannot have better * integer feasible solutions. * * On creating a subproblem (due to the branching step) its local bound * is inherited from its parent and then may get only stronger (never * weaker). For the root subproblem its local bound is initially set to * -DBL_MAX (minimization) or +DBL_MAX (maximization) and then improved * as the root LP relaxation has been solved. * * Note that the local bound is not necessarily the optimal objective * value to corresponding LP relaxation; it may be stronger. */ double glp_ios_node_bound(glp_tree *tree, int p) { IOSNPD *node; /* obtain pointer to the specified subproblem */ if (!(1 <= p && p <= tree->nslots)) err: xerror("glp_ios_node_bound: p = %d; invalid subproblem referen" "ce number\n", p); node = tree->slot[p].node; if (node == NULL) goto err; /* return the node local bound */ return node->bound; } /*********************************************************************** * NAME * * glp_ios_best_node - find active subproblem with best local bound * * SYNOPSIS * * int glp_ios_best_node(glp_tree *tree); * * RETURNS * * The routine glp_ios_best_node returns the reference number of the * active subproblem, whose local bound is best (i.e. smallest in case * of minimization or largest in case of maximization). However, if the * tree is empty, the routine returns zero. * * COMMENTS * * The best local bound is an lower (minimization) or upper * (maximization) bound for integer optimal solution to the original * MIP problem. */ int glp_ios_best_node(glp_tree *tree) { return ios_best_node(tree); } /*********************************************************************** * NAME * * glp_ios_mip_gap - compute relative MIP gap * * SYNOPSIS * * double glp_ios_mip_gap(glp_tree *tree); * * DESCRIPTION * * The routine glp_ios_mip_gap computes the relative MIP gap with the * following formula: * * gap = |best_mip - best_bnd| / (|best_mip| + DBL_EPSILON), * * where best_mip is the best integer feasible solution found so far, * best_bnd is the best (global) bound. If no integer feasible solution * has been found yet, gap is set to DBL_MAX. * * RETURNS * * The routine glp_ios_mip_gap returns the relative MIP gap. */ double glp_ios_mip_gap(glp_tree *tree) { return ios_relative_gap(tree); } /*********************************************************************** * NAME * * glp_ios_node_data - access subproblem application-specific data * * SYNOPSIS * * void *glp_ios_node_data(glp_tree *tree, int p); * * DESCRIPTION * * The routine glp_ios_node_data allows the application accessing a * memory block allocated for the subproblem (which may be active or * inactive), whose reference number is p. * * The size of the block is defined by the control parameter cb_size * passed to the routine glp_intopt. The block is initialized by binary * zeros on creating corresponding subproblem, and its contents is kept * until the subproblem will be removed from the tree. * * The application may use these memory blocks to store specific data * for each subproblem. * * RETURNS * * The routine glp_ios_node_data returns a pointer to the memory block * for the specified subproblem. Note that if cb_size = 0, the routine * returns a null pointer. */ void *glp_ios_node_data(glp_tree *tree, int p) { IOSNPD *node; /* obtain pointer to the specified subproblem */ if (!(1 <= p && p <= tree->nslots)) err: xerror("glp_ios_node_level: p = %d; invalid subproblem referen" "ce number\n", p); node = tree->slot[p].node; if (node == NULL) goto err; /* return pointer to the application-specific data */ return node->data; } /*********************************************************************** * NAME * * glp_ios_row_attr - retrieve additional row attributes * * SYNOPSIS * * void glp_ios_row_attr(glp_tree *tree, int i, glp_attr *attr); * * DESCRIPTION * * The routine glp_ios_row_attr retrieves additional attributes of row * i and stores them in the structure glp_attr. */ void glp_ios_row_attr(glp_tree *tree, int i, glp_attr *attr) { GLPROW *row; if (!(1 <= i && i <= tree->mip->m)) xerror("glp_ios_row_attr: i = %d; row number out of range\n", i); row = tree->mip->row[i]; attr->level = row->level; attr->origin = row->origin; attr->klass = row->klass; return; } /**********************************************************************/ int glp_ios_pool_size(glp_tree *tree) { /* determine current size of the cut pool */ if (tree->reason != GLP_ICUTGEN) xerror("glp_ios_pool_size: operation not allowed\n"); xassert(tree->local != NULL); return tree->local->size; } /**********************************************************************/ int glp_ios_add_row(glp_tree *tree, const char *name, int klass, int flags, int len, const int ind[], const double val[], int type, double rhs) { /* add row (constraint) to the cut pool */ int num; if (tree->reason != GLP_ICUTGEN) xerror("glp_ios_add_row: operation not allowed\n"); xassert(tree->local != NULL); num = ios_add_row(tree, tree->local, name, klass, flags, len, ind, val, type, rhs); return num; } /**********************************************************************/ void glp_ios_del_row(glp_tree *tree, int i) { /* remove row (constraint) from the cut pool */ if (tree->reason != GLP_ICUTGEN) xerror("glp_ios_del_row: operation not allowed\n"); ios_del_row(tree, tree->local, i); return; } /**********************************************************************/ void glp_ios_clear_pool(glp_tree *tree) { /* remove all rows (constraints) from the cut pool */ if (tree->reason != GLP_ICUTGEN) xerror("glp_ios_clear_pool: operation not allowed\n"); ios_clear_pool(tree, tree->local); return; } /*********************************************************************** * NAME * * glp_ios_can_branch - check if can branch upon specified variable * * SYNOPSIS * * int glp_ios_can_branch(glp_tree *tree, int j); * * RETURNS * * If j-th variable (column) can be used to branch upon, the routine * glp_ios_can_branch returns non-zero, otherwise zero. */ int glp_ios_can_branch(glp_tree *tree, int j) { if (!(1 <= j && j <= tree->mip->n)) xerror("glp_ios_can_branch: j = %d; column number out of range" "\n", j); return tree->non_int[j]; } /*********************************************************************** * NAME * * glp_ios_branch_upon - choose variable to branch upon * * SYNOPSIS * * void glp_ios_branch_upon(glp_tree *tree, int j, int sel); * * DESCRIPTION * * The routine glp_ios_branch_upon can be called from the user-defined * callback routine in response to the reason GLP_IBRANCH to choose a * branching variable, whose ordinal number is j. Should note that only * variables, for which the routine glp_ios_can_branch returns non-zero, * can be used to branch upon. * * The parameter sel is a flag that indicates which branch (subproblem) * should be selected next to continue the search: * * GLP_DN_BRNCH - select down-branch; * GLP_UP_BRNCH - select up-branch; * GLP_NO_BRNCH - use general selection technique. */ void glp_ios_branch_upon(glp_tree *tree, int j, int sel) { if (!(1 <= j && j <= tree->mip->n)) xerror("glp_ios_branch_upon: j = %d; column number out of rang" "e\n", j); if (!(sel == GLP_DN_BRNCH || sel == GLP_UP_BRNCH || sel == GLP_NO_BRNCH)) xerror("glp_ios_branch_upon: sel = %d: invalid branch selectio" "n flag\n", sel); if (!(tree->non_int[j])) xerror("glp_ios_branch_upon: j = %d; variable cannot be used t" "o branch upon\n", j); if (tree->br_var != 0) xerror("glp_ios_branch_upon: branching variable already chosen" "\n"); tree->br_var = j; tree->br_sel = sel; return; } /*********************************************************************** * NAME * * glp_ios_select_node - select subproblem to continue the search * * SYNOPSIS * * void glp_ios_select_node(glp_tree *tree, int p); * * DESCRIPTION * * The routine glp_ios_select_node can be called from the user-defined * callback routine in response to the reason GLP_ISELECT to select an * active subproblem, whose reference number is p. The search will be * continued from the subproblem selected. */ void glp_ios_select_node(glp_tree *tree, int p) { IOSNPD *node; /* obtain pointer to the specified subproblem */ if (!(1 <= p && p <= tree->nslots)) err: xerror("glp_ios_select_node: p = %d; invalid subproblem refere" "nce number\n", p); node = tree->slot[p].node; if (node == NULL) goto err; /* the specified subproblem must be active */ if (node->count != 0) xerror("glp_ios_select_node: p = %d; subproblem not in the act" "ive list\n", p); /* no subproblem must be selected yet */ if (tree->next_p != 0) xerror("glp_ios_select_node: subproblem already selected\n"); /* select the specified subproblem to continue the search */ tree->next_p = p; return; } /*********************************************************************** * NAME * * glp_ios_heur_sol - provide solution found by heuristic * * SYNOPSIS * * int glp_ios_heur_sol(glp_tree *tree, const double x[]); * * DESCRIPTION * * The routine glp_ios_heur_sol can be called from the user-defined * callback routine in response to the reason GLP_IHEUR to provide an * integer feasible solution found by a primal heuristic. * * Primal values of *all* variables (columns) found by the heuristic * should be placed in locations x[1], ..., x[n], where n is the number * of columns in the original problem object. Note that the routine * glp_ios_heur_sol *does not* check primal feasibility of the solution * provided. * * Using the solution passed in the array x the routine computes value * of the objective function. If the objective value is better than the * best known integer feasible solution, the routine computes values of * auxiliary variables (rows) and stores all solution components in the * problem object. * * RETURNS * * If the provided solution is accepted, the routine glp_ios_heur_sol * returns zero. Otherwise, if the provided solution is rejected, the * routine returns non-zero. */ int glp_ios_heur_sol(glp_tree *tree, const double x[]) { glp_prob *mip = tree->mip; int m = tree->orig_m; int n = tree->n; int i, j; double obj; xassert(mip->m >= m); xassert(mip->n == n); /* check values of integer variables and compute value of the objective function */ obj = mip->c0; for (j = 1; j <= n; j++) { GLPCOL *col = mip->col[j]; if (col->kind == GLP_IV) { /* provided value must be integral */ if (x[j] != floor(x[j])) return 1; } obj += col->coef * x[j]; } /* check if the provided solution is better than the best known integer feasible solution */ if (mip->mip_stat == GLP_FEAS) { switch (mip->dir) { case GLP_MIN: if (obj >= tree->mip->mip_obj) return 1; break; case GLP_MAX: if (obj <= tree->mip->mip_obj) return 1; break; default: xassert(mip != mip); } } /* it is better; store it in the problem object */ if (tree->parm->msg_lev >= GLP_MSG_ON) xprintf("Solution found by heuristic: %.12g\n", obj); mip->mip_stat = GLP_FEAS; mip->mip_obj = obj; for (j = 1; j <= n; j++) mip->col[j]->mipx = x[j]; for (i = 1; i <= m; i++) { GLPROW *row = mip->row[i]; GLPAIJ *aij; row->mipx = 0.0; for (aij = row->ptr; aij != NULL; aij = aij->r_next) row->mipx += aij->val * aij->col->mipx; } #if 1 /* 11/VII-2013 */ ios_process_sol(tree); #endif return 0; } /*********************************************************************** * NAME * * glp_ios_terminate - terminate the solution process. * * SYNOPSIS * * void glp_ios_terminate(glp_tree *tree); * * DESCRIPTION * * The routine glp_ios_terminate sets a flag indicating that the MIP * solver should prematurely terminate the search. */ void glp_ios_terminate(glp_tree *tree) { if (tree->parm->msg_lev >= GLP_MSG_DBG) xprintf("The search is prematurely terminated due to applicati" "on request\n"); tree->stop = 1; return; } /* eof */ Rglpk/src/GLPK/colamd/0000755000176000001440000000000012175147600014147 5ustar ripleyusersRglpk/src/GLPK/colamd/colamd.c0000644000176000001440000036777412245352174015604 0ustar ripleyusers/* ========================================================================== */ /* === colamd/symamd - a sparse matrix column ordering algorithm ============ */ /* ========================================================================== */ /* COLAMD / SYMAMD colamd: an approximate minimum degree column ordering algorithm, for LU factorization of symmetric or unsymmetric matrices, QR factorization, least squares, interior point methods for linear programming problems, and other related problems. symamd: an approximate minimum degree ordering algorithm for Cholesky factorization of symmetric matrices. Purpose: Colamd computes a permutation Q such that the Cholesky factorization of (AQ)'(AQ) has less fill-in and requires fewer floating point operations than A'A. This also provides a good ordering for sparse partial pivoting methods, P(AQ) = LU, where Q is computed prior to numerical factorization, and P is computed during numerical factorization via conventional partial pivoting with row interchanges. Colamd is the column ordering method used in SuperLU, part of the ScaLAPACK library. It is also available as built-in function in MATLAB Version 6, available from MathWorks, Inc. (http://www.mathworks.com). This routine can be used in place of colmmd in MATLAB. Symamd computes a permutation P of a symmetric matrix A such that the Cholesky factorization of PAP' has less fill-in and requires fewer floating point operations than A. Symamd constructs a matrix M such that M'M has the same nonzero pattern of A, and then orders the columns of M using colmmd. The column ordering of M is then returned as the row and column ordering P of A. Authors: The authors of the code itself are Stefan I. Larimore and Timothy A. Davis (davis at cise.ufl.edu), University of Florida. The algorithm was developed in collaboration with John Gilbert, Xerox PARC, and Esmond Ng, Oak Ridge National Laboratory. Acknowledgements: This work was supported by the National Science Foundation, under grants DMS-9504974 and DMS-9803599. Copyright and License: Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved. COLAMD is also available under alternate licenses, contact T. Davis for details. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Permission is hereby granted to use or copy this program under the terms of the GNU LGPL, provided that the Copyright, this License, and the Availability of the original version is retained on all copies. User documentation of any code that uses this code or any modified version of this code must cite the Copyright, this License, the Availability note, and "Used by permission." Permission to modify the code and to distribute modified code is granted, provided the Copyright, this License, and the Availability note are retained, and a notice that the code was modified is included. Availability: The colamd/symamd library is available at http://www.cise.ufl.edu/research/sparse/colamd/ This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.c file. It requires the colamd.h file. It is required by the colamdmex.c and symamdmex.c files, for the MATLAB interface to colamd and symamd. Appears as ACM Algorithm 836. See the ChangeLog file for changes since Version 1.0. References: T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column minimum degree ordering algorithm, ACM Transactions on Mathematical Software, vol. 30, no. 3., pp. 353-376, 2004. T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD, an approximate column minimum degree ordering algorithm, ACM Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380, 2004. */ /* ========================================================================== */ /* === Description of user-callable routines ================================ */ /* ========================================================================== */ /* COLAMD includes both int and UF_long versions of all its routines. The * description below is for the int version. For UF_long, all int arguments * become UF_long. UF_long is normally defined as long, except for WIN64. ---------------------------------------------------------------------------- colamd_recommended: ---------------------------------------------------------------------------- C syntax: #include "colamd.h" size_t colamd_recommended (int nnz, int n_row, int n_col) ; size_t colamd_l_recommended (UF_long nnz, UF_long n_row, UF_long n_col) ; Purpose: Returns recommended value of Alen for use by colamd. Returns 0 if any input argument is negative. The use of this routine is optional. Not needed for symamd, which dynamically allocates its own memory. Note that in v2.4 and earlier, these routines returned int or long. They now return a value of type size_t. Arguments (all input arguments): int nnz ; Number of nonzeros in the matrix A. This must be the same value as p [n_col] in the call to colamd - otherwise you will get a wrong value of the recommended memory to use. int n_row ; Number of rows in the matrix A. int n_col ; Number of columns in the matrix A. ---------------------------------------------------------------------------- colamd_set_defaults: ---------------------------------------------------------------------------- C syntax: #include "colamd.h" colamd_set_defaults (double knobs [COLAMD_KNOBS]) ; colamd_l_set_defaults (double knobs [COLAMD_KNOBS]) ; Purpose: Sets the default parameters. The use of this routine is optional. Arguments: double knobs [COLAMD_KNOBS] ; Output only. NOTE: the meaning of the dense row/col knobs has changed in v2.4 knobs [0] and knobs [1] control dense row and col detection: Colamd: rows with more than max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n_col)) entries are removed prior to ordering. Columns with more than max (16, knobs [COLAMD_DENSE_COL] * sqrt (MIN (n_row,n_col))) entries are removed prior to ordering, and placed last in the output column ordering. Symamd: uses only knobs [COLAMD_DENSE_ROW], which is knobs [0]. Rows and columns with more than max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n)) entries are removed prior to ordering, and placed last in the output ordering. COLAMD_DENSE_ROW and COLAMD_DENSE_COL are defined as 0 and 1, respectively, in colamd.h. Default values of these two knobs are both 10. Currently, only knobs [0] and knobs [1] are used, but future versions may use more knobs. If so, they will be properly set to their defaults by the future version of colamd_set_defaults, so that the code that calls colamd will not need to change, assuming that you either use colamd_set_defaults, or pass a (double *) NULL pointer as the knobs array to colamd or symamd. knobs [2]: aggressive absorption knobs [COLAMD_AGGRESSIVE] controls whether or not to do aggressive absorption during the ordering. Default is TRUE. ---------------------------------------------------------------------------- colamd: ---------------------------------------------------------------------------- C syntax: #include "colamd.h" int colamd (int n_row, int n_col, int Alen, int *A, int *p, double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS]) ; UF_long colamd_l (UF_long n_row, UF_long n_col, UF_long Alen, UF_long *A, UF_long *p, double knobs [COLAMD_KNOBS], UF_long stats [COLAMD_STATS]) ; Purpose: Computes a column ordering (Q) of A such that P(AQ)=LU or (AQ)'AQ=LL' have less fill-in and require fewer floating point operations than factorizing the unpermuted matrix A or A'A, respectively. Returns: TRUE (1) if successful, FALSE (0) otherwise. Arguments: int n_row ; Input argument. Number of rows in the matrix A. Restriction: n_row >= 0. Colamd returns FALSE if n_row is negative. int n_col ; Input argument. Number of columns in the matrix A. Restriction: n_col >= 0. Colamd returns FALSE if n_col is negative. int Alen ; Input argument. Restriction (see note): Alen >= 2*nnz + 6*(n_col+1) + 4*(n_row+1) + n_col Colamd returns FALSE if these conditions are not met. Note: this restriction makes an modest assumption regarding the size of the two typedef's structures in colamd.h. We do, however, guarantee that Alen >= colamd_recommended (nnz, n_row, n_col) will be sufficient. Note: the macro version does not check for integer overflow, and thus is not recommended. Use the colamd_recommended routine instead. int A [Alen] ; Input argument, undefined on output. A is an integer array of size Alen. Alen must be at least as large as the bare minimum value given above, but this is very low, and can result in excessive run time. For best performance, we recommend that Alen be greater than or equal to colamd_recommended (nnz, n_row, n_col), which adds nnz/5 to the bare minimum value given above. On input, the row indices of the entries in column c of the matrix are held in A [(p [c]) ... (p [c+1]-1)]. The row indices in a given column c need not be in ascending order, and duplicate row indices may be be present. However, colamd will work a little faster if both of these conditions are met (Colamd puts the matrix into this format, if it finds that the the conditions are not met). The matrix is 0-based. That is, rows are in the range 0 to n_row-1, and columns are in the range 0 to n_col-1. Colamd returns FALSE if any row index is out of range. The contents of A are modified during ordering, and are undefined on output. int p [n_col+1] ; Both input and output argument. p is an integer array of size n_col+1. On input, it holds the "pointers" for the column form of the matrix A. Column c of the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first entry, p [0], must be zero, and p [c] <= p [c+1] must hold for all c in the range 0 to n_col-1. The value p [n_col] is thus the total number of entries in the pattern of the matrix A. Colamd returns FALSE if these conditions are not met. On output, if colamd returns TRUE, the array p holds the column permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is the first column index in the new ordering, and p [n_col-1] is the last. That is, p [k] = j means that column j of A is the kth pivot column, in AQ, where k is in the range 0 to n_col-1 (p [0] = j means that column j of A is the first column in AQ). If colamd returns FALSE, then no permutation is returned, and p is undefined on output. double knobs [COLAMD_KNOBS] ; Input argument. See colamd_set_defaults for a description. int stats [COLAMD_STATS] ; Output argument. Statistics on the ordering, and error status. See colamd.h for related definitions. Colamd returns FALSE if stats is not present. stats [0]: number of dense or empty rows ignored. stats [1]: number of dense or empty columns ignored (and ordered last in the output permutation p) Note that a row can become "empty" if it contains only "dense" and/or "empty" columns, and similarly a column can become "empty" if it only contains "dense" and/or "empty" rows. stats [2]: number of garbage collections performed. This can be excessively high if Alen is close to the minimum required value. stats [3]: status code. < 0 is an error code. > 1 is a warning or notice. 0 OK. Each column of the input matrix contained row indices in increasing order, with no duplicates. 1 OK, but columns of input matrix were jumbled (unsorted columns or duplicate entries). Colamd had to do some extra work to sort the matrix first and remove duplicate entries, but it still was able to return a valid permutation (return value of colamd was TRUE). stats [4]: highest numbered column that is unsorted or has duplicate entries. stats [5]: last seen duplicate or unsorted row index. stats [6]: number of duplicate or unsorted row indices. -1 A is a null pointer -2 p is a null pointer -3 n_row is negative stats [4]: n_row -4 n_col is negative stats [4]: n_col -5 number of nonzeros in matrix is negative stats [4]: number of nonzeros, p [n_col] -6 p [0] is nonzero stats [4]: p [0] -7 A is too small stats [4]: required size stats [5]: actual size (Alen) -8 a column has a negative number of entries stats [4]: column with < 0 entries stats [5]: number of entries in col -9 a row index is out of bounds stats [4]: column with bad row index stats [5]: bad row index stats [6]: n_row, # of rows of matrx -10 (unused; see symamd.c) -999 (unused; see symamd.c) Future versions may return more statistics in the stats array. Example: See http://www.cise.ufl.edu/research/sparse/colamd/example.c for a complete example. To order the columns of a 5-by-4 matrix with 11 nonzero entries in the following nonzero pattern x 0 x 0 x 0 x x 0 x x 0 0 0 x x x x 0 0 with default knobs and no output statistics, do the following: #include "colamd.h" #define ALEN 100 int A [ALEN] = {0, 1, 4, 2, 4, 0, 1, 2, 3, 1, 3} ; int p [ ] = {0, 3, 5, 9, 11} ; int stats [COLAMD_STATS] ; colamd (5, 4, ALEN, A, p, (double *) NULL, stats) ; The permutation is returned in the array p, and A is destroyed. ---------------------------------------------------------------------------- symamd: ---------------------------------------------------------------------------- C syntax: #include "colamd.h" int symamd (int n, int *A, int *p, int *perm, double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS], void (*allocate) (size_t, size_t), void (*release) (void *)) ; UF_long symamd_l (UF_long n, UF_long *A, UF_long *p, UF_long *perm, double knobs [COLAMD_KNOBS], UF_long stats [COLAMD_STATS], void (*allocate) (size_t, size_t), void (*release) (void *)) ; Purpose: The symamd routine computes an ordering P of a symmetric sparse matrix A such that the Cholesky factorization PAP' = LL' remains sparse. It is based on a column ordering of a matrix M constructed so that the nonzero pattern of M'M is the same as A. The matrix A is assumed to be symmetric; only the strictly lower triangular part is accessed. You must pass your selected memory allocator (usually calloc/free or mxCalloc/mxFree) to symamd, for it to allocate memory for the temporary matrix M. Returns: TRUE (1) if successful, FALSE (0) otherwise. Arguments: int n ; Input argument. Number of rows and columns in the symmetrix matrix A. Restriction: n >= 0. Symamd returns FALSE if n is negative. int A [nnz] ; Input argument. A is an integer array of size nnz, where nnz = p [n]. The row indices of the entries in column c of the matrix are held in A [(p [c]) ... (p [c+1]-1)]. The row indices in a given column c need not be in ascending order, and duplicate row indices may be present. However, symamd will run faster if the columns are in sorted order with no duplicate entries. The matrix is 0-based. That is, rows are in the range 0 to n-1, and columns are in the range 0 to n-1. Symamd returns FALSE if any row index is out of range. The contents of A are not modified. int p [n+1] ; Input argument. p is an integer array of size n+1. On input, it holds the "pointers" for the column form of the matrix A. Column c of the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first entry, p [0], must be zero, and p [c] <= p [c+1] must hold for all c in the range 0 to n-1. The value p [n] is thus the total number of entries in the pattern of the matrix A. Symamd returns FALSE if these conditions are not met. The contents of p are not modified. int perm [n+1] ; Output argument. On output, if symamd returns TRUE, the array perm holds the permutation P, where perm [0] is the first index in the new ordering, and perm [n-1] is the last. That is, perm [k] = j means that row and column j of A is the kth column in PAP', where k is in the range 0 to n-1 (perm [0] = j means that row and column j of A are the first row and column in PAP'). The array is used as a workspace during the ordering, which is why it must be of length n+1, not just n. double knobs [COLAMD_KNOBS] ; Input argument. See colamd_set_defaults for a description. int stats [COLAMD_STATS] ; Output argument. Statistics on the ordering, and error status. See colamd.h for related definitions. Symamd returns FALSE if stats is not present. stats [0]: number of dense or empty row and columns ignored (and ordered last in the output permutation perm). Note that a row/column can become "empty" if it contains only "dense" and/or "empty" columns/rows. stats [1]: (same as stats [0]) stats [2]: number of garbage collections performed. stats [3]: status code. < 0 is an error code. > 1 is a warning or notice. 0 OK. Each column of the input matrix contained row indices in increasing order, with no duplicates. 1 OK, but columns of input matrix were jumbled (unsorted columns or duplicate entries). Symamd had to do some extra work to sort the matrix first and remove duplicate entries, but it still was able to return a valid permutation (return value of symamd was TRUE). stats [4]: highest numbered column that is unsorted or has duplicate entries. stats [5]: last seen duplicate or unsorted row index. stats [6]: number of duplicate or unsorted row indices. -1 A is a null pointer -2 p is a null pointer -3 (unused, see colamd.c) -4 n is negative stats [4]: n -5 number of nonzeros in matrix is negative stats [4]: # of nonzeros (p [n]). -6 p [0] is nonzero stats [4]: p [0] -7 (unused) -8 a column has a negative number of entries stats [4]: column with < 0 entries stats [5]: number of entries in col -9 a row index is out of bounds stats [4]: column with bad row index stats [5]: bad row index stats [6]: n_row, # of rows of matrx -10 out of memory (unable to allocate temporary workspace for M or count arrays using the "allocate" routine passed into symamd). Future versions may return more statistics in the stats array. void * (*allocate) (size_t, size_t) A pointer to a function providing memory allocation. The allocated memory must be returned initialized to zero. For a C application, this argument should normally be a pointer to calloc. For a MATLAB mexFunction, the routine mxCalloc is passed instead. void (*release) (size_t, size_t) A pointer to a function that frees memory allocated by the memory allocation routine above. For a C application, this argument should normally be a pointer to free. For a MATLAB mexFunction, the routine mxFree is passed instead. ---------------------------------------------------------------------------- colamd_report: ---------------------------------------------------------------------------- C syntax: #include "colamd.h" colamd_report (int stats [COLAMD_STATS]) ; colamd_l_report (UF_long stats [COLAMD_STATS]) ; Purpose: Prints the error status and statistics recorded in the stats array on the standard error output (for a standard C routine) or on the MATLAB output (for a mexFunction). Arguments: int stats [COLAMD_STATS] ; Input only. Statistics from colamd. ---------------------------------------------------------------------------- symamd_report: ---------------------------------------------------------------------------- C syntax: #include "colamd.h" symamd_report (int stats [COLAMD_STATS]) ; symamd_l_report (UF_long stats [COLAMD_STATS]) ; Purpose: Prints the error status and statistics recorded in the stats array on the standard error output (for a standard C routine) or on the MATLAB output (for a mexFunction). Arguments: int stats [COLAMD_STATS] ; Input only. Statistics from symamd. */ /* ========================================================================== */ /* === Scaffolding code definitions ======================================== */ /* ========================================================================== */ /* Ensure that debugging is turned off: */ #ifndef NDEBUG #define NDEBUG #endif /* turn on debugging by uncommenting the following line #undef NDEBUG */ /* Our "scaffolding code" philosophy: In our opinion, well-written library code should keep its "debugging" code, and just normally have it turned off by the compiler so as not to interfere with performance. This serves several purposes: (1) assertions act as comments to the reader, telling you what the code expects at that point. All assertions will always be true (unless there really is a bug, of course). (2) leaving in the scaffolding code assists anyone who would like to modify the code, or understand the algorithm (by reading the debugging output, one can get a glimpse into what the code is doing). (3) (gasp!) for actually finding bugs. This code has been heavily tested and "should" be fully functional and bug-free ... but you never know... The code will become outrageously slow when debugging is enabled. To control the level of debugging output, set an environment variable D to 0 (little), 1 (some), 2, 3, or 4 (lots). When debugging, you should see the following message on the standard output: colamd: debug version, D = 1 (THIS WILL BE SLOW!) or a similar message for symamd. If you don't, then debugging has not been enabled. */ /* ========================================================================== */ /* === Include files ======================================================== */ /* ========================================================================== */ #include "colamd.h" #if 0 /* by mao */ #include #include #ifdef MATLAB_MEX_FILE #include "mex.h" #include "matrix.h" #endif /* MATLAB_MEX_FILE */ #if !defined (NPRINT) || !defined (NDEBUG) #include #endif #ifndef NULL #define NULL ((void *) 0) #endif #endif /* ========================================================================== */ /* === int or UF_long ======================================================= */ /* ========================================================================== */ #if 0 /* by mao */ /* define UF_long */ #include "UFconfig.h" #endif #ifdef DLONG #define Int UF_long #define ID UF_long_id #define Int_MAX UF_long_max #define COLAMD_recommended colamd_l_recommended #define COLAMD_set_defaults colamd_l_set_defaults #define COLAMD_MAIN colamd_l #define SYMAMD_MAIN symamd_l #define COLAMD_report colamd_l_report #define SYMAMD_report symamd_l_report #else #define Int int #define ID "%d" #define Int_MAX INT_MAX #define COLAMD_recommended colamd_recommended #define COLAMD_set_defaults colamd_set_defaults #define COLAMD_MAIN colamd #define SYMAMD_MAIN symamd #define COLAMD_report colamd_report #define SYMAMD_report symamd_report #endif /* ========================================================================== */ /* === Row and Column structures ============================================ */ /* ========================================================================== */ /* User code that makes use of the colamd/symamd routines need not directly */ /* reference these structures. They are used only for colamd_recommended. */ typedef struct Colamd_Col_struct { Int start ; /* index for A of first row in this column, or DEAD */ /* if column is dead */ Int length ; /* number of rows in this column */ union { Int thickness ; /* number of original columns represented by this */ /* col, if the column is alive */ Int parent ; /* parent in parent tree super-column structure, if */ /* the column is dead */ } shared1 ; union { Int score ; /* the score used to maintain heap, if col is alive */ Int order ; /* pivot ordering of this column, if col is dead */ } shared2 ; union { Int headhash ; /* head of a hash bucket, if col is at the head of */ /* a degree list */ Int hash ; /* hash value, if col is not in a degree list */ Int prev ; /* previous column in degree list, if col is in a */ /* degree list (but not at the head of a degree list) */ } shared3 ; union { Int degree_next ; /* next column, if col is in a degree list */ Int hash_next ; /* next column, if col is in a hash list */ } shared4 ; } Colamd_Col ; typedef struct Colamd_Row_struct { Int start ; /* index for A of first col in this row */ Int length ; /* number of principal columns in this row */ union { Int degree ; /* number of principal & non-principal columns in row */ Int p ; /* used as a row pointer in init_rows_cols () */ } shared1 ; union { Int mark ; /* for computing set differences and marking dead rows*/ Int first_column ;/* first column in row (used in garbage collection) */ } shared2 ; } Colamd_Row ; /* ========================================================================== */ /* === Definitions ========================================================== */ /* ========================================================================== */ /* Routines are either PUBLIC (user-callable) or PRIVATE (not user-callable) */ #define PUBLIC #define PRIVATE static #define DENSE_DEGREE(alpha,n) \ ((Int) MAX (16.0, (alpha) * sqrt ((double) (n)))) #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define ONES_COMPLEMENT(r) (-(r)-1) /* -------------------------------------------------------------------------- */ /* Change for version 2.1: define TRUE and FALSE only if not yet defined */ /* -------------------------------------------------------------------------- */ #ifndef TRUE #define TRUE (1) #endif #ifndef FALSE #define FALSE (0) #endif /* -------------------------------------------------------------------------- */ #define EMPTY (-1) /* Row and column status */ #define ALIVE (0) #define DEAD (-1) /* Column status */ #define DEAD_PRINCIPAL (-1) #define DEAD_NON_PRINCIPAL (-2) /* Macros for row and column status update and checking. */ #define ROW_IS_DEAD(r) ROW_IS_MARKED_DEAD (Row[r].shared2.mark) #define ROW_IS_MARKED_DEAD(row_mark) (row_mark < ALIVE) #define ROW_IS_ALIVE(r) (Row [r].shared2.mark >= ALIVE) #define COL_IS_DEAD(c) (Col [c].start < ALIVE) #define COL_IS_ALIVE(c) (Col [c].start >= ALIVE) #define COL_IS_DEAD_PRINCIPAL(c) (Col [c].start == DEAD_PRINCIPAL) #define KILL_ROW(r) { Row [r].shared2.mark = DEAD ; } #define KILL_PRINCIPAL_COL(c) { Col [c].start = DEAD_PRINCIPAL ; } #define KILL_NON_PRINCIPAL_COL(c) { Col [c].start = DEAD_NON_PRINCIPAL ; } /* ========================================================================== */ /* === Colamd reporting mechanism =========================================== */ /* ========================================================================== */ #if defined (MATLAB_MEX_FILE) || defined (MATHWORKS) /* In MATLAB, matrices are 1-based to the user, but 0-based internally */ #define INDEX(i) ((i)+1) #else /* In C, matrices are 0-based and indices are reported as such in *_report */ #define INDEX(i) (i) #endif /* All output goes through the PRINTF macro. */ #define PRINTF(params) { if (colamd_printf != NULL) (void) colamd_printf params ; } /* ========================================================================== */ /* === Prototypes of PRIVATE routines ======================================= */ /* ========================================================================== */ PRIVATE Int init_rows_cols ( Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [], Int p [], Int stats [COLAMD_STATS] ) ; PRIVATE void init_scoring ( Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [], Int head [], double knobs [COLAMD_KNOBS], Int *p_n_row2, Int *p_n_col2, Int *p_max_deg ) ; PRIVATE Int find_ordering ( Int n_row, Int n_col, Int Alen, Colamd_Row Row [], Colamd_Col Col [], Int A [], Int head [], Int n_col2, Int max_deg, Int pfree, Int aggressive ) ; PRIVATE void order_children ( Int n_col, Colamd_Col Col [], Int p [] ) ; PRIVATE void detect_super_cols ( #ifndef NDEBUG Int n_col, Colamd_Row Row [], #endif /* NDEBUG */ Colamd_Col Col [], Int A [], Int head [], Int row_start, Int row_length ) ; PRIVATE Int garbage_collection ( Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [], Int *pfree ) ; PRIVATE Int clear_mark ( Int tag_mark, Int max_mark, Int n_row, Colamd_Row Row [] ) ; PRIVATE void print_report ( char *method, Int stats [COLAMD_STATS] ) ; /* ========================================================================== */ /* === Debugging prototypes and definitions ================================= */ /* ========================================================================== */ #ifndef NDEBUG #if 0 /* by mao */ #include #endif /* colamd_debug is the *ONLY* global variable, and is only */ /* present when debugging */ PRIVATE Int colamd_debug = 0 ; /* debug print level */ #define DEBUG0(params) { PRINTF (params) ; } #define DEBUG1(params) { if (colamd_debug >= 1) PRINTF (params) ; } #define DEBUG2(params) { if (colamd_debug >= 2) PRINTF (params) ; } #define DEBUG3(params) { if (colamd_debug >= 3) PRINTF (params) ; } #define DEBUG4(params) { if (colamd_debug >= 4) PRINTF (params) ; } #if 0 /* by mao */ #ifdef MATLAB_MEX_FILE #define ASSERT(expression) (mxAssert ((expression), "")) #else #define ASSERT(expression) (assert (expression)) #endif /* MATLAB_MEX_FILE */ #else #define ASSERT xassert #endif PRIVATE void colamd_get_debug /* gets the debug print level from getenv */ ( char *method ) ; PRIVATE void debug_deg_lists ( Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int head [], Int min_score, Int should, Int max_deg ) ; PRIVATE void debug_mark ( Int n_row, Colamd_Row Row [], Int tag_mark, Int max_mark ) ; PRIVATE void debug_matrix ( Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [] ) ; PRIVATE void debug_structures ( Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [], Int n_col2 ) ; #else /* NDEBUG */ /* === No debugging ========================================================= */ #define DEBUG0(params) ; #define DEBUG1(params) ; #define DEBUG2(params) ; #define DEBUG3(params) ; #define DEBUG4(params) ; #define ASSERT(expression) #endif /* NDEBUG */ /* ========================================================================== */ /* === USER-CALLABLE ROUTINES: ============================================== */ /* ========================================================================== */ /* ========================================================================== */ /* === colamd_recommended =================================================== */ /* ========================================================================== */ /* The colamd_recommended routine returns the suggested size for Alen. This value has been determined to provide good balance between the number of garbage collections and the memory requirements for colamd. If any argument is negative, or if integer overflow occurs, a 0 is returned as an error condition. 2*nnz space is required for the row and column indices of the matrix. COLAMD_C (n_col) + COLAMD_R (n_row) space is required for the Col and Row arrays, respectively, which are internal to colamd (roughly 6*n_col + 4*n_row). An additional n_col space is the minimal amount of "elbow room", and nnz/5 more space is recommended for run time efficiency. Alen is approximately 2.2*nnz + 7*n_col + 4*n_row + 10. This function is not needed when using symamd. */ /* add two values of type size_t, and check for integer overflow */ static size_t t_add (size_t a, size_t b, int *ok) { (*ok) = (*ok) && ((a + b) >= MAX (a,b)) ; return ((*ok) ? (a + b) : 0) ; } /* compute a*k where k is a small integer, and check for integer overflow */ static size_t t_mult (size_t a, size_t k, int *ok) { size_t i, s = 0 ; for (i = 0 ; i < k ; i++) { s = t_add (s, a, ok) ; } return (s) ; } /* size of the Col and Row structures */ #define COLAMD_C(n_col,ok) \ ((t_mult (t_add (n_col, 1, ok), sizeof (Colamd_Col), ok) / sizeof (Int))) #define COLAMD_R(n_row,ok) \ ((t_mult (t_add (n_row, 1, ok), sizeof (Colamd_Row), ok) / sizeof (Int))) PUBLIC size_t COLAMD_recommended /* returns recommended value of Alen. */ ( /* === Parameters ======================================================= */ Int nnz, /* number of nonzeros in A */ Int n_row, /* number of rows in A */ Int n_col /* number of columns in A */ ) { size_t s, c, r ; int ok = TRUE ; if (nnz < 0 || n_row < 0 || n_col < 0) { return (0) ; } s = t_mult (nnz, 2, &ok) ; /* 2*nnz */ c = COLAMD_C (n_col, &ok) ; /* size of column structures */ r = COLAMD_R (n_row, &ok) ; /* size of row structures */ s = t_add (s, c, &ok) ; s = t_add (s, r, &ok) ; s = t_add (s, n_col, &ok) ; /* elbow room */ s = t_add (s, nnz/5, &ok) ; /* elbow room */ ok = ok && (s < Int_MAX) ; return (ok ? s : 0) ; } /* ========================================================================== */ /* === colamd_set_defaults ================================================== */ /* ========================================================================== */ /* The colamd_set_defaults routine sets the default values of the user- controllable parameters for colamd and symamd: Colamd: rows with more than max (16, knobs [0] * sqrt (n_col)) entries are removed prior to ordering. Columns with more than max (16, knobs [1] * sqrt (MIN (n_row,n_col))) entries are removed prior to ordering, and placed last in the output column ordering. Symamd: Rows and columns with more than max (16, knobs [0] * sqrt (n)) entries are removed prior to ordering, and placed last in the output ordering. knobs [0] dense row control knobs [1] dense column control knobs [2] if nonzero, do aggresive absorption knobs [3..19] unused, but future versions might use this */ PUBLIC void COLAMD_set_defaults ( /* === Parameters ======================================================= */ double knobs [COLAMD_KNOBS] /* knob array */ ) { /* === Local variables ================================================== */ Int i ; if (!knobs) { return ; /* no knobs to initialize */ } for (i = 0 ; i < COLAMD_KNOBS ; i++) { knobs [i] = 0 ; } knobs [COLAMD_DENSE_ROW] = 10 ; knobs [COLAMD_DENSE_COL] = 10 ; knobs [COLAMD_AGGRESSIVE] = TRUE ; /* default: do aggressive absorption*/ } /* ========================================================================== */ /* === symamd =============================================================== */ /* ========================================================================== */ PUBLIC Int SYMAMD_MAIN /* return TRUE if OK, FALSE otherwise */ ( /* === Parameters ======================================================= */ Int n, /* number of rows and columns of A */ Int A [], /* row indices of A */ Int p [], /* column pointers of A */ Int perm [], /* output permutation, size n+1 */ double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */ Int stats [COLAMD_STATS], /* output statistics and error codes */ void * (*allocate) (size_t, size_t), /* pointer to calloc (ANSI C) or */ /* mxCalloc (for MATLAB mexFunction) */ void (*release) (void *) /* pointer to free (ANSI C) or */ /* mxFree (for MATLAB mexFunction) */ ) { /* === Local variables ================================================== */ Int *count ; /* length of each column of M, and col pointer*/ Int *mark ; /* mark array for finding duplicate entries */ Int *M ; /* row indices of matrix M */ size_t Mlen ; /* length of M */ Int n_row ; /* number of rows in M */ Int nnz ; /* number of entries in A */ Int i ; /* row index of A */ Int j ; /* column index of A */ Int k ; /* row index of M */ Int mnz ; /* number of nonzeros in M */ Int pp ; /* index into a column of A */ Int last_row ; /* last row seen in the current column */ Int length ; /* number of nonzeros in a column */ double cknobs [COLAMD_KNOBS] ; /* knobs for colamd */ double default_knobs [COLAMD_KNOBS] ; /* default knobs for colamd */ #ifndef NDEBUG colamd_get_debug ("symamd") ; #endif /* NDEBUG */ /* === Check the input arguments ======================================== */ if (!stats) { DEBUG0 (("symamd: stats not present\n")) ; return (FALSE) ; } for (i = 0 ; i < COLAMD_STATS ; i++) { stats [i] = 0 ; } stats [COLAMD_STATUS] = COLAMD_OK ; stats [COLAMD_INFO1] = -1 ; stats [COLAMD_INFO2] = -1 ; if (!A) { stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ; DEBUG0 (("symamd: A not present\n")) ; return (FALSE) ; } if (!p) /* p is not present */ { stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ; DEBUG0 (("symamd: p not present\n")) ; return (FALSE) ; } if (n < 0) /* n must be >= 0 */ { stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ; stats [COLAMD_INFO1] = n ; DEBUG0 (("symamd: n negative %d\n", n)) ; return (FALSE) ; } nnz = p [n] ; if (nnz < 0) /* nnz must be >= 0 */ { stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ; stats [COLAMD_INFO1] = nnz ; DEBUG0 (("symamd: number of entries negative %d\n", nnz)) ; return (FALSE) ; } if (p [0] != 0) { stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ; stats [COLAMD_INFO1] = p [0] ; DEBUG0 (("symamd: p[0] not zero %d\n", p [0])) ; return (FALSE) ; } /* === If no knobs, set default knobs =================================== */ if (!knobs) { COLAMD_set_defaults (default_knobs) ; knobs = default_knobs ; } /* === Allocate count and mark ========================================== */ count = (Int *) ((*allocate) (n+1, sizeof (Int))) ; if (!count) { stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ; DEBUG0 (("symamd: allocate count (size %d) failed\n", n+1)) ; return (FALSE) ; } mark = (Int *) ((*allocate) (n+1, sizeof (Int))) ; if (!mark) { stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ; (*release) ((void *) count) ; DEBUG0 (("symamd: allocate mark (size %d) failed\n", n+1)) ; return (FALSE) ; } /* === Compute column counts of M, check if A is valid ================== */ stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/ for (i = 0 ; i < n ; i++) { mark [i] = -1 ; } for (j = 0 ; j < n ; j++) { last_row = -1 ; length = p [j+1] - p [j] ; if (length < 0) { /* column pointers must be non-decreasing */ stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ; stats [COLAMD_INFO1] = j ; stats [COLAMD_INFO2] = length ; (*release) ((void *) count) ; (*release) ((void *) mark) ; DEBUG0 (("symamd: col %d negative length %d\n", j, length)) ; return (FALSE) ; } for (pp = p [j] ; pp < p [j+1] ; pp++) { i = A [pp] ; if (i < 0 || i >= n) { /* row index i, in column j, is out of bounds */ stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ; stats [COLAMD_INFO1] = j ; stats [COLAMD_INFO2] = i ; stats [COLAMD_INFO3] = n ; (*release) ((void *) count) ; (*release) ((void *) mark) ; DEBUG0 (("symamd: row %d col %d out of bounds\n", i, j)) ; return (FALSE) ; } if (i <= last_row || mark [i] == j) { /* row index is unsorted or repeated (or both), thus col */ /* is jumbled. This is a notice, not an error condition. */ stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ; stats [COLAMD_INFO1] = j ; stats [COLAMD_INFO2] = i ; (stats [COLAMD_INFO3]) ++ ; DEBUG1 (("symamd: row %d col %d unsorted/duplicate\n", i, j)) ; } if (i > j && mark [i] != j) { /* row k of M will contain column indices i and j */ count [i]++ ; count [j]++ ; } /* mark the row as having been seen in this column */ mark [i] = j ; last_row = i ; } } /* v2.4: removed free(mark) */ /* === Compute column pointers of M ===================================== */ /* use output permutation, perm, for column pointers of M */ perm [0] = 0 ; for (j = 1 ; j <= n ; j++) { perm [j] = perm [j-1] + count [j-1] ; } for (j = 0 ; j < n ; j++) { count [j] = perm [j] ; } /* === Construct M ====================================================== */ mnz = perm [n] ; n_row = mnz / 2 ; Mlen = COLAMD_recommended (mnz, n_row, n) ; M = (Int *) ((*allocate) (Mlen, sizeof (Int))) ; DEBUG0 (("symamd: M is %d-by-%d with %d entries, Mlen = %g\n", n_row, n, mnz, (double) Mlen)) ; if (!M) { stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ; (*release) ((void *) count) ; (*release) ((void *) mark) ; DEBUG0 (("symamd: allocate M (size %g) failed\n", (double) Mlen)) ; return (FALSE) ; } k = 0 ; if (stats [COLAMD_STATUS] == COLAMD_OK) { /* Matrix is OK */ for (j = 0 ; j < n ; j++) { ASSERT (p [j+1] - p [j] >= 0) ; for (pp = p [j] ; pp < p [j+1] ; pp++) { i = A [pp] ; ASSERT (i >= 0 && i < n) ; if (i > j) { /* row k of M contains column indices i and j */ M [count [i]++] = k ; M [count [j]++] = k ; k++ ; } } } } else { /* Matrix is jumbled. Do not add duplicates to M. Unsorted cols OK. */ DEBUG0 (("symamd: Duplicates in A.\n")) ; for (i = 0 ; i < n ; i++) { mark [i] = -1 ; } for (j = 0 ; j < n ; j++) { ASSERT (p [j+1] - p [j] >= 0) ; for (pp = p [j] ; pp < p [j+1] ; pp++) { i = A [pp] ; ASSERT (i >= 0 && i < n) ; if (i > j && mark [i] != j) { /* row k of M contains column indices i and j */ M [count [i]++] = k ; M [count [j]++] = k ; k++ ; mark [i] = j ; } } } /* v2.4: free(mark) moved below */ } /* count and mark no longer needed */ (*release) ((void *) count) ; (*release) ((void *) mark) ; /* v2.4: free (mark) moved here */ ASSERT (k == n_row) ; /* === Adjust the knobs for M =========================================== */ for (i = 0 ; i < COLAMD_KNOBS ; i++) { cknobs [i] = knobs [i] ; } /* there are no dense rows in M */ cknobs [COLAMD_DENSE_ROW] = -1 ; cknobs [COLAMD_DENSE_COL] = knobs [COLAMD_DENSE_ROW] ; /* === Order the columns of M =========================================== */ /* v2.4: colamd cannot fail here, so the error check is removed */ (void) COLAMD_MAIN (n_row, n, (Int) Mlen, M, perm, cknobs, stats) ; /* Note that the output permutation is now in perm */ /* === get the statistics for symamd from colamd ======================== */ /* a dense column in colamd means a dense row and col in symamd */ stats [COLAMD_DENSE_ROW] = stats [COLAMD_DENSE_COL] ; /* === Free M =========================================================== */ (*release) ((void *) M) ; DEBUG0 (("symamd: done.\n")) ; return (TRUE) ; } /* ========================================================================== */ /* === colamd =============================================================== */ /* ========================================================================== */ /* The colamd routine computes a column ordering Q of a sparse matrix A such that the LU factorization P(AQ) = LU remains sparse, where P is selected via partial pivoting. The routine can also be viewed as providing a permutation Q such that the Cholesky factorization (AQ)'(AQ) = LL' remains sparse. */ PUBLIC Int COLAMD_MAIN /* returns TRUE if successful, FALSE otherwise*/ ( /* === Parameters ======================================================= */ Int n_row, /* number of rows in A */ Int n_col, /* number of columns in A */ Int Alen, /* length of A */ Int A [], /* row indices of A */ Int p [], /* pointers to columns in A */ double knobs [COLAMD_KNOBS],/* parameters (uses defaults if NULL) */ Int stats [COLAMD_STATS] /* output statistics and error codes */ ) { /* === Local variables ================================================== */ Int i ; /* loop index */ Int nnz ; /* nonzeros in A */ size_t Row_size ; /* size of Row [], in integers */ size_t Col_size ; /* size of Col [], in integers */ size_t need ; /* minimum required length of A */ Colamd_Row *Row ; /* pointer into A of Row [0..n_row] array */ Colamd_Col *Col ; /* pointer into A of Col [0..n_col] array */ Int n_col2 ; /* number of non-dense, non-empty columns */ Int n_row2 ; /* number of non-dense, non-empty rows */ Int ngarbage ; /* number of garbage collections performed */ Int max_deg ; /* maximum row degree */ double default_knobs [COLAMD_KNOBS] ; /* default knobs array */ Int aggressive ; /* do aggressive absorption */ int ok ; #ifndef NDEBUG colamd_get_debug ("colamd") ; #endif /* NDEBUG */ /* === Check the input arguments ======================================== */ if (!stats) { DEBUG0 (("colamd: stats not present\n")) ; return (FALSE) ; } for (i = 0 ; i < COLAMD_STATS ; i++) { stats [i] = 0 ; } stats [COLAMD_STATUS] = COLAMD_OK ; stats [COLAMD_INFO1] = -1 ; stats [COLAMD_INFO2] = -1 ; if (!A) /* A is not present */ { stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ; DEBUG0 (("colamd: A not present\n")) ; return (FALSE) ; } if (!p) /* p is not present */ { stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ; DEBUG0 (("colamd: p not present\n")) ; return (FALSE) ; } if (n_row < 0) /* n_row must be >= 0 */ { stats [COLAMD_STATUS] = COLAMD_ERROR_nrow_negative ; stats [COLAMD_INFO1] = n_row ; DEBUG0 (("colamd: nrow negative %d\n", n_row)) ; return (FALSE) ; } if (n_col < 0) /* n_col must be >= 0 */ { stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ; stats [COLAMD_INFO1] = n_col ; DEBUG0 (("colamd: ncol negative %d\n", n_col)) ; return (FALSE) ; } nnz = p [n_col] ; if (nnz < 0) /* nnz must be >= 0 */ { stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ; stats [COLAMD_INFO1] = nnz ; DEBUG0 (("colamd: number of entries negative %d\n", nnz)) ; return (FALSE) ; } if (p [0] != 0) { stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ; stats [COLAMD_INFO1] = p [0] ; DEBUG0 (("colamd: p[0] not zero %d\n", p [0])) ; return (FALSE) ; } /* === If no knobs, set default knobs =================================== */ if (!knobs) { COLAMD_set_defaults (default_knobs) ; knobs = default_knobs ; } aggressive = (knobs [COLAMD_AGGRESSIVE] != FALSE) ; /* === Allocate the Row and Col arrays from array A ===================== */ ok = TRUE ; Col_size = COLAMD_C (n_col, &ok) ; /* size of Col array of structs */ Row_size = COLAMD_R (n_row, &ok) ; /* size of Row array of structs */ /* need = 2*nnz + n_col + Col_size + Row_size ; */ need = t_mult (nnz, 2, &ok) ; need = t_add (need, n_col, &ok) ; need = t_add (need, Col_size, &ok) ; need = t_add (need, Row_size, &ok) ; if (!ok || need > (size_t) Alen || need > Int_MAX) { /* not enough space in array A to perform the ordering */ stats [COLAMD_STATUS] = COLAMD_ERROR_A_too_small ; stats [COLAMD_INFO1] = need ; stats [COLAMD_INFO2] = Alen ; DEBUG0 (("colamd: Need Alen >= %d, given only Alen = %d\n", need,Alen)); return (FALSE) ; } Alen -= Col_size + Row_size ; Col = (Colamd_Col *) &A [Alen] ; Row = (Colamd_Row *) &A [Alen + Col_size] ; /* === Construct the row and column data structures ===================== */ if (!init_rows_cols (n_row, n_col, Row, Col, A, p, stats)) { /* input matrix is invalid */ DEBUG0 (("colamd: Matrix invalid\n")) ; return (FALSE) ; } /* === Initialize scores, kill dense rows/columns ======================= */ init_scoring (n_row, n_col, Row, Col, A, p, knobs, &n_row2, &n_col2, &max_deg) ; /* === Order the supercolumns =========================================== */ ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p, n_col2, max_deg, 2*nnz, aggressive) ; /* === Order the non-principal columns ================================== */ order_children (n_col, Col, p) ; /* === Return statistics in stats ======================================= */ stats [COLAMD_DENSE_ROW] = n_row - n_row2 ; stats [COLAMD_DENSE_COL] = n_col - n_col2 ; stats [COLAMD_DEFRAG_COUNT] = ngarbage ; DEBUG0 (("colamd: done.\n")) ; return (TRUE) ; } /* ========================================================================== */ /* === colamd_report ======================================================== */ /* ========================================================================== */ PUBLIC void COLAMD_report ( Int stats [COLAMD_STATS] ) { print_report ("colamd", stats) ; } /* ========================================================================== */ /* === symamd_report ======================================================== */ /* ========================================================================== */ PUBLIC void SYMAMD_report ( Int stats [COLAMD_STATS] ) { print_report ("symamd", stats) ; } /* ========================================================================== */ /* === NON-USER-CALLABLE ROUTINES: ========================================== */ /* ========================================================================== */ /* There are no user-callable routines beyond this point in the file */ /* ========================================================================== */ /* === init_rows_cols ======================================================= */ /* ========================================================================== */ /* Takes the column form of the matrix in A and creates the row form of the matrix. Also, row and column attributes are stored in the Col and Row structs. If the columns are un-sorted or contain duplicate row indices, this routine will also sort and remove duplicate row indices from the column form of the matrix. Returns FALSE if the matrix is invalid, TRUE otherwise. Not user-callable. */ PRIVATE Int init_rows_cols /* returns TRUE if OK, or FALSE otherwise */ ( /* === Parameters ======================================================= */ Int n_row, /* number of rows of A */ Int n_col, /* number of columns of A */ Colamd_Row Row [], /* of size n_row+1 */ Colamd_Col Col [], /* of size n_col+1 */ Int A [], /* row indices of A, of size Alen */ Int p [], /* pointers to columns in A, of size n_col+1 */ Int stats [COLAMD_STATS] /* colamd statistics */ ) { /* === Local variables ================================================== */ Int col ; /* a column index */ Int row ; /* a row index */ Int *cp ; /* a column pointer */ Int *cp_end ; /* a pointer to the end of a column */ Int *rp ; /* a row pointer */ Int *rp_end ; /* a pointer to the end of a row */ Int last_row ; /* previous row */ /* === Initialize columns, and check column pointers ==================== */ for (col = 0 ; col < n_col ; col++) { Col [col].start = p [col] ; Col [col].length = p [col+1] - p [col] ; if (Col [col].length < 0) { /* column pointers must be non-decreasing */ stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ; stats [COLAMD_INFO1] = col ; stats [COLAMD_INFO2] = Col [col].length ; DEBUG0 (("colamd: col %d length %d < 0\n", col, Col [col].length)) ; return (FALSE) ; } Col [col].shared1.thickness = 1 ; Col [col].shared2.score = 0 ; Col [col].shared3.prev = EMPTY ; Col [col].shared4.degree_next = EMPTY ; } /* p [0..n_col] no longer needed, used as "head" in subsequent routines */ /* === Scan columns, compute row degrees, and check row indices ========= */ stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/ for (row = 0 ; row < n_row ; row++) { Row [row].length = 0 ; Row [row].shared2.mark = -1 ; } for (col = 0 ; col < n_col ; col++) { last_row = -1 ; cp = &A [p [col]] ; cp_end = &A [p [col+1]] ; while (cp < cp_end) { row = *cp++ ; /* make sure row indices within range */ if (row < 0 || row >= n_row) { stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ; stats [COLAMD_INFO1] = col ; stats [COLAMD_INFO2] = row ; stats [COLAMD_INFO3] = n_row ; DEBUG0 (("colamd: row %d col %d out of bounds\n", row, col)) ; return (FALSE) ; } if (row <= last_row || Row [row].shared2.mark == col) { /* row index are unsorted or repeated (or both), thus col */ /* is jumbled. This is a notice, not an error condition. */ stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ; stats [COLAMD_INFO1] = col ; stats [COLAMD_INFO2] = row ; (stats [COLAMD_INFO3]) ++ ; DEBUG1 (("colamd: row %d col %d unsorted/duplicate\n",row,col)); } if (Row [row].shared2.mark != col) { Row [row].length++ ; } else { /* this is a repeated entry in the column, */ /* it will be removed */ Col [col].length-- ; } /* mark the row as having been seen in this column */ Row [row].shared2.mark = col ; last_row = row ; } } /* === Compute row pointers ============================================= */ /* row form of the matrix starts directly after the column */ /* form of matrix in A */ Row [0].start = p [n_col] ; Row [0].shared1.p = Row [0].start ; Row [0].shared2.mark = -1 ; for (row = 1 ; row < n_row ; row++) { Row [row].start = Row [row-1].start + Row [row-1].length ; Row [row].shared1.p = Row [row].start ; Row [row].shared2.mark = -1 ; } /* === Create row form ================================================== */ if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED) { /* if cols jumbled, watch for repeated row indices */ for (col = 0 ; col < n_col ; col++) { cp = &A [p [col]] ; cp_end = &A [p [col+1]] ; while (cp < cp_end) { row = *cp++ ; if (Row [row].shared2.mark != col) { A [(Row [row].shared1.p)++] = col ; Row [row].shared2.mark = col ; } } } } else { /* if cols not jumbled, we don't need the mark (this is faster) */ for (col = 0 ; col < n_col ; col++) { cp = &A [p [col]] ; cp_end = &A [p [col+1]] ; while (cp < cp_end) { A [(Row [*cp++].shared1.p)++] = col ; } } } /* === Clear the row marks and set row degrees ========================== */ for (row = 0 ; row < n_row ; row++) { Row [row].shared2.mark = 0 ; Row [row].shared1.degree = Row [row].length ; } /* === See if we need to re-create columns ============================== */ if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED) { DEBUG0 (("colamd: reconstructing column form, matrix jumbled\n")) ; #ifndef NDEBUG /* make sure column lengths are correct */ for (col = 0 ; col < n_col ; col++) { p [col] = Col [col].length ; } for (row = 0 ; row < n_row ; row++) { rp = &A [Row [row].start] ; rp_end = rp + Row [row].length ; while (rp < rp_end) { p [*rp++]-- ; } } for (col = 0 ; col < n_col ; col++) { ASSERT (p [col] == 0) ; } /* now p is all zero (different than when debugging is turned off) */ #endif /* NDEBUG */ /* === Compute col pointers ========================================= */ /* col form of the matrix starts at A [0]. */ /* Note, we may have a gap between the col form and the row */ /* form if there were duplicate entries, if so, it will be */ /* removed upon the first garbage collection */ Col [0].start = 0 ; p [0] = Col [0].start ; for (col = 1 ; col < n_col ; col++) { /* note that the lengths here are for pruned columns, i.e. */ /* no duplicate row indices will exist for these columns */ Col [col].start = Col [col-1].start + Col [col-1].length ; p [col] = Col [col].start ; } /* === Re-create col form =========================================== */ for (row = 0 ; row < n_row ; row++) { rp = &A [Row [row].start] ; rp_end = rp + Row [row].length ; while (rp < rp_end) { A [(p [*rp++])++] = row ; } } } /* === Done. Matrix is not (or no longer) jumbled ====================== */ return (TRUE) ; } /* ========================================================================== */ /* === init_scoring ========================================================= */ /* ========================================================================== */ /* Kills dense or empty columns and rows, calculates an initial score for each column, and places all columns in the degree lists. Not user-callable. */ PRIVATE void init_scoring ( /* === Parameters ======================================================= */ Int n_row, /* number of rows of A */ Int n_col, /* number of columns of A */ Colamd_Row Row [], /* of size n_row+1 */ Colamd_Col Col [], /* of size n_col+1 */ Int A [], /* column form and row form of A */ Int head [], /* of size n_col+1 */ double knobs [COLAMD_KNOBS],/* parameters */ Int *p_n_row2, /* number of non-dense, non-empty rows */ Int *p_n_col2, /* number of non-dense, non-empty columns */ Int *p_max_deg /* maximum row degree */ ) { /* === Local variables ================================================== */ Int c ; /* a column index */ Int r, row ; /* a row index */ Int *cp ; /* a column pointer */ Int deg ; /* degree of a row or column */ Int *cp_end ; /* a pointer to the end of a column */ Int *new_cp ; /* new column pointer */ Int col_length ; /* length of pruned column */ Int score ; /* current column score */ Int n_col2 ; /* number of non-dense, non-empty columns */ Int n_row2 ; /* number of non-dense, non-empty rows */ Int dense_row_count ; /* remove rows with more entries than this */ Int dense_col_count ; /* remove cols with more entries than this */ Int min_score ; /* smallest column score */ Int max_deg ; /* maximum row degree */ Int next_col ; /* Used to add to degree list.*/ #ifndef NDEBUG Int debug_count ; /* debug only. */ #endif /* NDEBUG */ /* === Extract knobs ==================================================== */ /* Note: if knobs contains a NaN, this is undefined: */ if (knobs [COLAMD_DENSE_ROW] < 0) { /* only remove completely dense rows */ dense_row_count = n_col-1 ; } else { dense_row_count = DENSE_DEGREE (knobs [COLAMD_DENSE_ROW], n_col) ; } if (knobs [COLAMD_DENSE_COL] < 0) { /* only remove completely dense columns */ dense_col_count = n_row-1 ; } else { dense_col_count = DENSE_DEGREE (knobs [COLAMD_DENSE_COL], MIN (n_row, n_col)) ; } DEBUG1 (("colamd: densecount: %d %d\n", dense_row_count, dense_col_count)) ; max_deg = 0 ; n_col2 = n_col ; n_row2 = n_row ; /* === Kill empty columns =============================================== */ /* Put the empty columns at the end in their natural order, so that LU */ /* factorization can proceed as far as possible. */ for (c = n_col-1 ; c >= 0 ; c--) { deg = Col [c].length ; if (deg == 0) { /* this is a empty column, kill and order it last */ Col [c].shared2.order = --n_col2 ; KILL_PRINCIPAL_COL (c) ; } } DEBUG1 (("colamd: null columns killed: %d\n", n_col - n_col2)) ; /* === Kill dense columns =============================================== */ /* Put the dense columns at the end, in their natural order */ for (c = n_col-1 ; c >= 0 ; c--) { /* skip any dead columns */ if (COL_IS_DEAD (c)) { continue ; } deg = Col [c].length ; if (deg > dense_col_count) { /* this is a dense column, kill and order it last */ Col [c].shared2.order = --n_col2 ; /* decrement the row degrees */ cp = &A [Col [c].start] ; cp_end = cp + Col [c].length ; while (cp < cp_end) { Row [*cp++].shared1.degree-- ; } KILL_PRINCIPAL_COL (c) ; } } DEBUG1 (("colamd: Dense and null columns killed: %d\n", n_col - n_col2)) ; /* === Kill dense and empty rows ======================================== */ for (r = 0 ; r < n_row ; r++) { deg = Row [r].shared1.degree ; ASSERT (deg >= 0 && deg <= n_col) ; if (deg > dense_row_count || deg == 0) { /* kill a dense or empty row */ KILL_ROW (r) ; --n_row2 ; } else { /* keep track of max degree of remaining rows */ max_deg = MAX (max_deg, deg) ; } } DEBUG1 (("colamd: Dense and null rows killed: %d\n", n_row - n_row2)) ; /* === Compute initial column scores ==================================== */ /* At this point the row degrees are accurate. They reflect the number */ /* of "live" (non-dense) columns in each row. No empty rows exist. */ /* Some "live" columns may contain only dead rows, however. These are */ /* pruned in the code below. */ /* now find the initial matlab score for each column */ for (c = n_col-1 ; c >= 0 ; c--) { /* skip dead column */ if (COL_IS_DEAD (c)) { continue ; } score = 0 ; cp = &A [Col [c].start] ; new_cp = cp ; cp_end = cp + Col [c].length ; while (cp < cp_end) { /* get a row */ row = *cp++ ; /* skip if dead */ if (ROW_IS_DEAD (row)) { continue ; } /* compact the column */ *new_cp++ = row ; /* add row's external degree */ score += Row [row].shared1.degree - 1 ; /* guard against integer overflow */ score = MIN (score, n_col) ; } /* determine pruned column length */ col_length = (Int) (new_cp - &A [Col [c].start]) ; if (col_length == 0) { /* a newly-made null column (all rows in this col are "dense" */ /* and have already been killed) */ DEBUG2 (("Newly null killed: %d\n", c)) ; Col [c].shared2.order = --n_col2 ; KILL_PRINCIPAL_COL (c) ; } else { /* set column length and set score */ ASSERT (score >= 0) ; ASSERT (score <= n_col) ; Col [c].length = col_length ; Col [c].shared2.score = score ; } } DEBUG1 (("colamd: Dense, null, and newly-null columns killed: %d\n", n_col-n_col2)) ; /* At this point, all empty rows and columns are dead. All live columns */ /* are "clean" (containing no dead rows) and simplicial (no supercolumns */ /* yet). Rows may contain dead columns, but all live rows contain at */ /* least one live column. */ #ifndef NDEBUG debug_structures (n_row, n_col, Row, Col, A, n_col2) ; #endif /* NDEBUG */ /* === Initialize degree lists ========================================== */ #ifndef NDEBUG debug_count = 0 ; #endif /* NDEBUG */ /* clear the hash buckets */ for (c = 0 ; c <= n_col ; c++) { head [c] = EMPTY ; } min_score = n_col ; /* place in reverse order, so low column indices are at the front */ /* of the lists. This is to encourage natural tie-breaking */ for (c = n_col-1 ; c >= 0 ; c--) { /* only add principal columns to degree lists */ if (COL_IS_ALIVE (c)) { DEBUG4 (("place %d score %d minscore %d ncol %d\n", c, Col [c].shared2.score, min_score, n_col)) ; /* === Add columns score to DList =============================== */ score = Col [c].shared2.score ; ASSERT (min_score >= 0) ; ASSERT (min_score <= n_col) ; ASSERT (score >= 0) ; ASSERT (score <= n_col) ; ASSERT (head [score] >= EMPTY) ; /* now add this column to dList at proper score location */ next_col = head [score] ; Col [c].shared3.prev = EMPTY ; Col [c].shared4.degree_next = next_col ; /* if there already was a column with the same score, set its */ /* previous pointer to this new column */ if (next_col != EMPTY) { Col [next_col].shared3.prev = c ; } head [score] = c ; /* see if this score is less than current min */ min_score = MIN (min_score, score) ; #ifndef NDEBUG debug_count++ ; #endif /* NDEBUG */ } } #ifndef NDEBUG DEBUG1 (("colamd: Live cols %d out of %d, non-princ: %d\n", debug_count, n_col, n_col-debug_count)) ; ASSERT (debug_count == n_col2) ; debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2, max_deg) ; #endif /* NDEBUG */ /* === Return number of remaining columns, and max row degree =========== */ *p_n_col2 = n_col2 ; *p_n_row2 = n_row2 ; *p_max_deg = max_deg ; } /* ========================================================================== */ /* === find_ordering ======================================================== */ /* ========================================================================== */ /* Order the principal columns of the supercolumn form of the matrix (no supercolumns on input). Uses a minimum approximate column minimum degree ordering method. Not user-callable. */ PRIVATE Int find_ordering /* return the number of garbage collections */ ( /* === Parameters ======================================================= */ Int n_row, /* number of rows of A */ Int n_col, /* number of columns of A */ Int Alen, /* size of A, 2*nnz + n_col or larger */ Colamd_Row Row [], /* of size n_row+1 */ Colamd_Col Col [], /* of size n_col+1 */ Int A [], /* column form and row form of A */ Int head [], /* of size n_col+1 */ Int n_col2, /* Remaining columns to order */ Int max_deg, /* Maximum row degree */ Int pfree, /* index of first free slot (2*nnz on entry) */ Int aggressive ) { /* === Local variables ================================================== */ Int k ; /* current pivot ordering step */ Int pivot_col ; /* current pivot column */ Int *cp ; /* a column pointer */ Int *rp ; /* a row pointer */ Int pivot_row ; /* current pivot row */ Int *new_cp ; /* modified column pointer */ Int *new_rp ; /* modified row pointer */ Int pivot_row_start ; /* pointer to start of pivot row */ Int pivot_row_degree ; /* number of columns in pivot row */ Int pivot_row_length ; /* number of supercolumns in pivot row */ Int pivot_col_score ; /* score of pivot column */ Int needed_memory ; /* free space needed for pivot row */ Int *cp_end ; /* pointer to the end of a column */ Int *rp_end ; /* pointer to the end of a row */ Int row ; /* a row index */ Int col ; /* a column index */ Int max_score ; /* maximum possible score */ Int cur_score ; /* score of current column */ unsigned Int hash ; /* hash value for supernode detection */ Int head_column ; /* head of hash bucket */ Int first_col ; /* first column in hash bucket */ Int tag_mark ; /* marker value for mark array */ Int row_mark ; /* Row [row].shared2.mark */ Int set_difference ; /* set difference size of row with pivot row */ Int min_score ; /* smallest column score */ Int col_thickness ; /* "thickness" (no. of columns in a supercol) */ Int max_mark ; /* maximum value of tag_mark */ Int pivot_col_thickness ; /* number of columns represented by pivot col */ Int prev_col ; /* Used by Dlist operations. */ Int next_col ; /* Used by Dlist operations. */ Int ngarbage ; /* number of garbage collections performed */ #ifndef NDEBUG Int debug_d ; /* debug loop counter */ Int debug_step = 0 ; /* debug loop counter */ #endif /* NDEBUG */ /* === Initialization and clear mark ==================================== */ max_mark = INT_MAX - n_col ; /* INT_MAX defined in */ tag_mark = clear_mark (0, max_mark, n_row, Row) ; min_score = 0 ; ngarbage = 0 ; DEBUG1 (("colamd: Ordering, n_col2=%d\n", n_col2)) ; /* === Order the columns ================================================ */ for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */) { #ifndef NDEBUG if (debug_step % 100 == 0) { DEBUG2 (("\n... Step k: %d out of n_col2: %d\n", k, n_col2)) ; } else { DEBUG3 (("\n----------Step k: %d out of n_col2: %d\n", k, n_col2)) ; } debug_step++ ; debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2-k, max_deg) ; debug_matrix (n_row, n_col, Row, Col, A) ; #endif /* NDEBUG */ /* === Select pivot column, and order it ============================ */ /* make sure degree list isn't empty */ ASSERT (min_score >= 0) ; ASSERT (min_score <= n_col) ; ASSERT (head [min_score] >= EMPTY) ; #ifndef NDEBUG for (debug_d = 0 ; debug_d < min_score ; debug_d++) { ASSERT (head [debug_d] == EMPTY) ; } #endif /* NDEBUG */ /* get pivot column from head of minimum degree list */ while (head [min_score] == EMPTY && min_score < n_col) { min_score++ ; } pivot_col = head [min_score] ; ASSERT (pivot_col >= 0 && pivot_col <= n_col) ; next_col = Col [pivot_col].shared4.degree_next ; head [min_score] = next_col ; if (next_col != EMPTY) { Col [next_col].shared3.prev = EMPTY ; } ASSERT (COL_IS_ALIVE (pivot_col)) ; /* remember score for defrag check */ pivot_col_score = Col [pivot_col].shared2.score ; /* the pivot column is the kth column in the pivot order */ Col [pivot_col].shared2.order = k ; /* increment order count by column thickness */ pivot_col_thickness = Col [pivot_col].shared1.thickness ; k += pivot_col_thickness ; ASSERT (pivot_col_thickness > 0) ; DEBUG3 (("Pivot col: %d thick %d\n", pivot_col, pivot_col_thickness)) ; /* === Garbage_collection, if necessary ============================= */ needed_memory = MIN (pivot_col_score, n_col - k) ; if (pfree + needed_memory >= Alen) { pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ; ngarbage++ ; /* after garbage collection we will have enough */ ASSERT (pfree + needed_memory < Alen) ; /* garbage collection has wiped out the Row[].shared2.mark array */ tag_mark = clear_mark (0, max_mark, n_row, Row) ; #ifndef NDEBUG debug_matrix (n_row, n_col, Row, Col, A) ; #endif /* NDEBUG */ } /* === Compute pivot row pattern ==================================== */ /* get starting location for this new merged row */ pivot_row_start = pfree ; /* initialize new row counts to zero */ pivot_row_degree = 0 ; /* tag pivot column as having been visited so it isn't included */ /* in merged pivot row */ Col [pivot_col].shared1.thickness = -pivot_col_thickness ; /* pivot row is the union of all rows in the pivot column pattern */ cp = &A [Col [pivot_col].start] ; cp_end = cp + Col [pivot_col].length ; while (cp < cp_end) { /* get a row */ row = *cp++ ; DEBUG4 (("Pivot col pattern %d %d\n", ROW_IS_ALIVE (row), row)) ; /* skip if row is dead */ if (ROW_IS_ALIVE (row)) { rp = &A [Row [row].start] ; rp_end = rp + Row [row].length ; while (rp < rp_end) { /* get a column */ col = *rp++ ; /* add the column, if alive and untagged */ col_thickness = Col [col].shared1.thickness ; if (col_thickness > 0 && COL_IS_ALIVE (col)) { /* tag column in pivot row */ Col [col].shared1.thickness = -col_thickness ; ASSERT (pfree < Alen) ; /* place column in pivot row */ A [pfree++] = col ; pivot_row_degree += col_thickness ; } } } } /* clear tag on pivot column */ Col [pivot_col].shared1.thickness = pivot_col_thickness ; max_deg = MAX (max_deg, pivot_row_degree) ; #ifndef NDEBUG DEBUG3 (("check2\n")) ; debug_mark (n_row, Row, tag_mark, max_mark) ; #endif /* NDEBUG */ /* === Kill all rows used to construct pivot row ==================== */ /* also kill pivot row, temporarily */ cp = &A [Col [pivot_col].start] ; cp_end = cp + Col [pivot_col].length ; while (cp < cp_end) { /* may be killing an already dead row */ row = *cp++ ; DEBUG3 (("Kill row in pivot col: %d\n", row)) ; KILL_ROW (row) ; } /* === Select a row index to use as the new pivot row =============== */ pivot_row_length = pfree - pivot_row_start ; if (pivot_row_length > 0) { /* pick the "pivot" row arbitrarily (first row in col) */ pivot_row = A [Col [pivot_col].start] ; DEBUG3 (("Pivotal row is %d\n", pivot_row)) ; } else { /* there is no pivot row, since it is of zero length */ pivot_row = EMPTY ; ASSERT (pivot_row_length == 0) ; } ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ; /* === Approximate degree computation =============================== */ /* Here begins the computation of the approximate degree. The column */ /* score is the sum of the pivot row "length", plus the size of the */ /* set differences of each row in the column minus the pattern of the */ /* pivot row itself. The column ("thickness") itself is also */ /* excluded from the column score (we thus use an approximate */ /* external degree). */ /* The time taken by the following code (compute set differences, and */ /* add them up) is proportional to the size of the data structure */ /* being scanned - that is, the sum of the sizes of each column in */ /* the pivot row. Thus, the amortized time to compute a column score */ /* is proportional to the size of that column (where size, in this */ /* context, is the column "length", or the number of row indices */ /* in that column). The number of row indices in a column is */ /* monotonically non-decreasing, from the length of the original */ /* column on input to colamd. */ /* === Compute set differences ====================================== */ DEBUG3 (("** Computing set differences phase. **\n")) ; /* pivot row is currently dead - it will be revived later. */ DEBUG3 (("Pivot row: ")) ; /* for each column in pivot row */ rp = &A [pivot_row_start] ; rp_end = rp + pivot_row_length ; while (rp < rp_end) { col = *rp++ ; ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ; DEBUG3 (("Col: %d\n", col)) ; /* clear tags used to construct pivot row pattern */ col_thickness = -Col [col].shared1.thickness ; ASSERT (col_thickness > 0) ; Col [col].shared1.thickness = col_thickness ; /* === Remove column from degree list =========================== */ cur_score = Col [col].shared2.score ; prev_col = Col [col].shared3.prev ; next_col = Col [col].shared4.degree_next ; ASSERT (cur_score >= 0) ; ASSERT (cur_score <= n_col) ; ASSERT (cur_score >= EMPTY) ; if (prev_col == EMPTY) { head [cur_score] = next_col ; } else { Col [prev_col].shared4.degree_next = next_col ; } if (next_col != EMPTY) { Col [next_col].shared3.prev = prev_col ; } /* === Scan the column ========================================== */ cp = &A [Col [col].start] ; cp_end = cp + Col [col].length ; while (cp < cp_end) { /* get a row */ row = *cp++ ; row_mark = Row [row].shared2.mark ; /* skip if dead */ if (ROW_IS_MARKED_DEAD (row_mark)) { continue ; } ASSERT (row != pivot_row) ; set_difference = row_mark - tag_mark ; /* check if the row has been seen yet */ if (set_difference < 0) { ASSERT (Row [row].shared1.degree <= max_deg) ; set_difference = Row [row].shared1.degree ; } /* subtract column thickness from this row's set difference */ set_difference -= col_thickness ; ASSERT (set_difference >= 0) ; /* absorb this row if the set difference becomes zero */ if (set_difference == 0 && aggressive) { DEBUG3 (("aggressive absorption. Row: %d\n", row)) ; KILL_ROW (row) ; } else { /* save the new mark */ Row [row].shared2.mark = set_difference + tag_mark ; } } } #ifndef NDEBUG debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2-k-pivot_row_degree, max_deg) ; #endif /* NDEBUG */ /* === Add up set differences for each column ======================= */ DEBUG3 (("** Adding set differences phase. **\n")) ; /* for each column in pivot row */ rp = &A [pivot_row_start] ; rp_end = rp + pivot_row_length ; while (rp < rp_end) { /* get a column */ col = *rp++ ; ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ; hash = 0 ; cur_score = 0 ; cp = &A [Col [col].start] ; /* compact the column */ new_cp = cp ; cp_end = cp + Col [col].length ; DEBUG4 (("Adding set diffs for Col: %d.\n", col)) ; while (cp < cp_end) { /* get a row */ row = *cp++ ; ASSERT(row >= 0 && row < n_row) ; row_mark = Row [row].shared2.mark ; /* skip if dead */ if (ROW_IS_MARKED_DEAD (row_mark)) { DEBUG4 ((" Row %d, dead\n", row)) ; continue ; } DEBUG4 ((" Row %d, set diff %d\n", row, row_mark-tag_mark)); ASSERT (row_mark >= tag_mark) ; /* compact the column */ *new_cp++ = row ; /* compute hash function */ hash += row ; /* add set difference */ cur_score += row_mark - tag_mark ; /* integer overflow... */ cur_score = MIN (cur_score, n_col) ; } /* recompute the column's length */ Col [col].length = (Int) (new_cp - &A [Col [col].start]) ; /* === Further mass elimination ================================= */ if (Col [col].length == 0) { DEBUG4 (("further mass elimination. Col: %d\n", col)) ; /* nothing left but the pivot row in this column */ KILL_PRINCIPAL_COL (col) ; pivot_row_degree -= Col [col].shared1.thickness ; ASSERT (pivot_row_degree >= 0) ; /* order it */ Col [col].shared2.order = k ; /* increment order count by column thickness */ k += Col [col].shared1.thickness ; } else { /* === Prepare for supercolumn detection ==================== */ DEBUG4 (("Preparing supercol detection for Col: %d.\n", col)) ; /* save score so far */ Col [col].shared2.score = cur_score ; /* add column to hash table, for supercolumn detection */ hash %= n_col + 1 ; DEBUG4 ((" Hash = %d, n_col = %d.\n", hash, n_col)) ; ASSERT (((Int) hash) <= n_col) ; head_column = head [hash] ; if (head_column > EMPTY) { /* degree list "hash" is non-empty, use prev (shared3) of */ /* first column in degree list as head of hash bucket */ first_col = Col [head_column].shared3.headhash ; Col [head_column].shared3.headhash = col ; } else { /* degree list "hash" is empty, use head as hash bucket */ first_col = - (head_column + 2) ; head [hash] = - (col + 2) ; } Col [col].shared4.hash_next = first_col ; /* save hash function in Col [col].shared3.hash */ Col [col].shared3.hash = (Int) hash ; ASSERT (COL_IS_ALIVE (col)) ; } } /* The approximate external column degree is now computed. */ /* === Supercolumn detection ======================================== */ DEBUG3 (("** Supercolumn detection phase. **\n")) ; detect_super_cols ( #ifndef NDEBUG n_col, Row, #endif /* NDEBUG */ Col, A, head, pivot_row_start, pivot_row_length) ; /* === Kill the pivotal column ====================================== */ KILL_PRINCIPAL_COL (pivot_col) ; /* === Clear mark =================================================== */ tag_mark = clear_mark (tag_mark+max_deg+1, max_mark, n_row, Row) ; #ifndef NDEBUG DEBUG3 (("check3\n")) ; debug_mark (n_row, Row, tag_mark, max_mark) ; #endif /* NDEBUG */ /* === Finalize the new pivot row, and column scores ================ */ DEBUG3 (("** Finalize scores phase. **\n")) ; /* for each column in pivot row */ rp = &A [pivot_row_start] ; /* compact the pivot row */ new_rp = rp ; rp_end = rp + pivot_row_length ; while (rp < rp_end) { col = *rp++ ; /* skip dead columns */ if (COL_IS_DEAD (col)) { continue ; } *new_rp++ = col ; /* add new pivot row to column */ A [Col [col].start + (Col [col].length++)] = pivot_row ; /* retrieve score so far and add on pivot row's degree. */ /* (we wait until here for this in case the pivot */ /* row's degree was reduced due to mass elimination). */ cur_score = Col [col].shared2.score + pivot_row_degree ; /* calculate the max possible score as the number of */ /* external columns minus the 'k' value minus the */ /* columns thickness */ max_score = n_col - k - Col [col].shared1.thickness ; /* make the score the external degree of the union-of-rows */ cur_score -= Col [col].shared1.thickness ; /* make sure score is less or equal than the max score */ cur_score = MIN (cur_score, max_score) ; ASSERT (cur_score >= 0) ; /* store updated score */ Col [col].shared2.score = cur_score ; /* === Place column back in degree list ========================= */ ASSERT (min_score >= 0) ; ASSERT (min_score <= n_col) ; ASSERT (cur_score >= 0) ; ASSERT (cur_score <= n_col) ; ASSERT (head [cur_score] >= EMPTY) ; next_col = head [cur_score] ; Col [col].shared4.degree_next = next_col ; Col [col].shared3.prev = EMPTY ; if (next_col != EMPTY) { Col [next_col].shared3.prev = col ; } head [cur_score] = col ; /* see if this score is less than current min */ min_score = MIN (min_score, cur_score) ; } #ifndef NDEBUG debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2-k, max_deg) ; #endif /* NDEBUG */ /* === Resurrect the new pivot row ================================== */ if (pivot_row_degree > 0) { /* update pivot row length to reflect any cols that were killed */ /* during super-col detection and mass elimination */ Row [pivot_row].start = pivot_row_start ; Row [pivot_row].length = (Int) (new_rp - &A[pivot_row_start]) ; ASSERT (Row [pivot_row].length > 0) ; Row [pivot_row].shared1.degree = pivot_row_degree ; Row [pivot_row].shared2.mark = 0 ; /* pivot row is no longer dead */ DEBUG1 (("Resurrect Pivot_row %d deg: %d\n", pivot_row, pivot_row_degree)) ; } } /* === All principal columns have now been ordered ====================== */ return (ngarbage) ; } /* ========================================================================== */ /* === order_children ======================================================= */ /* ========================================================================== */ /* The find_ordering routine has ordered all of the principal columns (the representatives of the supercolumns). The non-principal columns have not yet been ordered. This routine orders those columns by walking up the parent tree (a column is a child of the column which absorbed it). The final permutation vector is then placed in p [0 ... n_col-1], with p [0] being the first column, and p [n_col-1] being the last. It doesn't look like it at first glance, but be assured that this routine takes time linear in the number of columns. Although not immediately obvious, the time taken by this routine is O (n_col), that is, linear in the number of columns. Not user-callable. */ PRIVATE void order_children ( /* === Parameters ======================================================= */ Int n_col, /* number of columns of A */ Colamd_Col Col [], /* of size n_col+1 */ Int p [] /* p [0 ... n_col-1] is the column permutation*/ ) { /* === Local variables ================================================== */ Int i ; /* loop counter for all columns */ Int c ; /* column index */ Int parent ; /* index of column's parent */ Int order ; /* column's order */ /* === Order each non-principal column ================================== */ for (i = 0 ; i < n_col ; i++) { /* find an un-ordered non-principal column */ ASSERT (COL_IS_DEAD (i)) ; if (!COL_IS_DEAD_PRINCIPAL (i) && Col [i].shared2.order == EMPTY) { parent = i ; /* once found, find its principal parent */ do { parent = Col [parent].shared1.parent ; } while (!COL_IS_DEAD_PRINCIPAL (parent)) ; /* now, order all un-ordered non-principal columns along path */ /* to this parent. collapse tree at the same time */ c = i ; /* get order of parent */ order = Col [parent].shared2.order ; do { ASSERT (Col [c].shared2.order == EMPTY) ; /* order this column */ Col [c].shared2.order = order++ ; /* collaps tree */ Col [c].shared1.parent = parent ; /* get immediate parent of this column */ c = Col [c].shared1.parent ; /* continue until we hit an ordered column. There are */ /* guarranteed not to be anymore unordered columns */ /* above an ordered column */ } while (Col [c].shared2.order == EMPTY) ; /* re-order the super_col parent to largest order for this group */ Col [parent].shared2.order = order ; } } /* === Generate the permutation ========================================= */ for (c = 0 ; c < n_col ; c++) { p [Col [c].shared2.order] = c ; } } /* ========================================================================== */ /* === detect_super_cols ==================================================== */ /* ========================================================================== */ /* Detects supercolumns by finding matches between columns in the hash buckets. Check amongst columns in the set A [row_start ... row_start + row_length-1]. The columns under consideration are currently *not* in the degree lists, and have already been placed in the hash buckets. The hash bucket for columns whose hash function is equal to h is stored as follows: if head [h] is >= 0, then head [h] contains a degree list, so: head [h] is the first column in degree bucket h. Col [head [h]].headhash gives the first column in hash bucket h. otherwise, the degree list is empty, and: -(head [h] + 2) is the first column in hash bucket h. For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous column" pointer. Col [c].shared3.hash is used instead as the hash number for that column. The value of Col [c].shared4.hash_next is the next column in the same hash bucket. Assuming no, or "few" hash collisions, the time taken by this routine is linear in the sum of the sizes (lengths) of each column whose score has just been computed in the approximate degree computation. Not user-callable. */ PRIVATE void detect_super_cols ( /* === Parameters ======================================================= */ #ifndef NDEBUG /* these two parameters are only needed when debugging is enabled: */ Int n_col, /* number of columns of A */ Colamd_Row Row [], /* of size n_row+1 */ #endif /* NDEBUG */ Colamd_Col Col [], /* of size n_col+1 */ Int A [], /* row indices of A */ Int head [], /* head of degree lists and hash buckets */ Int row_start, /* pointer to set of columns to check */ Int row_length /* number of columns to check */ ) { /* === Local variables ================================================== */ Int hash ; /* hash value for a column */ Int *rp ; /* pointer to a row */ Int c ; /* a column index */ Int super_c ; /* column index of the column to absorb into */ Int *cp1 ; /* column pointer for column super_c */ Int *cp2 ; /* column pointer for column c */ Int length ; /* length of column super_c */ Int prev_c ; /* column preceding c in hash bucket */ Int i ; /* loop counter */ Int *rp_end ; /* pointer to the end of the row */ Int col ; /* a column index in the row to check */ Int head_column ; /* first column in hash bucket or degree list */ Int first_col ; /* first column in hash bucket */ /* === Consider each column in the row ================================== */ rp = &A [row_start] ; rp_end = rp + row_length ; while (rp < rp_end) { col = *rp++ ; if (COL_IS_DEAD (col)) { continue ; } /* get hash number for this column */ hash = Col [col].shared3.hash ; ASSERT (hash <= n_col) ; /* === Get the first column in this hash bucket ===================== */ head_column = head [hash] ; if (head_column > EMPTY) { first_col = Col [head_column].shared3.headhash ; } else { first_col = - (head_column + 2) ; } /* === Consider each column in the hash bucket ====================== */ for (super_c = first_col ; super_c != EMPTY ; super_c = Col [super_c].shared4.hash_next) { ASSERT (COL_IS_ALIVE (super_c)) ; ASSERT (Col [super_c].shared3.hash == hash) ; length = Col [super_c].length ; /* prev_c is the column preceding column c in the hash bucket */ prev_c = super_c ; /* === Compare super_c with all columns after it ================ */ for (c = Col [super_c].shared4.hash_next ; c != EMPTY ; c = Col [c].shared4.hash_next) { ASSERT (c != super_c) ; ASSERT (COL_IS_ALIVE (c)) ; ASSERT (Col [c].shared3.hash == hash) ; /* not identical if lengths or scores are different */ if (Col [c].length != length || Col [c].shared2.score != Col [super_c].shared2.score) { prev_c = c ; continue ; } /* compare the two columns */ cp1 = &A [Col [super_c].start] ; cp2 = &A [Col [c].start] ; for (i = 0 ; i < length ; i++) { /* the columns are "clean" (no dead rows) */ ASSERT (ROW_IS_ALIVE (*cp1)) ; ASSERT (ROW_IS_ALIVE (*cp2)) ; /* row indices will same order for both supercols, */ /* no gather scatter nessasary */ if (*cp1++ != *cp2++) { break ; } } /* the two columns are different if the for-loop "broke" */ if (i != length) { prev_c = c ; continue ; } /* === Got it! two columns are identical =================== */ ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ; Col [super_c].shared1.thickness += Col [c].shared1.thickness ; Col [c].shared1.parent = super_c ; KILL_NON_PRINCIPAL_COL (c) ; /* order c later, in order_children() */ Col [c].shared2.order = EMPTY ; /* remove c from hash bucket */ Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ; } } /* === Empty this hash bucket ======================================= */ if (head_column > EMPTY) { /* corresponding degree list "hash" is not empty */ Col [head_column].shared3.headhash = EMPTY ; } else { /* corresponding degree list "hash" is empty */ head [hash] = EMPTY ; } } } /* ========================================================================== */ /* === garbage_collection =================================================== */ /* ========================================================================== */ /* Defragments and compacts columns and rows in the workspace A. Used when all avaliable memory has been used while performing row merging. Returns the index of the first free position in A, after garbage collection. The time taken by this routine is linear is the size of the array A, which is itself linear in the number of nonzeros in the input matrix. Not user-callable. */ PRIVATE Int garbage_collection /* returns the new value of pfree */ ( /* === Parameters ======================================================= */ Int n_row, /* number of rows */ Int n_col, /* number of columns */ Colamd_Row Row [], /* row info */ Colamd_Col Col [], /* column info */ Int A [], /* A [0 ... Alen-1] holds the matrix */ Int *pfree /* &A [0] ... pfree is in use */ ) { /* === Local variables ================================================== */ Int *psrc ; /* source pointer */ Int *pdest ; /* destination pointer */ Int j ; /* counter */ Int r ; /* a row index */ Int c ; /* a column index */ Int length ; /* length of a row or column */ #ifndef NDEBUG Int debug_rows ; DEBUG2 (("Defrag..\n")) ; for (psrc = &A[0] ; psrc < pfree ; psrc++) ASSERT (*psrc >= 0) ; debug_rows = 0 ; #endif /* NDEBUG */ /* === Defragment the columns =========================================== */ pdest = &A[0] ; for (c = 0 ; c < n_col ; c++) { if (COL_IS_ALIVE (c)) { psrc = &A [Col [c].start] ; /* move and compact the column */ ASSERT (pdest <= psrc) ; Col [c].start = (Int) (pdest - &A [0]) ; length = Col [c].length ; for (j = 0 ; j < length ; j++) { r = *psrc++ ; if (ROW_IS_ALIVE (r)) { *pdest++ = r ; } } Col [c].length = (Int) (pdest - &A [Col [c].start]) ; } } /* === Prepare to defragment the rows =================================== */ for (r = 0 ; r < n_row ; r++) { if (ROW_IS_DEAD (r) || (Row [r].length == 0)) { /* This row is already dead, or is of zero length. Cannot compact * a row of zero length, so kill it. NOTE: in the current version, * there are no zero-length live rows. Kill the row (for the first * time, or again) just to be safe. */ KILL_ROW (r) ; } else { /* save first column index in Row [r].shared2.first_column */ psrc = &A [Row [r].start] ; Row [r].shared2.first_column = *psrc ; ASSERT (ROW_IS_ALIVE (r)) ; /* flag the start of the row with the one's complement of row */ *psrc = ONES_COMPLEMENT (r) ; #ifndef NDEBUG debug_rows++ ; #endif /* NDEBUG */ } } /* === Defragment the rows ============================================== */ psrc = pdest ; while (psrc < pfree) { /* find a negative number ... the start of a row */ if (*psrc++ < 0) { psrc-- ; /* get the row index */ r = ONES_COMPLEMENT (*psrc) ; ASSERT (r >= 0 && r < n_row) ; /* restore first column index */ *psrc = Row [r].shared2.first_column ; ASSERT (ROW_IS_ALIVE (r)) ; ASSERT (Row [r].length > 0) ; /* move and compact the row */ ASSERT (pdest <= psrc) ; Row [r].start = (Int) (pdest - &A [0]) ; length = Row [r].length ; for (j = 0 ; j < length ; j++) { c = *psrc++ ; if (COL_IS_ALIVE (c)) { *pdest++ = c ; } } Row [r].length = (Int) (pdest - &A [Row [r].start]) ; ASSERT (Row [r].length > 0) ; #ifndef NDEBUG debug_rows-- ; #endif /* NDEBUG */ } } /* ensure we found all the rows */ ASSERT (debug_rows == 0) ; /* === Return the new value of pfree ==================================== */ return ((Int) (pdest - &A [0])) ; } /* ========================================================================== */ /* === clear_mark =========================================================== */ /* ========================================================================== */ /* Clears the Row [].shared2.mark array, and returns the new tag_mark. Return value is the new tag_mark. Not user-callable. */ PRIVATE Int clear_mark /* return the new value for tag_mark */ ( /* === Parameters ======================================================= */ Int tag_mark, /* new value of tag_mark */ Int max_mark, /* max allowed value of tag_mark */ Int n_row, /* number of rows in A */ Colamd_Row Row [] /* Row [0 ... n_row-1].shared2.mark is set to zero */ ) { /* === Local variables ================================================== */ Int r ; if (tag_mark <= 0 || tag_mark >= max_mark) { for (r = 0 ; r < n_row ; r++) { if (ROW_IS_ALIVE (r)) { Row [r].shared2.mark = 0 ; } } tag_mark = 1 ; } return (tag_mark) ; } /* ========================================================================== */ /* === print_report ========================================================= */ /* ========================================================================== */ PRIVATE void print_report ( char *method, Int stats [COLAMD_STATS] ) { Int i1, i2, i3 ; PRINTF (("\n%s version %d.%d, %s: ", method, COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE)) ; if (!stats) { PRINTF (("No statistics available.\n")) ; return ; } i1 = stats [COLAMD_INFO1] ; i2 = stats [COLAMD_INFO2] ; i3 = stats [COLAMD_INFO3] ; if (stats [COLAMD_STATUS] >= 0) { PRINTF (("OK. ")) ; } else { PRINTF (("ERROR. ")) ; } switch (stats [COLAMD_STATUS]) { case COLAMD_OK_BUT_JUMBLED: PRINTF(("Matrix has unsorted or duplicate row indices.\n")) ; PRINTF(("%s: number of duplicate or out-of-order row indices: %d\n", method, i3)) ; PRINTF(("%s: last seen duplicate or out-of-order row index: %d\n", method, INDEX (i2))) ; PRINTF(("%s: last seen in column: %d", method, INDEX (i1))) ; /* no break - fall through to next case instead */ case COLAMD_OK: PRINTF(("\n")) ; PRINTF(("%s: number of dense or empty rows ignored: %d\n", method, stats [COLAMD_DENSE_ROW])) ; PRINTF(("%s: number of dense or empty columns ignored: %d\n", method, stats [COLAMD_DENSE_COL])) ; PRINTF(("%s: number of garbage collections performed: %d\n", method, stats [COLAMD_DEFRAG_COUNT])) ; break ; case COLAMD_ERROR_A_not_present: PRINTF(("Array A (row indices of matrix) not present.\n")) ; break ; case COLAMD_ERROR_p_not_present: PRINTF(("Array p (column pointers for matrix) not present.\n")) ; break ; case COLAMD_ERROR_nrow_negative: PRINTF(("Invalid number of rows (%d).\n", i1)) ; break ; case COLAMD_ERROR_ncol_negative: PRINTF(("Invalid number of columns (%d).\n", i1)) ; break ; case COLAMD_ERROR_nnz_negative: PRINTF(("Invalid number of nonzero entries (%d).\n", i1)) ; break ; case COLAMD_ERROR_p0_nonzero: PRINTF(("Invalid column pointer, p [0] = %d, must be zero.\n", i1)); break ; case COLAMD_ERROR_A_too_small: PRINTF(("Array A too small.\n")) ; PRINTF((" Need Alen >= %d, but given only Alen = %d.\n", i1, i2)) ; break ; case COLAMD_ERROR_col_length_negative: PRINTF (("Column %d has a negative number of nonzero entries (%d).\n", INDEX (i1), i2)) ; break ; case COLAMD_ERROR_row_index_out_of_bounds: PRINTF (("Row index (row %d) out of bounds (%d to %d) in column %d.\n", INDEX (i2), INDEX (0), INDEX (i3-1), INDEX (i1))) ; break ; case COLAMD_ERROR_out_of_memory: PRINTF(("Out of memory.\n")) ; break ; /* v2.4: internal-error case deleted */ } } /* ========================================================================== */ /* === colamd debugging routines ============================================ */ /* ========================================================================== */ /* When debugging is disabled, the remainder of this file is ignored. */ #ifndef NDEBUG /* ========================================================================== */ /* === debug_structures ===================================================== */ /* ========================================================================== */ /* At this point, all empty rows and columns are dead. All live columns are "clean" (containing no dead rows) and simplicial (no supercolumns yet). Rows may contain dead columns, but all live rows contain at least one live column. */ PRIVATE void debug_structures ( /* === Parameters ======================================================= */ Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [], Int n_col2 ) { /* === Local variables ================================================== */ Int i ; Int c ; Int *cp ; Int *cp_end ; Int len ; Int score ; Int r ; Int *rp ; Int *rp_end ; Int deg ; /* === Check A, Row, and Col ============================================ */ for (c = 0 ; c < n_col ; c++) { if (COL_IS_ALIVE (c)) { len = Col [c].length ; score = Col [c].shared2.score ; DEBUG4 (("initial live col %5d %5d %5d\n", c, len, score)) ; ASSERT (len > 0) ; ASSERT (score >= 0) ; ASSERT (Col [c].shared1.thickness == 1) ; cp = &A [Col [c].start] ; cp_end = cp + len ; while (cp < cp_end) { r = *cp++ ; ASSERT (ROW_IS_ALIVE (r)) ; } } else { i = Col [c].shared2.order ; ASSERT (i >= n_col2 && i < n_col) ; } } for (r = 0 ; r < n_row ; r++) { if (ROW_IS_ALIVE (r)) { i = 0 ; len = Row [r].length ; deg = Row [r].shared1.degree ; ASSERT (len > 0) ; ASSERT (deg > 0) ; rp = &A [Row [r].start] ; rp_end = rp + len ; while (rp < rp_end) { c = *rp++ ; if (COL_IS_ALIVE (c)) { i++ ; } } ASSERT (i > 0) ; } } } /* ========================================================================== */ /* === debug_deg_lists ====================================================== */ /* ========================================================================== */ /* Prints the contents of the degree lists. Counts the number of columns in the degree list and compares it to the total it should have. Also checks the row degrees. */ PRIVATE void debug_deg_lists ( /* === Parameters ======================================================= */ Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int head [], Int min_score, Int should, Int max_deg ) { /* === Local variables ================================================== */ Int deg ; Int col ; Int have ; Int row ; /* === Check the degree lists =========================================== */ if (n_col > 10000 && colamd_debug <= 0) { return ; } have = 0 ; DEBUG4 (("Degree lists: %d\n", min_score)) ; for (deg = 0 ; deg <= n_col ; deg++) { col = head [deg] ; if (col == EMPTY) { continue ; } DEBUG4 (("%d:", deg)) ; while (col != EMPTY) { DEBUG4 ((" %d", col)) ; have += Col [col].shared1.thickness ; ASSERT (COL_IS_ALIVE (col)) ; col = Col [col].shared4.degree_next ; } DEBUG4 (("\n")) ; } DEBUG4 (("should %d have %d\n", should, have)) ; ASSERT (should == have) ; /* === Check the row degrees ============================================ */ if (n_row > 10000 && colamd_debug <= 0) { return ; } for (row = 0 ; row < n_row ; row++) { if (ROW_IS_ALIVE (row)) { ASSERT (Row [row].shared1.degree <= max_deg) ; } } } /* ========================================================================== */ /* === debug_mark =========================================================== */ /* ========================================================================== */ /* Ensures that the tag_mark is less that the maximum and also ensures that each entry in the mark array is less than the tag mark. */ PRIVATE void debug_mark ( /* === Parameters ======================================================= */ Int n_row, Colamd_Row Row [], Int tag_mark, Int max_mark ) { /* === Local variables ================================================== */ Int r ; /* === Check the Row marks ============================================== */ ASSERT (tag_mark > 0 && tag_mark <= max_mark) ; if (n_row > 10000 && colamd_debug <= 0) { return ; } for (r = 0 ; r < n_row ; r++) { ASSERT (Row [r].shared2.mark < tag_mark) ; } } /* ========================================================================== */ /* === debug_matrix ========================================================= */ /* ========================================================================== */ /* Prints out the contents of the columns and the rows. */ PRIVATE void debug_matrix ( /* === Parameters ======================================================= */ Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [] ) { /* === Local variables ================================================== */ Int r ; Int c ; Int *rp ; Int *rp_end ; Int *cp ; Int *cp_end ; /* === Dump the rows and columns of the matrix ========================== */ if (colamd_debug < 3) { return ; } DEBUG3 (("DUMP MATRIX:\n")) ; for (r = 0 ; r < n_row ; r++) { DEBUG3 (("Row %d alive? %d\n", r, ROW_IS_ALIVE (r))) ; if (ROW_IS_DEAD (r)) { continue ; } DEBUG3 (("start %d length %d degree %d\n", Row [r].start, Row [r].length, Row [r].shared1.degree)) ; rp = &A [Row [r].start] ; rp_end = rp + Row [r].length ; while (rp < rp_end) { c = *rp++ ; DEBUG4 ((" %d col %d\n", COL_IS_ALIVE (c), c)) ; } } for (c = 0 ; c < n_col ; c++) { DEBUG3 (("Col %d alive? %d\n", c, COL_IS_ALIVE (c))) ; if (COL_IS_DEAD (c)) { continue ; } DEBUG3 (("start %d length %d shared1 %d shared2 %d\n", Col [c].start, Col [c].length, Col [c].shared1.thickness, Col [c].shared2.score)) ; cp = &A [Col [c].start] ; cp_end = cp + Col [c].length ; while (cp < cp_end) { r = *cp++ ; DEBUG4 ((" %d row %d\n", ROW_IS_ALIVE (r), r)) ; } } } PRIVATE void colamd_get_debug ( char *method ) { FILE *f ; colamd_debug = 0 ; /* no debug printing */ f = fopen ("debug", "r") ; if (f == (FILE *) NULL) { colamd_debug = 0 ; } else { fscanf (f, "%d", &colamd_debug) ; fclose (f) ; } DEBUG0 (("%s: debug version, D = %d (THIS WILL BE SLOW!)\n", method, colamd_debug)) ; } #endif /* NDEBUG */ Rglpk/src/GLPK/colamd/COPYING0000644000176000001440000006362512175147600015216 0ustar ripleyusers GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! Rglpk/src/GLPK/colamd/colamd.h0000644000176000001440000000411112245352174015556 0ustar ripleyusers/* colamd.h */ /* Written by Andrew Makhorin . */ #ifndef COLAMD_H #define COLAMD_H #define _GLPSTD_STDIO #include "env.h" #define COLAMD_DATE "Nov 1, 2007" #define COLAMD_VERSION_CODE(main, sub) ((main) * 1000 + (sub)) #define COLAMD_MAIN_VERSION 2 #define COLAMD_SUB_VERSION 7 #define COLAMD_SUBSUB_VERSION 1 #define COLAMD_VERSION \ COLAMD_VERSION_CODE(COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION) #define COLAMD_KNOBS 20 #define COLAMD_STATS 20 #define COLAMD_DENSE_ROW 0 #define COLAMD_DENSE_COL 1 #define COLAMD_AGGRESSIVE 2 #define COLAMD_DEFRAG_COUNT 2 #define COLAMD_STATUS 3 #define COLAMD_INFO1 4 #define COLAMD_INFO2 5 #define COLAMD_INFO3 6 #define COLAMD_OK (0) #define COLAMD_OK_BUT_JUMBLED (1) #define COLAMD_ERROR_A_not_present (-1) #define COLAMD_ERROR_p_not_present (-2) #define COLAMD_ERROR_nrow_negative (-3) #define COLAMD_ERROR_ncol_negative (-4) #define COLAMD_ERROR_nnz_negative (-5) #define COLAMD_ERROR_p0_nonzero (-6) #define COLAMD_ERROR_A_too_small (-7) #define COLAMD_ERROR_col_length_negative (-8) #define COLAMD_ERROR_row_index_out_of_bounds (-9) #define COLAMD_ERROR_out_of_memory (-10) #define COLAMD_ERROR_internal_error (-999) #define colamd_recommended _glp_colamd_recommended size_t colamd_recommended(int nnz, int n_row, int n_col); #define colamd_set_defaults _glp_colamd_set_defaults void colamd_set_defaults(double knobs [COLAMD_KNOBS]); #define colamd _glp_colamd int colamd(int n_row, int n_col, int Alen, int A[], int p[], double knobs[COLAMD_KNOBS], int stats[COLAMD_STATS]); #define symamd _glp_symamd int symamd(int n, int A[], int p[], int perm[], double knobs[COLAMD_KNOBS], int stats[COLAMD_STATS], void *(*allocate)(size_t, size_t), void(*release)(void *)); #define colamd_report _glp_colamd_report void colamd_report(int stats[COLAMD_STATS]); #define symamd_report _glp_symamd_report void symamd_report(int stats[COLAMD_STATS]); #define colamd_printf xprintf #endif /* eof */ Rglpk/src/GLPK/colamd/README0000644000176000001440000001027412175147600015033 0ustar ripleyusersNOTE: Files in this subdirectory are NOT part of the GLPK package, but are used with GLPK. The original code was modified according to GLPK requirements by Andrew Makhorin . ************************************************************************ COLAMD/SYMAMD Version 2.7, Copyright (C) 1998-2007, Timothy A. Davis, All Rights Reserved. Description: colamd: an approximate minimum degree column ordering algorithm, for LU factorization of symmetric or unsymmetric matrices, QR factorization, least squares, interior point methods for linear programming problems, and other related problems. symamd: an approximate minimum degree ordering algorithm for Cholesky factorization of symmetric matrices. Purpose: Colamd computes a permutation Q such that the Cholesky factorization of (AQ)'(AQ) has less fill-in and requires fewer floating point operations than A'A. This also provides a good ordering for sparse partial pivoting methods, P(AQ) = LU, where Q is computed prior to numerical factorization, and P is computed during numerical factorization via conventional partial pivoting with row interchanges. Colamd is the column ordering method used in SuperLU, part of the ScaLAPACK library. It is also available as built-in function in MATLAB Version 6, available from MathWorks, Inc. (http://www.mathworks.com). This routine can be used in place of colmmd in MATLAB. Symamd computes a permutation P of a symmetric matrix A such that the Cholesky factorization of PAP' has less fill-in and requires fewer floating point operations than A. Symamd constructs a matrix M such that M'M has the same nonzero pattern of A, and then orders the columns of M using colmmd. The column ordering of M is then returned as the row and column ordering P of A. Authors: The authors of the code itself are Stefan I. Larimore and Timothy A. Davis (davis at cise.ufl.edu), University of Florida. The algorithm was developed in collaboration with John Gilbert, Xerox PARC, and Esmond Ng, Oak Ridge National Laboratory. Acknowledgements: This work was supported by the National Science Foundation, under grants DMS-9504974 and DMS-9803599. License: This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. Permission is hereby granted to use or copy this program under the terms of the GNU LGPL, provided that the Copyright, this License, and the Availability of the original version is retained on all copies. User documentation of any code that uses this code or any modified version of this code must cite the Copyright, this License, the Availability note, and "Used by permission." Permission to modify the code and to distribute modified code is granted, provided the Copyright, this License, and the Availability note are retained, and a notice that the code was modified is included. COLAMD is also available under alternate licenses, contact T. Davis for details. Availability: The colamd/symamd library is available at: http://www.cise.ufl.edu/research/sparse/colamd/ References: T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column minimum degree ordering algorithm, ACM Transactions on Mathematical Software, vol. 30, no. 3., pp. 353-376, 2004. T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD, an approximate column minimum degree ordering algorithm, ACM Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380, 2004. Rglpk/src/GLPK/mc21a.h0000644000176000001440000000243012245352174013765 0ustar ripleyusers/* mc21a.h (permutations for zero-free diagonal) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2009, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef MC21A_H #define MC21A_H #define mc21a _glp_mc21a int mc21a(int n, const int icn[], const int ip[], const int lenr[], int iperm[], int pr[], int arp[], int cv[], int out[]); /* permutations for zero-free diagonal */ #endif /* eof */ Rglpk/src/GLPK/glpapi19.c0000644000176000001440000001072312245352174014507 0ustar ripleyusers/* glpapi19.c (driver to MiniSat solver) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpapi.h" #include "minisat/minisat.h" int glp_minisat1(glp_prob *P) { /* solve CNF-SAT problem with MiniSat solver */ solver *s; GLPAIJ *aij; int i, j, len, ret, *ind; double sum; /* check problem object */ if (P == NULL || P->magic != GLP_PROB_MAGIC) xerror("glp_minisat1: P = %p; invalid problem object\n", P); if (P->tree != NULL) xerror("glp_minisat1: operation not allowed\n"); /* integer solution is currently undefined */ P->mip_stat = GLP_UNDEF; P->mip_obj = 0.0; /* check that problem object encodes CNF-SAT instance */ if (glp_check_cnfsat(P) != 0) { xprintf("glp_minisat1: problem object does not encode CNF-SAT " "instance\n"); ret = GLP_EDATA; goto done; } /* solve CNF-SAT problem */ xprintf("Solving CNF-SAT problem...\n"); xprintf("Instance has %d variable%s, %d clause%s, and %d literal%" "s\n", P->n, P->n == 1 ? "" : "s", P->m, P->m == 1 ? "" : "s", P->nnz, P->nnz == 1 ? "" : "s"); /* if CNF-SAT has no clauses, it is satisfiable */ if (P->m == 0) { P->mip_stat = GLP_OPT; for (j = 1; j <= P->n; j++) P->col[j]->mipx = 0.0; goto fini; } /* if CNF-SAT has an empty clause, it is unsatisfiable */ for (i = 1; i <= P->m; i++) { if (P->row[i]->ptr == NULL) { P->mip_stat = GLP_NOFEAS; goto fini; } } /* prepare input data for the solver */ s = solver_new(); solver_setnvars(s, P->n); ind = xcalloc(1+P->n, sizeof(int)); for (i = 1; i <= P->m; i++) { len = 0; for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next) { ind[++len] = toLit(aij->col->j-1); if (aij->val < 0.0) ind[len] = lit_neg(ind[len]); } xassert(len > 0); xassert(solver_addclause(s, &ind[1], &ind[1+len])); } xfree(ind); /* call the solver */ s->verbosity = 1; if (solver_solve(s, 0, 0)) { /* instance is reported as satisfiable */ P->mip_stat = GLP_OPT; /* copy solution to the problem object */ xassert(s->model.size == P->n); for (j = 1; j <= P->n; j++) { P->col[j]->mipx = s->model.ptr[j-1] == l_True ? 1.0 : 0.0; } /* compute row values */ for (i = 1; i <= P->m; i++) { sum = 0; for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next) sum += aij->val * aij->col->mipx; P->row[i]->mipx = sum; } /* check integer feasibility */ for (i = 1; i <= P->m; i++) { if (P->row[i]->mipx < P->row[i]->lb) { /* solution is wrong */ P->mip_stat = GLP_UNDEF; break; } } } else { /* instance is reported as unsatisfiable */ P->mip_stat = GLP_NOFEAS; } solver_delete(s); fini: /* report the instance status */ if (P->mip_stat == GLP_OPT) { xprintf("SATISFIABLE\n"); ret = 0; } else if (P->mip_stat == GLP_NOFEAS) { xprintf("UNSATISFIABLE\n"); ret = 0; } else { xprintf("glp_minisat1: solver failed\n"); ret = GLP_EFAIL; } done: return ret; } /* eof */ Rglpk/src/GLPK/glpssx02.c0000644000176000001440000004071412245352174014546 0ustar ripleyusers/* glpssx02.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #include "glpssx.h" static void show_progress(SSX *ssx, int phase) { /* this auxiliary routine displays information about progress of the search */ int i, def = 0; for (i = 1; i <= ssx->m; i++) if (ssx->type[ssx->Q_col[i]] == SSX_FX) def++; xprintf("%s%6d: %s = %22.15g (%d)\n", phase == 1 ? " " : "*", ssx->it_cnt, phase == 1 ? "infsum" : "objval", mpq_get_d(ssx->bbar[0]), def); #if 0 ssx->tm_lag = utime(); #else ssx->tm_lag = xtime(); #endif return; } /*---------------------------------------------------------------------- // ssx_phase_I - find primal feasible solution. // // This routine implements phase I of the primal simplex method. // // On exit the routine returns one of the following codes: // // 0 - feasible solution found; // 1 - problem has no feasible solution; // 2 - iterations limit exceeded; // 3 - time limit exceeded. ----------------------------------------------------------------------*/ int ssx_phase_I(SSX *ssx) { int m = ssx->m; int n = ssx->n; int *type = ssx->type; mpq_t *lb = ssx->lb; mpq_t *ub = ssx->ub; mpq_t *coef = ssx->coef; int *A_ptr = ssx->A_ptr; int *A_ind = ssx->A_ind; mpq_t *A_val = ssx->A_val; int *Q_col = ssx->Q_col; mpq_t *bbar = ssx->bbar; mpq_t *pi = ssx->pi; mpq_t *cbar = ssx->cbar; int *orig_type, orig_dir; mpq_t *orig_lb, *orig_ub, *orig_coef; int i, k, ret; /* save components of the original LP problem, which are changed by the routine */ orig_type = xcalloc(1+m+n, sizeof(int)); orig_lb = xcalloc(1+m+n, sizeof(mpq_t)); orig_ub = xcalloc(1+m+n, sizeof(mpq_t)); orig_coef = xcalloc(1+m+n, sizeof(mpq_t)); for (k = 1; k <= m+n; k++) { orig_type[k] = type[k]; mpq_init(orig_lb[k]); mpq_set(orig_lb[k], lb[k]); mpq_init(orig_ub[k]); mpq_set(orig_ub[k], ub[k]); } orig_dir = ssx->dir; for (k = 0; k <= m+n; k++) { mpq_init(orig_coef[k]); mpq_set(orig_coef[k], coef[k]); } /* build an artificial basic solution, which is primal feasible, and also build an auxiliary objective function to minimize the sum of infeasibilities for the original problem */ ssx->dir = SSX_MIN; for (k = 0; k <= m+n; k++) mpq_set_si(coef[k], 0, 1); mpq_set_si(bbar[0], 0, 1); for (i = 1; i <= m; i++) { int t; k = Q_col[i]; /* x[k] = xB[i] */ t = type[k]; if (t == SSX_LO || t == SSX_DB || t == SSX_FX) { /* in the original problem x[k] has lower bound */ if (mpq_cmp(bbar[i], lb[k]) < 0) { /* which is violated */ type[k] = SSX_UP; mpq_set(ub[k], lb[k]); mpq_set_si(lb[k], 0, 1); mpq_set_si(coef[k], -1, 1); mpq_add(bbar[0], bbar[0], ub[k]); mpq_sub(bbar[0], bbar[0], bbar[i]); } } if (t == SSX_UP || t == SSX_DB || t == SSX_FX) { /* in the original problem x[k] has upper bound */ if (mpq_cmp(bbar[i], ub[k]) > 0) { /* which is violated */ type[k] = SSX_LO; mpq_set(lb[k], ub[k]); mpq_set_si(ub[k], 0, 1); mpq_set_si(coef[k], +1, 1); mpq_add(bbar[0], bbar[0], bbar[i]); mpq_sub(bbar[0], bbar[0], lb[k]); } } } /* now the initial basic solution should be primal feasible due to changes of bounds of some basic variables, which turned to implicit artifical variables */ /* compute simplex multipliers and reduced costs */ ssx_eval_pi(ssx); ssx_eval_cbar(ssx); /* display initial progress of the search */ show_progress(ssx, 1); /* main loop starts here */ for (;;) { /* display current progress of the search */ #if 0 if (utime() - ssx->tm_lag >= ssx->out_frq - 0.001) #else if (xdifftime(xtime(), ssx->tm_lag) >= ssx->out_frq - 0.001) #endif show_progress(ssx, 1); /* we do not need to wait until all artificial variables have left the basis */ if (mpq_sgn(bbar[0]) == 0) { /* the sum of infeasibilities is zero, therefore the current solution is primal feasible for the original problem */ ret = 0; break; } /* check if the iterations limit has been exhausted */ if (ssx->it_lim == 0) { ret = 2; break; } /* check if the time limit has been exhausted */ #if 0 if (ssx->tm_lim >= 0.0 && ssx->tm_lim <= utime() - ssx->tm_beg) #else if (ssx->tm_lim >= 0.0 && ssx->tm_lim <= xdifftime(xtime(), ssx->tm_beg)) #endif { ret = 3; break; } /* choose non-basic variable xN[q] */ ssx_chuzc(ssx); /* if xN[q] cannot be chosen, the sum of infeasibilities is minimal but non-zero; therefore the original problem has no primal feasible solution */ if (ssx->q == 0) { ret = 1; break; } /* compute q-th column of the simplex table */ ssx_eval_col(ssx); /* choose basic variable xB[p] */ ssx_chuzr(ssx); /* the sum of infeasibilities cannot be negative, therefore the auxiliary lp problem cannot have unbounded solution */ xassert(ssx->p != 0); /* update values of basic variables */ ssx_update_bbar(ssx); if (ssx->p > 0) { /* compute p-th row of the inverse inv(B) */ ssx_eval_rho(ssx); /* compute p-th row of the simplex table */ ssx_eval_row(ssx); xassert(mpq_cmp(ssx->aq[ssx->p], ssx->ap[ssx->q]) == 0); /* update simplex multipliers */ ssx_update_pi(ssx); /* update reduced costs of non-basic variables */ ssx_update_cbar(ssx); } /* xB[p] is leaving the basis; if it is implicit artificial variable, the corresponding residual vanishes; therefore bounds of this variable should be restored to the original values */ if (ssx->p > 0) { k = Q_col[ssx->p]; /* x[k] = xB[p] */ if (type[k] != orig_type[k]) { /* x[k] is implicit artificial variable */ type[k] = orig_type[k]; mpq_set(lb[k], orig_lb[k]); mpq_set(ub[k], orig_ub[k]); xassert(ssx->p_stat == SSX_NL || ssx->p_stat == SSX_NU); ssx->p_stat = (ssx->p_stat == SSX_NL ? SSX_NU : SSX_NL); if (type[k] == SSX_FX) ssx->p_stat = SSX_NS; /* nullify the objective coefficient at x[k] */ mpq_set_si(coef[k], 0, 1); /* since coef[k] has been changed, we need to compute new reduced cost of x[k], which it will have in the adjacent basis */ /* the formula d[j] = cN[j] - pi' * N[j] is used (note that the vector pi is not changed, because it depends on objective coefficients at basic variables, but in the adjacent basis, for which the vector pi has been just recomputed, x[k] is non-basic) */ if (k <= m) { /* x[k] is auxiliary variable */ mpq_neg(cbar[ssx->q], pi[k]); } else { /* x[k] is structural variable */ int ptr; mpq_t temp; mpq_init(temp); mpq_set_si(cbar[ssx->q], 0, 1); for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++) { mpq_mul(temp, pi[A_ind[ptr]], A_val[ptr]); mpq_add(cbar[ssx->q], cbar[ssx->q], temp); } mpq_clear(temp); } } } /* jump to the adjacent vertex of the polyhedron */ ssx_change_basis(ssx); /* one simplex iteration has been performed */ if (ssx->it_lim > 0) ssx->it_lim--; ssx->it_cnt++; } /* display final progress of the search */ show_progress(ssx, 1); /* restore components of the original problem, which were changed by the routine */ for (k = 1; k <= m+n; k++) { type[k] = orig_type[k]; mpq_set(lb[k], orig_lb[k]); mpq_clear(orig_lb[k]); mpq_set(ub[k], orig_ub[k]); mpq_clear(orig_ub[k]); } ssx->dir = orig_dir; for (k = 0; k <= m+n; k++) { mpq_set(coef[k], orig_coef[k]); mpq_clear(orig_coef[k]); } xfree(orig_type); xfree(orig_lb); xfree(orig_ub); xfree(orig_coef); /* return to the calling program */ return ret; } /*---------------------------------------------------------------------- // ssx_phase_II - find optimal solution. // // This routine implements phase II of the primal simplex method. // // On exit the routine returns one of the following codes: // // 0 - optimal solution found; // 1 - problem has unbounded solution; // 2 - iterations limit exceeded; // 3 - time limit exceeded. ----------------------------------------------------------------------*/ int ssx_phase_II(SSX *ssx) { int ret; /* display initial progress of the search */ show_progress(ssx, 2); /* main loop starts here */ for (;;) { /* display current progress of the search */ #if 0 if (utime() - ssx->tm_lag >= ssx->out_frq - 0.001) #else if (xdifftime(xtime(), ssx->tm_lag) >= ssx->out_frq - 0.001) #endif show_progress(ssx, 2); /* check if the iterations limit has been exhausted */ if (ssx->it_lim == 0) { ret = 2; break; } /* check if the time limit has been exhausted */ #if 0 if (ssx->tm_lim >= 0.0 && ssx->tm_lim <= utime() - ssx->tm_beg) #else if (ssx->tm_lim >= 0.0 && ssx->tm_lim <= xdifftime(xtime(), ssx->tm_beg)) #endif { ret = 3; break; } /* choose non-basic variable xN[q] */ ssx_chuzc(ssx); /* if xN[q] cannot be chosen, the current basic solution is dual feasible and therefore optimal */ if (ssx->q == 0) { ret = 0; break; } /* compute q-th column of the simplex table */ ssx_eval_col(ssx); /* choose basic variable xB[p] */ ssx_chuzr(ssx); /* if xB[p] cannot be chosen, the problem has no dual feasible solution (i.e. unbounded) */ if (ssx->p == 0) { ret = 1; break; } /* update values of basic variables */ ssx_update_bbar(ssx); if (ssx->p > 0) { /* compute p-th row of the inverse inv(B) */ ssx_eval_rho(ssx); /* compute p-th row of the simplex table */ ssx_eval_row(ssx); xassert(mpq_cmp(ssx->aq[ssx->p], ssx->ap[ssx->q]) == 0); #if 0 /* update simplex multipliers */ ssx_update_pi(ssx); #endif /* update reduced costs of non-basic variables */ ssx_update_cbar(ssx); } /* jump to the adjacent vertex of the polyhedron */ ssx_change_basis(ssx); /* one simplex iteration has been performed */ if (ssx->it_lim > 0) ssx->it_lim--; ssx->it_cnt++; } /* display final progress of the search */ show_progress(ssx, 2); /* return to the calling program */ return ret; } /*---------------------------------------------------------------------- // ssx_driver - base driver to exact simplex method. // // This routine is a base driver to a version of the primal simplex // method using exact (bignum) arithmetic. // // On exit the routine returns one of the following codes: // // 0 - optimal solution found; // 1 - problem has no feasible solution; // 2 - problem has unbounded solution; // 3 - iterations limit exceeded (phase I); // 4 - iterations limit exceeded (phase II); // 5 - time limit exceeded (phase I); // 6 - time limit exceeded (phase II); // 7 - initial basis matrix is exactly singular. ----------------------------------------------------------------------*/ int ssx_driver(SSX *ssx) { int m = ssx->m; int *type = ssx->type; mpq_t *lb = ssx->lb; mpq_t *ub = ssx->ub; int *Q_col = ssx->Q_col; mpq_t *bbar = ssx->bbar; int i, k, ret; ssx->tm_beg = xtime(); /* factorize the initial basis matrix */ if (ssx_factorize(ssx)) { xprintf("Initial basis matrix is singular\n"); ret = 7; goto done; } /* compute values of basic variables */ ssx_eval_bbar(ssx); /* check if the initial basic solution is primal feasible */ for (i = 1; i <= m; i++) { int t; k = Q_col[i]; /* x[k] = xB[i] */ t = type[k]; if (t == SSX_LO || t == SSX_DB || t == SSX_FX) { /* x[k] has lower bound */ if (mpq_cmp(bbar[i], lb[k]) < 0) { /* which is violated */ break; } } if (t == SSX_UP || t == SSX_DB || t == SSX_FX) { /* x[k] has upper bound */ if (mpq_cmp(bbar[i], ub[k]) > 0) { /* which is violated */ break; } } } if (i > m) { /* no basic variable violates its bounds */ ret = 0; goto skip; } /* phase I: find primal feasible solution */ ret = ssx_phase_I(ssx); switch (ret) { case 0: ret = 0; break; case 1: xprintf("PROBLEM HAS NO FEASIBLE SOLUTION\n"); ret = 1; break; case 2: xprintf("ITERATIONS LIMIT EXCEEDED; SEARCH TERMINATED\n"); ret = 3; break; case 3: xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n"); ret = 5; break; default: xassert(ret != ret); } /* compute values of basic variables (actually only the objective value needs to be computed) */ ssx_eval_bbar(ssx); skip: /* compute simplex multipliers */ ssx_eval_pi(ssx); /* compute reduced costs of non-basic variables */ ssx_eval_cbar(ssx); /* if phase I failed, do not start phase II */ if (ret != 0) goto done; /* phase II: find optimal solution */ ret = ssx_phase_II(ssx); switch (ret) { case 0: xprintf("OPTIMAL SOLUTION FOUND\n"); ret = 0; break; case 1: xprintf("PROBLEM HAS UNBOUNDED SOLUTION\n"); ret = 2; break; case 2: xprintf("ITERATIONS LIMIT EXCEEDED; SEARCH TERMINATED\n"); ret = 4; break; case 3: xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n"); ret = 6; break; default: xassert(ret != ret); } done: /* decrease the time limit by the spent amount of time */ if (ssx->tm_lim >= 0.0) #if 0 { ssx->tm_lim -= utime() - ssx->tm_beg; #else { ssx->tm_lim -= xdifftime(xtime(), ssx->tm_beg); #endif if (ssx->tm_lim < 0.0) ssx->tm_lim = 0.0; } return ret; } /* eof */ Rglpk/src/GLPK/glpapi15.c0000644000176000001440000004461712245352174014514 0ustar ripleyusers/* glpapi15.c (basic graph and network routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #if 1 /* 11/VI-2013 */ #include "env2.h" #endif #include "glpapi.h" #include "glpsdf.h" /* CAUTION: DO NOT CHANGE THE LIMITS BELOW */ #define NV_MAX 100000000 /* = 100*10^6 */ /* maximal number of vertices in the graph */ #define NA_MAX 500000000 /* = 500*10^6 */ /* maximal number of arcs in the graph */ /*********************************************************************** * NAME * * glp_create_graph - create graph * * SYNOPSIS * * glp_graph *glp_create_graph(int v_size, int a_size); * * DESCRIPTION * * The routine creates a new graph, which initially is empty, i.e. has * no vertices and arcs. * * The parameter v_size specifies the size of data associated with each * vertex of the graph (0 to 256 bytes). * * The parameter a_size specifies the size of data associated with each * arc of the graph (0 to 256 bytes). * * RETURNS * * The routine returns a pointer to the graph created. */ static void create_graph(glp_graph *G, int v_size, int a_size) { G->pool = dmp_create_pool(); G->name = NULL; G->nv_max = 50; G->nv = G->na = 0; G->v = xcalloc(1+G->nv_max, sizeof(glp_vertex *)); G->index = NULL; G->v_size = v_size; G->a_size = a_size; return; } glp_graph *glp_create_graph(int v_size, int a_size) { glp_graph *G; if (!(0 <= v_size && v_size <= 256)) xerror("glp_create_graph: v_size = %d; invalid size of vertex " "data\n", v_size); if (!(0 <= a_size && a_size <= 256)) xerror("glp_create_graph: a_size = %d; invalid size of arc dat" "a\n", a_size); G = xmalloc(sizeof(glp_graph)); create_graph(G, v_size, a_size); return G; } /*********************************************************************** * NAME * * glp_set_graph_name - assign (change) graph name * * SYNOPSIS * * void glp_set_graph_name(glp_graph *G, const char *name); * * DESCRIPTION * * The routine glp_set_graph_name assigns a symbolic name specified by * the character string name (1 to 255 chars) to the graph. * * If the parameter name is NULL or an empty string, the routine erases * the existing symbolic name of the graph. */ void glp_set_graph_name(glp_graph *G, const char *name) { if (G->name != NULL) { dmp_free_atom(G->pool, G->name, strlen(G->name)+1); G->name = NULL; } if (!(name == NULL || name[0] == '\0')) { int j; for (j = 0; name[j] != '\0'; j++) { if (j == 256) xerror("glp_set_graph_name: graph name too long\n"); if (iscntrl((unsigned char)name[j])) xerror("glp_set_graph_name: graph name contains invalid " "character(s)\n"); } G->name = dmp_get_atom(G->pool, strlen(name)+1); strcpy(G->name, name); } return; } /*********************************************************************** * NAME * * glp_add_vertices - add new vertices to graph * * SYNOPSIS * * int glp_add_vertices(glp_graph *G, int nadd); * * DESCRIPTION * * The routine glp_add_vertices adds nadd vertices to the specified * graph. New vertices are always added to the end of the vertex list, * so ordinal numbers of existing vertices remain unchanged. * * Being added each new vertex is isolated (has no incident arcs). * * RETURNS * * The routine glp_add_vertices returns an ordinal number of the first * new vertex added to the graph. */ int glp_add_vertices(glp_graph *G, int nadd) { int i, nv_new; if (nadd < 1) xerror("glp_add_vertices: nadd = %d; invalid number of vertice" "s\n", nadd); if (nadd > NV_MAX - G->nv) xerror("glp_add_vertices: nadd = %d; too many vertices\n", nadd); /* determine new number of vertices */ nv_new = G->nv + nadd; /* increase the room, if necessary */ if (G->nv_max < nv_new) { glp_vertex **save = G->v; while (G->nv_max < nv_new) { G->nv_max += G->nv_max; xassert(G->nv_max > 0); } G->v = xcalloc(1+G->nv_max, sizeof(glp_vertex *)); memcpy(&G->v[1], &save[1], G->nv * sizeof(glp_vertex *)); xfree(save); } /* add new vertices to the end of the vertex list */ for (i = G->nv+1; i <= nv_new; i++) { glp_vertex *v; G->v[i] = v = dmp_get_atom(G->pool, sizeof(glp_vertex)); v->i = i; v->name = NULL; v->entry = NULL; if (G->v_size == 0) v->data = NULL; else { v->data = dmp_get_atom(G->pool, G->v_size); memset(v->data, 0, G->v_size); } v->temp = NULL; v->in = v->out = NULL; } /* set new number of vertices */ G->nv = nv_new; /* return the ordinal number of the first vertex added */ return nv_new - nadd + 1; } /**********************************************************************/ void glp_set_vertex_name(glp_graph *G, int i, const char *name) { /* assign (change) vertex name */ glp_vertex *v; if (!(1 <= i && i <= G->nv)) xerror("glp_set_vertex_name: i = %d; vertex number out of rang" "e\n", i); v = G->v[i]; if (v->name != NULL) { if (v->entry != NULL) { xassert(G->index != NULL); avl_delete_node(G->index, v->entry); v->entry = NULL; } dmp_free_atom(G->pool, v->name, strlen(v->name)+1); v->name = NULL; } if (!(name == NULL || name[0] == '\0')) { int k; for (k = 0; name[k] != '\0'; k++) { if (k == 256) xerror("glp_set_vertex_name: i = %d; vertex name too lon" "g\n", i); if (iscntrl((unsigned char)name[k])) xerror("glp_set_vertex_name: i = %d; vertex name contain" "s invalid character(s)\n", i); } v->name = dmp_get_atom(G->pool, strlen(name)+1); strcpy(v->name, name); if (G->index != NULL) { xassert(v->entry == NULL); v->entry = avl_insert_node(G->index, v->name); avl_set_node_link(v->entry, v); } } return; } /*********************************************************************** * NAME * * glp_add_arc - add new arc to graph * * SYNOPSIS * * glp_arc *glp_add_arc(glp_graph *G, int i, int j); * * DESCRIPTION * * The routine glp_add_arc adds a new arc to the specified graph. * * The parameters i and j specify the ordinal numbers of, resp., tail * and head vertices of the arc. Note that self-loops and multiple arcs * are allowed. * * RETURNS * * The routine glp_add_arc returns a pointer to the arc added. */ glp_arc *glp_add_arc(glp_graph *G, int i, int j) { glp_arc *a; if (!(1 <= i && i <= G->nv)) xerror("glp_add_arc: i = %d; tail vertex number out of range\n" , i); if (!(1 <= j && j <= G->nv)) xerror("glp_add_arc: j = %d; head vertex number out of range\n" , j); if (G->na == NA_MAX) xerror("glp_add_arc: too many arcs\n"); a = dmp_get_atom(G->pool, sizeof(glp_arc)); a->tail = G->v[i]; a->head = G->v[j]; if (G->a_size == 0) a->data = NULL; else { a->data = dmp_get_atom(G->pool, G->a_size); memset(a->data, 0, G->a_size); } a->temp = NULL; a->t_prev = NULL; a->t_next = G->v[i]->out; if (a->t_next != NULL) a->t_next->t_prev = a; a->h_prev = NULL; a->h_next = G->v[j]->in; if (a->h_next != NULL) a->h_next->h_prev = a; G->v[i]->out = G->v[j]->in = a; G->na++; return a; } /*********************************************************************** * NAME * * glp_del_vertices - delete vertices from graph * * SYNOPSIS * * void glp_del_vertices(glp_graph *G, int ndel, const int num[]); * * DESCRIPTION * * The routine glp_del_vertices deletes vertices along with all * incident arcs from the specified graph. Ordinal numbers of vertices * to be deleted should be placed in locations num[1], ..., num[ndel], * ndel > 0. * * Note that deleting vertices involves changing ordinal numbers of * other vertices remaining in the graph. New ordinal numbers of the * remaining vertices are assigned under the assumption that the * original order of vertices is not changed. */ void glp_del_vertices(glp_graph *G, int ndel, const int num[]) { glp_vertex *v; int i, k, nv_new; /* scan the list of vertices to be deleted */ if (!(1 <= ndel && ndel <= G->nv)) xerror("glp_del_vertices: ndel = %d; invalid number of vertice" "s\n", ndel); for (k = 1; k <= ndel; k++) { /* take the number of vertex to be deleted */ i = num[k]; /* obtain pointer to i-th vertex */ if (!(1 <= i && i <= G->nv)) xerror("glp_del_vertices: num[%d] = %d; vertex number out o" "f range\n", k, i); v = G->v[i]; /* check that the vertex is not marked yet */ if (v->i == 0) xerror("glp_del_vertices: num[%d] = %d; duplicate vertex nu" "mbers not allowed\n", k, i); /* erase symbolic name assigned to the vertex */ glp_set_vertex_name(G, i, NULL); xassert(v->name == NULL); xassert(v->entry == NULL); /* free vertex data, if allocated */ if (v->data != NULL) dmp_free_atom(G->pool, v->data, G->v_size); /* delete all incoming arcs */ while (v->in != NULL) glp_del_arc(G, v->in); /* delete all outgoing arcs */ while (v->out != NULL) glp_del_arc(G, v->out); /* mark the vertex to be deleted */ v->i = 0; } /* delete all marked vertices from the vertex list */ nv_new = 0; for (i = 1; i <= G->nv; i++) { /* obtain pointer to i-th vertex */ v = G->v[i]; /* check if the vertex is marked */ if (v->i == 0) { /* it is marked, delete it */ dmp_free_atom(G->pool, v, sizeof(glp_vertex)); } else { /* it is not marked, keep it */ v->i = ++nv_new; G->v[v->i] = v; } } /* set new number of vertices in the graph */ G->nv = nv_new; return; } /*********************************************************************** * NAME * * glp_del_arc - delete arc from graph * * SYNOPSIS * * void glp_del_arc(glp_graph *G, glp_arc *a); * * DESCRIPTION * * The routine glp_del_arc deletes an arc from the specified graph. * The arc to be deleted must exist. */ void glp_del_arc(glp_graph *G, glp_arc *a) { /* some sanity checks */ xassert(G->na > 0); xassert(1 <= a->tail->i && a->tail->i <= G->nv); xassert(a->tail == G->v[a->tail->i]); xassert(1 <= a->head->i && a->head->i <= G->nv); xassert(a->head == G->v[a->head->i]); /* remove the arc from the list of incoming arcs */ if (a->h_prev == NULL) a->head->in = a->h_next; else a->h_prev->h_next = a->h_next; if (a->h_next == NULL) ; else a->h_next->h_prev = a->h_prev; /* remove the arc from the list of outgoing arcs */ if (a->t_prev == NULL) a->tail->out = a->t_next; else a->t_prev->t_next = a->t_next; if (a->t_next == NULL) ; else a->t_next->t_prev = a->t_prev; /* free arc data, if allocated */ if (a->data != NULL) dmp_free_atom(G->pool, a->data, G->a_size); /* delete the arc from the graph */ dmp_free_atom(G->pool, a, sizeof(glp_arc)); G->na--; return; } /*********************************************************************** * NAME * * glp_erase_graph - erase graph content * * SYNOPSIS * * void glp_erase_graph(glp_graph *G, int v_size, int a_size); * * DESCRIPTION * * The routine glp_erase_graph erases the content of the specified * graph. The effect of this operation is the same as if the graph * would be deleted with the routine glp_delete_graph and then created * anew with the routine glp_create_graph, with exception that the * handle (pointer) to the graph remains valid. */ static void delete_graph(glp_graph *G) { dmp_delete_pool(G->pool); xfree(G->v); if (G->index != NULL) avl_delete_tree(G->index); return; } void glp_erase_graph(glp_graph *G, int v_size, int a_size) { if (!(0 <= v_size && v_size <= 256)) xerror("glp_erase_graph: v_size = %d; invalid size of vertex d" "ata\n", v_size); if (!(0 <= a_size && a_size <= 256)) xerror("glp_erase_graph: a_size = %d; invalid size of arc data" "\n", a_size); delete_graph(G); create_graph(G, v_size, a_size); return; } /*********************************************************************** * NAME * * glp_delete_graph - delete graph * * SYNOPSIS * * void glp_delete_graph(glp_graph *G); * * DESCRIPTION * * The routine glp_delete_graph deletes the specified graph and frees * all the memory allocated to this program object. */ void glp_delete_graph(glp_graph *G) { delete_graph(G); xfree(G); return; } /**********************************************************************/ void glp_create_v_index(glp_graph *G) { /* create vertex name index */ glp_vertex *v; int i; if (G->index == NULL) { G->index = avl_create_tree(avl_strcmp, NULL); for (i = 1; i <= G->nv; i++) { v = G->v[i]; xassert(v->entry == NULL); if (v->name != NULL) { v->entry = avl_insert_node(G->index, v->name); avl_set_node_link(v->entry, v); } } } return; } int glp_find_vertex(glp_graph *G, const char *name) { /* find vertex by its name */ AVLNODE *node; int i = 0; if (G->index == NULL) xerror("glp_find_vertex: vertex name index does not exist\n"); if (!(name == NULL || name[0] == '\0' || strlen(name) > 255)) { node = avl_find_node(G->index, name); if (node != NULL) i = ((glp_vertex *)avl_get_node_link(node))->i; } return i; } void glp_delete_v_index(glp_graph *G) { /* delete vertex name index */ int i; if (G->index != NULL) { avl_delete_tree(G->index), G->index = NULL; for (i = 1; i <= G->nv; i++) G->v[i]->entry = NULL; } return; } /*********************************************************************** * NAME * * glp_read_graph - read graph from plain text file * * SYNOPSIS * * int glp_read_graph(glp_graph *G, const char *fname); * * DESCRIPTION * * The routine glp_read_graph reads a graph from a plain text file. * * RETURNS * * If the operation was successful, the routine returns zero. Otherwise * it prints an error message and returns non-zero. */ int glp_read_graph(glp_graph *G, const char *fname) { glp_data *data; jmp_buf jump; int nv, na, i, j, k, ret; glp_erase_graph(G, G->v_size, G->a_size); xprintf("Reading graph from `%s'...\n", fname); data = glp_sdf_open_file(fname); if (data == NULL) { ret = 1; goto done; } if (setjmp(jump)) { ret = 1; goto done; } glp_sdf_set_jump(data, jump); nv = glp_sdf_read_int(data); if (nv < 0) glp_sdf_error(data, "invalid number of vertices\n"); na = glp_sdf_read_int(data); if (na < 0) glp_sdf_error(data, "invalid number of arcs\n"); xprintf("Graph has %d vert%s and %d arc%s\n", nv, nv == 1 ? "ex" : "ices", na, na == 1 ? "" : "s"); if (nv > 0) glp_add_vertices(G, nv); for (k = 1; k <= na; k++) { i = glp_sdf_read_int(data); if (!(1 <= i && i <= nv)) glp_sdf_error(data, "tail vertex number out of range\n"); j = glp_sdf_read_int(data); if (!(1 <= j && j <= nv)) glp_sdf_error(data, "head vertex number out of range\n"); glp_add_arc(G, i, j); } xprintf("%d lines were read\n", glp_sdf_line(data)); ret = 0; done: if (data != NULL) glp_sdf_close_file(data); return ret; } /*********************************************************************** * NAME * * glp_write_graph - write graph to plain text file * * SYNOPSIS * * int glp_write_graph(glp_graph *G, const char *fname). * * DESCRIPTION * * The routine glp_write_graph writes the specified graph to a plain * text file. * * RETURNS * * If the operation was successful, the routine returns zero. Otherwise * it prints an error message and returns non-zero. */ int glp_write_graph(glp_graph *G, const char *fname) { XFILE *fp; glp_vertex *v; glp_arc *a; int i, count, ret; xprintf("Writing graph to `%s'...\n", fname); fp = xfopen(fname, "w"), count = 0; if (fp == NULL) { xprintf("Unable to create `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } xfprintf(fp, "%d %d\n", G->nv, G->na), count++; for (i = 1; i <= G->nv; i++) { v = G->v[i]; for (a = v->out; a != NULL; a = a->t_next) xfprintf(fp, "%d %d\n", a->tail->i, a->head->i), count++; } xfflush(fp); if (xferror(fp)) { xprintf("Write error on `%s' - %s\n", fname, xerrmsg()); ret = 1; goto done; } xprintf("%d lines were written\n", count); ret = 0; done: if (fp != NULL) xfclose(fp); return ret; } /* eof */ Rglpk/src/GLPK/dmp.c0000644000176000001440000001572712245352174013652 0ustar ripleyusers/* dmp.c (dynamic memory pool) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #include "dmp.h" struct DMP { /* dynamic memory pool */ void *avail[32]; /* avail[k], 0 <= k <= 31, is a pointer to first available (free) * atom of (k+1)*8 bytes long; at the beginning of each free atom * there is a pointer to another free atom of the same size */ void *block; /* pointer to most recently allocated memory block; at the * beginning of each allocated memory block there is a pointer to * previously allocated memory block */ int used; /* number of bytes used in most recently allocated memory block */ size_t count; /* number of atoms which are currently in use */ }; #define DMP_BLK_SIZE 8000 /* size of memory blocks, in bytes, allocated for memory pools */ struct prefix { /* atom prefix (for debugging only) */ DMP *pool; /* dynamic memory pool */ int size; /* original atom size, in bytes */ }; #define prefix_size ((sizeof(struct prefix) + 7) & ~7) /* size of atom prefix rounded up to multiple of 8 bytes */ int dmp_debug; /* debug mode flag */ /*********************************************************************** * NAME * * dmp_create_pool - create dynamic memory pool * * SYNOPSIS * * #include "dmp.h" * DMP *dmp_create_pool(void); * * DESCRIPTION * * The routine dmp_create_pool creates a dynamic memory pool. * * RETURNS * * The routine returns a pointer to the memory pool created. */ DMP *dmp_create_pool(void) { DMP *pool; int k; xassert(sizeof(void *) <= 8); if (dmp_debug) xprintf("dmp_create_pool: warning: debug mode is on\n"); pool = talloc(1, DMP); for (k = 0; k <= 31; k++) pool->avail[k] = NULL; pool->block = NULL; pool->used = DMP_BLK_SIZE; pool->count = 0; return pool; } /*********************************************************************** * NAME * * dmp_get_atom - get free atom from dynamic memory pool * * SYNOPSIS * * #include "dmp.h" * void *dmp_get_atom(DMP *pool, int size); * * DESCRIPTION * * The routine dmp_get_atom obtains a free atom (memory space) from the * specified memory pool. * * The parameter size is the atom size, in bytes, 1 <= size <= 256. * * Note that the free atom contains arbitrary data, not binary zeros. * * RETURNS * * The routine returns a pointer to the free atom obtained. */ void *dmp_get_atom(DMP *pool, int size) { void *atom; int k, need; xassert(1 <= size && size <= 256); /* round up atom size to multiple of 8 bytes */ need = (size + 7) & ~7; /* determine number of corresponding list of free atoms */ k = (need >> 3) - 1; /* obtain free atom */ if (pool->avail[k] == NULL) { /* corresponding list of free atoms is empty */ /* if debug mode is on, add atom prefix size */ if (dmp_debug) need += prefix_size; if (pool->used + need > DMP_BLK_SIZE) { /* allocate new memory block */ void *block = talloc(DMP_BLK_SIZE, char); *(void **)block = pool->block; pool->block = block; pool->used = 8; /* sufficient to store pointer */ } /* allocate new atom in current memory block */ atom = (char *)pool->block + pool->used; pool->used += need; } else { /* obtain atom from corresponding list of free atoms */ atom = pool->avail[k]; pool->avail[k] = *(void **)atom; } /* if debug mode is on, fill atom prefix */ if (dmp_debug) { ((struct prefix *)atom)->pool = pool; ((struct prefix *)atom)->size = size; atom = (char *)atom + prefix_size; } /* increase number of allocated atoms */ pool->count++; return atom; } /*********************************************************************** * NAME * * dmp_free_atom - return atom to dynamic memory pool * * SYNOPSIS * * #include "dmp.h" * void dmp_free_atom(DMP *pool, void *atom, int size); * * DESCRIPTION * * The routine dmp_free_atom returns the specified atom (memory space) * to the specified memory pool, making the atom free. * * The parameter size is the atom size, in bytes, 1 <= size <= 256. * * Note that the atom can be returned only to the pool, from which it * was obtained, and its size must be exactly the same as on obtaining * it from the pool. */ void dmp_free_atom(DMP *pool, void *atom, int size) { int k; xassert(1 <= size && size <= 256); /* determine number of corresponding list of free atoms */ k = ((size + 7) >> 3) - 1; /* if debug mode is on, check atom prefix */ if (dmp_debug) { atom = (char *)atom - prefix_size; xassert(((struct prefix *)atom)->pool == pool); xassert(((struct prefix *)atom)->size == size); } /* return atom to corresponding list of free atoms */ *(void **)atom = pool->avail[k]; pool->avail[k] = atom; /* decrease number of allocated atoms */ xassert(pool->count > 0); pool->count--; return; } /*********************************************************************** * NAME * * dmp_in_use - determine how many atoms are still in use * * SYNOPSIS * * #include "dmp.h" * size_t dmp_in_use(DMP *pool); * * RETURNS * * The routine returns the number of atoms of the specified memory pool * which are still in use. */ size_t dmp_in_use(DMP *pool) { return pool->count; } /*********************************************************************** * NAME * * dmp_delete_pool - delete dynamic memory pool * * SYNOPSIS * * #include "dmp.h" * void dmp_delete_pool(DMP *pool); * * DESCRIPTION * * The routine dmp_delete_pool deletes the specified dynamic memory * pool freeing all the memory allocated to this object. */ void dmp_delete_pool(DMP *pool) { while (pool->block != NULL) { void *block = pool->block; pool->block = *(void **)block; tfree(block); } tfree(pool); return; } /* eof */ Rglpk/src/GLPK/keller.h0000644000176000001440000000244512245352174014346 0ustar ripleyusers/* keller.h (cover edges by cliques, Kellerman's heuristic) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2009, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef KELLER_H #define KELLER_H #define kellerman _glp_kellerman int kellerman(int n, int (*func)(void *info, int i, int ind[]), void *info, void /* glp_graph */ *H); /* cover edges by cliques with Kellerman's heuristic */ #endif /* eof */ Rglpk/src/GLPK/glpapi12.c0000644000176000001440000023630212245352174014503 0ustar ripleyusers/* glpapi12.c (basis factorization and simplex tableau routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpapi.h" /*********************************************************************** * NAME * * glp_bf_exists - check if the basis factorization exists * * SYNOPSIS * * int glp_bf_exists(glp_prob *lp); * * RETURNS * * If the basis factorization for the current basis associated with * the specified problem object exists and therefore is available for * computations, the routine glp_bf_exists returns non-zero. Otherwise * the routine returns zero. */ int glp_bf_exists(glp_prob *lp) { int ret; ret = (lp->m == 0 || lp->valid); return ret; } /*********************************************************************** * NAME * * glp_factorize - compute the basis factorization * * SYNOPSIS * * int glp_factorize(glp_prob *lp); * * DESCRIPTION * * The routine glp_factorize computes the basis factorization for the * current basis associated with the specified problem object. * * RETURNS * * 0 The basis factorization has been successfully computed. * * GLP_EBADB * The basis matrix is invalid, i.e. the number of basic (auxiliary * and structural) variables differs from the number of rows in the * problem object. * * GLP_ESING * The basis matrix is singular within the working precision. * * GLP_ECOND * The basis matrix is ill-conditioned. */ static int b_col(void *info, int j, int ind[], double val[]) { glp_prob *lp = info; int m = lp->m; GLPAIJ *aij; int k, len; xassert(1 <= j && j <= m); /* determine the ordinal number of basic auxiliary or structural variable x[k] corresponding to basic variable xB[j] */ k = lp->head[j]; /* build j-th column of the basic matrix, which is k-th column of the scaled augmented matrix (I | -R*A*S) */ if (k <= m) { /* x[k] is auxiliary variable */ len = 1; ind[1] = k; val[1] = 1.0; } else { /* x[k] is structural variable */ len = 0; for (aij = lp->col[k-m]->ptr; aij != NULL; aij = aij->c_next) { len++; ind[len] = aij->row->i; val[len] = - aij->row->rii * aij->val * aij->col->sjj; } } return len; } static void copy_bfcp(glp_prob *lp); int glp_factorize(glp_prob *lp) { int m = lp->m; int n = lp->n; GLPROW **row = lp->row; GLPCOL **col = lp->col; int *head = lp->head; int j, k, stat, ret; /* invalidate the basis factorization */ lp->valid = 0; /* build the basis header */ j = 0; for (k = 1; k <= m+n; k++) { if (k <= m) { stat = row[k]->stat; row[k]->bind = 0; } else { stat = col[k-m]->stat; col[k-m]->bind = 0; } if (stat == GLP_BS) { j++; if (j > m) { /* too many basic variables */ ret = GLP_EBADB; goto fini; } head[j] = k; if (k <= m) row[k]->bind = j; else col[k-m]->bind = j; } } if (j < m) { /* too few basic variables */ ret = GLP_EBADB; goto fini; } /* try to factorize the basis matrix */ if (m > 0) { if (lp->bfd == NULL) { lp->bfd = bfd_create_it(); copy_bfcp(lp); } switch (bfd_factorize(lp->bfd, m, lp->head, b_col, lp)) { case 0: /* ok */ break; case BFD_ESING: /* singular matrix */ ret = GLP_ESING; goto fini; case BFD_ECOND: /* ill-conditioned matrix */ ret = GLP_ECOND; goto fini; default: xassert(lp != lp); } lp->valid = 1; } /* factorization successful */ ret = 0; fini: /* bring the return code to the calling program */ return ret; } /*********************************************************************** * NAME * * glp_bf_updated - check if the basis factorization has been updated * * SYNOPSIS * * int glp_bf_updated(glp_prob *lp); * * RETURNS * * If the basis factorization has been just computed from scratch, the * routine glp_bf_updated returns zero. Otherwise, if the factorization * has been updated one or more times, the routine returns non-zero. */ int glp_bf_updated(glp_prob *lp) { int cnt; if (!(lp->m == 0 || lp->valid)) xerror("glp_bf_update: basis factorization does not exist\n"); #if 0 /* 15/XI-2009 */ cnt = (lp->m == 0 ? 0 : lp->bfd->upd_cnt); #else cnt = (lp->m == 0 ? 0 : bfd_get_count(lp->bfd)); #endif return cnt; } /*********************************************************************** * NAME * * glp_get_bfcp - retrieve basis factorization control parameters * * SYNOPSIS * * void glp_get_bfcp(glp_prob *lp, glp_bfcp *parm); * * DESCRIPTION * * The routine glp_get_bfcp retrieves control parameters, which are * used on computing and updating the basis factorization associated * with the specified problem object. * * Current values of control parameters are stored by the routine in * a glp_bfcp structure, which the parameter parm points to. */ void glp_get_bfcp(glp_prob *lp, glp_bfcp *parm) { glp_bfcp *bfcp = lp->bfcp; if (bfcp == NULL) { parm->type = GLP_BF_FT; parm->lu_size = 0; parm->piv_tol = 0.10; parm->piv_lim = 4; parm->suhl = GLP_ON; parm->eps_tol = 1e-15; parm->max_gro = 1e+10; parm->nfs_max = 100; parm->upd_tol = 1e-6; parm->nrs_max = 100; parm->rs_size = 0; } else memcpy(parm, bfcp, sizeof(glp_bfcp)); return; } /*********************************************************************** * NAME * * glp_set_bfcp - change basis factorization control parameters * * SYNOPSIS * * void glp_set_bfcp(glp_prob *lp, const glp_bfcp *parm); * * DESCRIPTION * * The routine glp_set_bfcp changes control parameters, which are used * by internal GLPK routines in computing and updating the basis * factorization associated with the specified problem object. * * New values of the control parameters should be passed in a structure * glp_bfcp, which the parameter parm points to. * * The parameter parm can be specified as NULL, in which case all * control parameters are reset to their default values. */ #if 0 /* 15/XI-2009 */ static void copy_bfcp(glp_prob *lp) { glp_bfcp _parm, *parm = &_parm; BFD *bfd = lp->bfd; glp_get_bfcp(lp, parm); xassert(bfd != NULL); bfd->type = parm->type; bfd->lu_size = parm->lu_size; bfd->piv_tol = parm->piv_tol; bfd->piv_lim = parm->piv_lim; bfd->suhl = parm->suhl; bfd->eps_tol = parm->eps_tol; bfd->max_gro = parm->max_gro; bfd->nfs_max = parm->nfs_max; bfd->upd_tol = parm->upd_tol; bfd->nrs_max = parm->nrs_max; bfd->rs_size = parm->rs_size; return; } #else static void copy_bfcp(glp_prob *lp) { glp_bfcp _parm, *parm = &_parm; glp_get_bfcp(lp, parm); bfd_set_parm(lp->bfd, parm); return; } #endif void glp_set_bfcp(glp_prob *lp, const glp_bfcp *parm) { glp_bfcp *bfcp = lp->bfcp; if (parm == NULL) { /* reset to default values */ if (bfcp != NULL) xfree(bfcp), lp->bfcp = NULL; } else { /* set to specified values */ if (bfcp == NULL) bfcp = lp->bfcp = xmalloc(sizeof(glp_bfcp)); memcpy(bfcp, parm, sizeof(glp_bfcp)); if (!(bfcp->type == GLP_BF_FT || bfcp->type == GLP_BF_BG || bfcp->type == GLP_BF_GR)) xerror("glp_set_bfcp: type = %d; invalid parameter\n", bfcp->type); if (bfcp->lu_size < 0) xerror("glp_set_bfcp: lu_size = %d; invalid parameter\n", bfcp->lu_size); if (!(0.0 < bfcp->piv_tol && bfcp->piv_tol < 1.0)) xerror("glp_set_bfcp: piv_tol = %g; invalid parameter\n", bfcp->piv_tol); if (bfcp->piv_lim < 1) xerror("glp_set_bfcp: piv_lim = %d; invalid parameter\n", bfcp->piv_lim); if (!(bfcp->suhl == GLP_ON || bfcp->suhl == GLP_OFF)) xerror("glp_set_bfcp: suhl = %d; invalid parameter\n", bfcp->suhl); if (!(0.0 <= bfcp->eps_tol && bfcp->eps_tol <= 1e-6)) xerror("glp_set_bfcp: eps_tol = %g; invalid parameter\n", bfcp->eps_tol); if (bfcp->max_gro < 1.0) xerror("glp_set_bfcp: max_gro = %g; invalid parameter\n", bfcp->max_gro); if (!(1 <= bfcp->nfs_max && bfcp->nfs_max <= 32767)) xerror("glp_set_bfcp: nfs_max = %d; invalid parameter\n", bfcp->nfs_max); if (!(0.0 < bfcp->upd_tol && bfcp->upd_tol < 1.0)) xerror("glp_set_bfcp: upd_tol = %g; invalid parameter\n", bfcp->upd_tol); if (!(1 <= bfcp->nrs_max && bfcp->nrs_max <= 32767)) xerror("glp_set_bfcp: nrs_max = %d; invalid parameter\n", bfcp->nrs_max); if (bfcp->rs_size < 0) xerror("glp_set_bfcp: rs_size = %d; invalid parameter\n", bfcp->nrs_max); if (bfcp->rs_size == 0) bfcp->rs_size = 20 * bfcp->nrs_max; } if (lp->bfd != NULL) copy_bfcp(lp); return; } /*********************************************************************** * NAME * * glp_get_bhead - retrieve the basis header information * * SYNOPSIS * * int glp_get_bhead(glp_prob *lp, int k); * * DESCRIPTION * * The routine glp_get_bhead returns the basis header information for * the current basis associated with the specified problem object. * * RETURNS * * If xB[k], 1 <= k <= m, is i-th auxiliary variable (1 <= i <= m), the * routine returns i. Otherwise, if xB[k] is j-th structural variable * (1 <= j <= n), the routine returns m+j. Here m is the number of rows * and n is the number of columns in the problem object. */ int glp_get_bhead(glp_prob *lp, int k) { if (!(lp->m == 0 || lp->valid)) xerror("glp_get_bhead: basis factorization does not exist\n"); if (!(1 <= k && k <= lp->m)) xerror("glp_get_bhead: k = %d; index out of range\n", k); return lp->head[k]; } /*********************************************************************** * NAME * * glp_get_row_bind - retrieve row index in the basis header * * SYNOPSIS * * int glp_get_row_bind(glp_prob *lp, int i); * * RETURNS * * The routine glp_get_row_bind returns the index k of basic variable * xB[k], 1 <= k <= m, which is i-th auxiliary variable, 1 <= i <= m, * in the current basis associated with the specified problem object, * where m is the number of rows. However, if i-th auxiliary variable * is non-basic, the routine returns zero. */ int glp_get_row_bind(glp_prob *lp, int i) { if (!(lp->m == 0 || lp->valid)) xerror("glp_get_row_bind: basis factorization does not exist\n" ); if (!(1 <= i && i <= lp->m)) xerror("glp_get_row_bind: i = %d; row number out of range\n", i); return lp->row[i]->bind; } /*********************************************************************** * NAME * * glp_get_col_bind - retrieve column index in the basis header * * SYNOPSIS * * int glp_get_col_bind(glp_prob *lp, int j); * * RETURNS * * The routine glp_get_col_bind returns the index k of basic variable * xB[k], 1 <= k <= m, which is j-th structural variable, 1 <= j <= n, * in the current basis associated with the specified problem object, * where m is the number of rows, n is the number of columns. However, * if j-th structural variable is non-basic, the routine returns zero.*/ int glp_get_col_bind(glp_prob *lp, int j) { if (!(lp->m == 0 || lp->valid)) xerror("glp_get_col_bind: basis factorization does not exist\n" ); if (!(1 <= j && j <= lp->n)) xerror("glp_get_col_bind: j = %d; column number out of range\n" , j); return lp->col[j]->bind; } /*********************************************************************** * NAME * * glp_ftran - perform forward transformation (solve system B*x = b) * * SYNOPSIS * * void glp_ftran(glp_prob *lp, double x[]); * * DESCRIPTION * * The routine glp_ftran performs forward transformation, i.e. solves * the system B*x = b, where B is the basis matrix corresponding to the * current basis for the specified problem object, x is the vector of * unknowns to be computed, b is the vector of right-hand sides. * * On entry elements of the vector b should be stored in dense format * in locations x[1], ..., x[m], where m is the number of rows. On exit * the routine stores elements of the vector x in the same locations. * * SCALING/UNSCALING * * Let A~ = (I | -A) is the augmented constraint matrix of the original * (unscaled) problem. In the scaled LP problem instead the matrix A the * scaled matrix A" = R*A*S is actually used, so * * A~" = (I | A") = (I | R*A*S) = (R*I*inv(R) | R*A*S) = * (1) * = R*(I | A)*S~ = R*A~*S~, * * is the scaled augmented constraint matrix, where R and S are diagonal * scaling matrices used to scale rows and columns of the matrix A, and * * S~ = diag(inv(R) | S) (2) * * is an augmented diagonal scaling matrix. * * By definition: * * A~ = (B | N), (3) * * where B is the basic matrix, which consists of basic columns of the * augmented constraint matrix A~, and N is a matrix, which consists of * non-basic columns of A~. From (1) it follows that: * * A~" = (B" | N") = (R*B*SB | R*N*SN), (4) * * where SB and SN are parts of the augmented scaling matrix S~, which * correspond to basic and non-basic variables, respectively. Therefore * * B" = R*B*SB, (5) * * which is the scaled basis matrix. */ void glp_ftran(glp_prob *lp, double x[]) { int m = lp->m; GLPROW **row = lp->row; GLPCOL **col = lp->col; int i, k; /* B*x = b ===> (R*B*SB)*(inv(SB)*x) = R*b ===> B"*x" = b", where b" = R*b, x = SB*x" */ if (!(m == 0 || lp->valid)) xerror("glp_ftran: basis factorization does not exist\n"); /* b" := R*b */ for (i = 1; i <= m; i++) x[i] *= row[i]->rii; /* x" := inv(B")*b" */ if (m > 0) bfd_ftran(lp->bfd, x); /* x := SB*x" */ for (i = 1; i <= m; i++) { k = lp->head[i]; if (k <= m) x[i] /= row[k]->rii; else x[i] *= col[k-m]->sjj; } return; } /*********************************************************************** * NAME * * glp_btran - perform backward transformation (solve system B'*x = b) * * SYNOPSIS * * void glp_btran(glp_prob *lp, double x[]); * * DESCRIPTION * * The routine glp_btran performs backward transformation, i.e. solves * the system B'*x = b, where B' is a matrix transposed to the basis * matrix corresponding to the current basis for the specified problem * problem object, x is the vector of unknowns to be computed, b is the * vector of right-hand sides. * * On entry elements of the vector b should be stored in dense format * in locations x[1], ..., x[m], where m is the number of rows. On exit * the routine stores elements of the vector x in the same locations. * * SCALING/UNSCALING * * See comments to the routine glp_ftran. */ void glp_btran(glp_prob *lp, double x[]) { int m = lp->m; GLPROW **row = lp->row; GLPCOL **col = lp->col; int i, k; /* B'*x = b ===> (SB*B'*R)*(inv(R)*x) = SB*b ===> (B")'*x" = b", where b" = SB*b, x = R*x" */ if (!(m == 0 || lp->valid)) xerror("glp_btran: basis factorization does not exist\n"); /* b" := SB*b */ for (i = 1; i <= m; i++) { k = lp->head[i]; if (k <= m) x[i] /= row[k]->rii; else x[i] *= col[k-m]->sjj; } /* x" := inv[(B")']*b" */ if (m > 0) bfd_btran(lp->bfd, x); /* x := R*x" */ for (i = 1; i <= m; i++) x[i] *= row[i]->rii; return; } /*********************************************************************** * NAME * * glp_warm_up - "warm up" LP basis * * SYNOPSIS * * int glp_warm_up(glp_prob *P); * * DESCRIPTION * * The routine glp_warm_up "warms up" the LP basis for the specified * problem object using current statuses assigned to rows and columns * (that is, to auxiliary and structural variables). * * This operation includes computing factorization of the basis matrix * (if it does not exist), computing primal and dual components of basic * solution, and determining the solution status. * * RETURNS * * 0 The operation has been successfully performed. * * GLP_EBADB * The basis matrix is invalid, i.e. the number of basic (auxiliary * and structural) variables differs from the number of rows in the * problem object. * * GLP_ESING * The basis matrix is singular within the working precision. * * GLP_ECOND * The basis matrix is ill-conditioned. */ int glp_warm_up(glp_prob *P) { GLPROW *row; GLPCOL *col; GLPAIJ *aij; int i, j, type, stat, ret; double eps, temp, *work; /* invalidate basic solution */ P->pbs_stat = P->dbs_stat = GLP_UNDEF; P->obj_val = 0.0; P->some = 0; for (i = 1; i <= P->m; i++) { row = P->row[i]; row->prim = row->dual = 0.0; } for (j = 1; j <= P->n; j++) { col = P->col[j]; col->prim = col->dual = 0.0; } /* compute the basis factorization, if necessary */ if (!glp_bf_exists(P)) { ret = glp_factorize(P); if (ret != 0) goto done; } /* allocate working array */ work = xcalloc(1+P->m, sizeof(double)); /* determine and store values of non-basic variables, compute vector (- N * xN) */ for (i = 1; i <= P->m; i++) work[i] = 0.0; for (i = 1; i <= P->m; i++) { row = P->row[i]; if (row->stat == GLP_BS) continue; else if (row->stat == GLP_NL) row->prim = row->lb; else if (row->stat == GLP_NU) row->prim = row->ub; else if (row->stat == GLP_NF) row->prim = 0.0; else if (row->stat == GLP_NS) row->prim = row->lb; else xassert(row != row); /* N[j] is i-th column of matrix (I|-A) */ work[i] -= row->prim; } for (j = 1; j <= P->n; j++) { col = P->col[j]; if (col->stat == GLP_BS) continue; else if (col->stat == GLP_NL) col->prim = col->lb; else if (col->stat == GLP_NU) col->prim = col->ub; else if (col->stat == GLP_NF) col->prim = 0.0; else if (col->stat == GLP_NS) col->prim = col->lb; else xassert(col != col); /* N[j] is (m+j)-th column of matrix (I|-A) */ if (col->prim != 0.0) { for (aij = col->ptr; aij != NULL; aij = aij->c_next) work[aij->row->i] += aij->val * col->prim; } } /* compute vector of basic variables xB = - inv(B) * N * xN */ glp_ftran(P, work); /* store values of basic variables, check primal feasibility */ P->pbs_stat = GLP_FEAS; for (i = 1; i <= P->m; i++) { row = P->row[i]; if (row->stat != GLP_BS) continue; row->prim = work[row->bind]; type = row->type; if (type == GLP_LO || type == GLP_DB || type == GLP_FX) { eps = 1e-6 + 1e-9 * fabs(row->lb); if (row->prim < row->lb - eps) P->pbs_stat = GLP_INFEAS; } if (type == GLP_UP || type == GLP_DB || type == GLP_FX) { eps = 1e-6 + 1e-9 * fabs(row->ub); if (row->prim > row->ub + eps) P->pbs_stat = GLP_INFEAS; } } for (j = 1; j <= P->n; j++) { col = P->col[j]; if (col->stat != GLP_BS) continue; col->prim = work[col->bind]; type = col->type; if (type == GLP_LO || type == GLP_DB || type == GLP_FX) { eps = 1e-6 + 1e-9 * fabs(col->lb); if (col->prim < col->lb - eps) P->pbs_stat = GLP_INFEAS; } if (type == GLP_UP || type == GLP_DB || type == GLP_FX) { eps = 1e-6 + 1e-9 * fabs(col->ub); if (col->prim > col->ub + eps) P->pbs_stat = GLP_INFEAS; } } /* compute value of the objective function */ P->obj_val = P->c0; for (j = 1; j <= P->n; j++) { col = P->col[j]; P->obj_val += col->coef * col->prim; } /* build vector cB of objective coefficients at basic variables */ for (i = 1; i <= P->m; i++) work[i] = 0.0; for (j = 1; j <= P->n; j++) { col = P->col[j]; if (col->stat == GLP_BS) work[col->bind] = col->coef; } /* compute vector of simplex multipliers pi = inv(B') * cB */ glp_btran(P, work); /* compute and store reduced costs of non-basic variables d[j] = c[j] - N'[j] * pi, check dual feasibility */ P->dbs_stat = GLP_FEAS; for (i = 1; i <= P->m; i++) { row = P->row[i]; if (row->stat == GLP_BS) { row->dual = 0.0; continue; } /* N[j] is i-th column of matrix (I|-A) */ row->dual = - work[i]; #if 0 /* 07/III-2013 */ type = row->type; temp = (P->dir == GLP_MIN ? + row->dual : - row->dual); if ((type == GLP_FR || type == GLP_LO) && temp < -1e-5 || (type == GLP_FR || type == GLP_UP) && temp > +1e-5) P->dbs_stat = GLP_INFEAS; #else stat = row->stat; temp = (P->dir == GLP_MIN ? + row->dual : - row->dual); if ((stat == GLP_NF || stat == GLP_NL) && temp < -1e-5 || (stat == GLP_NF || stat == GLP_NU) && temp > +1e-5) P->dbs_stat = GLP_INFEAS; #endif } for (j = 1; j <= P->n; j++) { col = P->col[j]; if (col->stat == GLP_BS) { col->dual = 0.0; continue; } /* N[j] is (m+j)-th column of matrix (I|-A) */ col->dual = col->coef; for (aij = col->ptr; aij != NULL; aij = aij->c_next) col->dual += aij->val * work[aij->row->i]; #if 0 /* 07/III-2013 */ type = col->type; temp = (P->dir == GLP_MIN ? + col->dual : - col->dual); if ((type == GLP_FR || type == GLP_LO) && temp < -1e-5 || (type == GLP_FR || type == GLP_UP) && temp > +1e-5) P->dbs_stat = GLP_INFEAS; #else stat = col->stat; temp = (P->dir == GLP_MIN ? + col->dual : - col->dual); if ((stat == GLP_NF || stat == GLP_NL) && temp < -1e-5 || (stat == GLP_NF || stat == GLP_NU) && temp > +1e-5) P->dbs_stat = GLP_INFEAS; #endif } /* free working array */ xfree(work); ret = 0; done: return ret; } /*********************************************************************** * NAME * * glp_eval_tab_row - compute row of the simplex tableau * * SYNOPSIS * * int glp_eval_tab_row(glp_prob *lp, int k, int ind[], double val[]); * * DESCRIPTION * * The routine glp_eval_tab_row computes a row of the current simplex * tableau for the basic variable, which is specified by the number k: * if 1 <= k <= m, x[k] is k-th auxiliary variable; if m+1 <= k <= m+n, * x[k] is (k-m)-th structural variable, where m is number of rows, and * n is number of columns. The current basis must be available. * * The routine stores column indices and numerical values of non-zero * elements of the computed row using sparse format to the locations * ind[1], ..., ind[len] and val[1], ..., val[len], respectively, where * 0 <= len <= n is number of non-zeros returned on exit. * * Element indices stored in the array ind have the same sense as the * index k, i.e. indices 1 to m denote auxiliary variables and indices * m+1 to m+n denote structural ones (all these variables are obviously * non-basic by definition). * * The computed row shows how the specified basic variable x[k] = xB[i] * depends on non-basic variables: * * xB[i] = alfa[i,1]*xN[1] + alfa[i,2]*xN[2] + ... + alfa[i,n]*xN[n], * * where alfa[i,j] are elements of the simplex table row, xN[j] are * non-basic (auxiliary and structural) variables. * * RETURNS * * The routine returns number of non-zero elements in the simplex table * row stored in the arrays ind and val. * * BACKGROUND * * The system of equality constraints of the LP problem is: * * xR = A * xS, (1) * * where xR is the vector of auxliary variables, xS is the vector of * structural variables, A is the matrix of constraint coefficients. * * The system (1) can be written in homogenous form as follows: * * A~ * x = 0, (2) * * where A~ = (I | -A) is the augmented constraint matrix (has m rows * and m+n columns), x = (xR | xS) is the vector of all (auxiliary and * structural) variables. * * By definition for the current basis we have: * * A~ = (B | N), (3) * * where B is the basis matrix. Thus, the system (2) can be written as: * * B * xB + N * xN = 0. (4) * * From (4) it follows that: * * xB = A^ * xN, (5) * * where the matrix * * A^ = - inv(B) * N (6) * * is called the simplex table. * * It is understood that i-th row of the simplex table is: * * e * A^ = - e * inv(B) * N, (7) * * where e is a unity vector with e[i] = 1. * * To compute i-th row of the simplex table the routine first computes * i-th row of the inverse: * * rho = inv(B') * e, (8) * * where B' is a matrix transposed to B, and then computes elements of * i-th row of the simplex table as scalar products: * * alfa[i,j] = - rho * N[j] for all j, (9) * * where N[j] is a column of the augmented constraint matrix A~, which * corresponds to some non-basic auxiliary or structural variable. */ int glp_eval_tab_row(glp_prob *lp, int k, int ind[], double val[]) { int m = lp->m; int n = lp->n; int i, t, len, lll, *iii; double alfa, *rho, *vvv; if (!(m == 0 || lp->valid)) xerror("glp_eval_tab_row: basis factorization does not exist\n" ); if (!(1 <= k && k <= m+n)) xerror("glp_eval_tab_row: k = %d; variable number out of range" , k); /* determine xB[i] which corresponds to x[k] */ if (k <= m) i = glp_get_row_bind(lp, k); else i = glp_get_col_bind(lp, k-m); if (i == 0) xerror("glp_eval_tab_row: k = %d; variable must be basic", k); xassert(1 <= i && i <= m); /* allocate working arrays */ rho = xcalloc(1+m, sizeof(double)); iii = xcalloc(1+m, sizeof(int)); vvv = xcalloc(1+m, sizeof(double)); /* compute i-th row of the inverse; see (8) */ for (t = 1; t <= m; t++) rho[t] = 0.0; rho[i] = 1.0; glp_btran(lp, rho); /* compute i-th row of the simplex table */ len = 0; for (k = 1; k <= m+n; k++) { if (k <= m) { /* x[k] is auxiliary variable, so N[k] is a unity column */ if (glp_get_row_stat(lp, k) == GLP_BS) continue; /* compute alfa[i,j]; see (9) */ alfa = - rho[k]; } else { /* x[k] is structural variable, so N[k] is a column of the original constraint matrix A with negative sign */ if (glp_get_col_stat(lp, k-m) == GLP_BS) continue; /* compute alfa[i,j]; see (9) */ lll = glp_get_mat_col(lp, k-m, iii, vvv); alfa = 0.0; for (t = 1; t <= lll; t++) alfa += rho[iii[t]] * vvv[t]; } /* store alfa[i,j] */ if (alfa != 0.0) len++, ind[len] = k, val[len] = alfa; } xassert(len <= n); /* free working arrays */ xfree(rho); xfree(iii); xfree(vvv); /* return to the calling program */ return len; } /*********************************************************************** * NAME * * glp_eval_tab_col - compute column of the simplex tableau * * SYNOPSIS * * int glp_eval_tab_col(glp_prob *lp, int k, int ind[], double val[]); * * DESCRIPTION * * The routine glp_eval_tab_col computes a column of the current simplex * table for the non-basic variable, which is specified by the number k: * if 1 <= k <= m, x[k] is k-th auxiliary variable; if m+1 <= k <= m+n, * x[k] is (k-m)-th structural variable, where m is number of rows, and * n is number of columns. The current basis must be available. * * The routine stores row indices and numerical values of non-zero * elements of the computed column using sparse format to the locations * ind[1], ..., ind[len] and val[1], ..., val[len] respectively, where * 0 <= len <= m is number of non-zeros returned on exit. * * Element indices stored in the array ind have the same sense as the * index k, i.e. indices 1 to m denote auxiliary variables and indices * m+1 to m+n denote structural ones (all these variables are obviously * basic by the definition). * * The computed column shows how basic variables depend on the specified * non-basic variable x[k] = xN[j]: * * xB[1] = ... + alfa[1,j]*xN[j] + ... * xB[2] = ... + alfa[2,j]*xN[j] + ... * . . . . . . * xB[m] = ... + alfa[m,j]*xN[j] + ... * * where alfa[i,j] are elements of the simplex table column, xB[i] are * basic (auxiliary and structural) variables. * * RETURNS * * The routine returns number of non-zero elements in the simplex table * column stored in the arrays ind and val. * * BACKGROUND * * As it was explained in comments to the routine glp_eval_tab_row (see * above) the simplex table is the following matrix: * * A^ = - inv(B) * N. (1) * * Therefore j-th column of the simplex table is: * * A^ * e = - inv(B) * N * e = - inv(B) * N[j], (2) * * where e is a unity vector with e[j] = 1, B is the basis matrix, N[j] * is a column of the augmented constraint matrix A~, which corresponds * to the given non-basic auxiliary or structural variable. */ int glp_eval_tab_col(glp_prob *lp, int k, int ind[], double val[]) { int m = lp->m; int n = lp->n; int t, len, stat; double *col; if (!(m == 0 || lp->valid)) xerror("glp_eval_tab_col: basis factorization does not exist\n" ); if (!(1 <= k && k <= m+n)) xerror("glp_eval_tab_col: k = %d; variable number out of range" , k); if (k <= m) stat = glp_get_row_stat(lp, k); else stat = glp_get_col_stat(lp, k-m); if (stat == GLP_BS) xerror("glp_eval_tab_col: k = %d; variable must be non-basic", k); /* obtain column N[k] with negative sign */ col = xcalloc(1+m, sizeof(double)); for (t = 1; t <= m; t++) col[t] = 0.0; if (k <= m) { /* x[k] is auxiliary variable, so N[k] is a unity column */ col[k] = -1.0; } else { /* x[k] is structural variable, so N[k] is a column of the original constraint matrix A with negative sign */ len = glp_get_mat_col(lp, k-m, ind, val); for (t = 1; t <= len; t++) col[ind[t]] = val[t]; } /* compute column of the simplex table, which corresponds to the specified non-basic variable x[k] */ glp_ftran(lp, col); len = 0; for (t = 1; t <= m; t++) { if (col[t] != 0.0) { len++; ind[len] = glp_get_bhead(lp, t); val[len] = col[t]; } } xfree(col); /* return to the calling program */ return len; } /*********************************************************************** * NAME * * glp_transform_row - transform explicitly specified row * * SYNOPSIS * * int glp_transform_row(glp_prob *P, int len, int ind[], double val[]); * * DESCRIPTION * * The routine glp_transform_row performs the same operation as the * routine glp_eval_tab_row with exception that the row to be * transformed is specified explicitly as a sparse vector. * * The explicitly specified row may be thought as a linear form: * * x = a[1]*x[m+1] + a[2]*x[m+2] + ... + a[n]*x[m+n], (1) * * where x is an auxiliary variable for this row, a[j] are coefficients * of the linear form, x[m+j] are structural variables. * * On entry column indices and numerical values of non-zero elements of * the row should be stored in locations ind[1], ..., ind[len] and * val[1], ..., val[len], where len is the number of non-zero elements. * * This routine uses the system of equality constraints and the current * basis in order to express the auxiliary variable x in (1) through the * current non-basic variables (as if the transformed row were added to * the problem object and its auxiliary variable were basic), i.e. the * resultant row has the form: * * x = alfa[1]*xN[1] + alfa[2]*xN[2] + ... + alfa[n]*xN[n], (2) * * where xN[j] are non-basic (auxiliary or structural) variables, n is * the number of columns in the LP problem object. * * On exit the routine stores indices and numerical values of non-zero * elements of the resultant row (2) in locations ind[1], ..., ind[len'] * and val[1], ..., val[len'], where 0 <= len' <= n is the number of * non-zero elements in the resultant row returned by the routine. Note * that indices (numbers) of non-basic variables stored in the array ind * correspond to original ordinal numbers of variables: indices 1 to m * mean auxiliary variables and indices m+1 to m+n mean structural ones. * * RETURNS * * The routine returns len', which is the number of non-zero elements in * the resultant row stored in the arrays ind and val. * * BACKGROUND * * The explicitly specified row (1) is transformed in the same way as it * were the objective function row. * * From (1) it follows that: * * x = aB * xB + aN * xN, (3) * * where xB is the vector of basic variables, xN is the vector of * non-basic variables. * * The simplex table, which corresponds to the current basis, is: * * xB = [-inv(B) * N] * xN. (4) * * Therefore substituting xB from (4) to (3) we have: * * x = aB * [-inv(B) * N] * xN + aN * xN = * (5) * = rho * (-N) * xN + aN * xN = alfa * xN, * * where: * * rho = inv(B') * aB, (6) * * and * * alfa = aN + rho * (-N) (7) * * is the resultant row computed by the routine. */ int glp_transform_row(glp_prob *P, int len, int ind[], double val[]) { int i, j, k, m, n, t, lll, *iii; double alfa, *a, *aB, *rho, *vvv; if (!glp_bf_exists(P)) xerror("glp_transform_row: basis factorization does not exist " "\n"); m = glp_get_num_rows(P); n = glp_get_num_cols(P); /* unpack the row to be transformed to the array a */ a = xcalloc(1+n, sizeof(double)); for (j = 1; j <= n; j++) a[j] = 0.0; if (!(0 <= len && len <= n)) xerror("glp_transform_row: len = %d; invalid row length\n", len); for (t = 1; t <= len; t++) { j = ind[t]; if (!(1 <= j && j <= n)) xerror("glp_transform_row: ind[%d] = %d; column index out o" "f range\n", t, j); if (val[t] == 0.0) xerror("glp_transform_row: val[%d] = 0; zero coefficient no" "t allowed\n", t); if (a[j] != 0.0) xerror("glp_transform_row: ind[%d] = %d; duplicate column i" "ndices not allowed\n", t, j); a[j] = val[t]; } /* construct the vector aB */ aB = xcalloc(1+m, sizeof(double)); for (i = 1; i <= m; i++) { k = glp_get_bhead(P, i); /* xB[i] is k-th original variable */ xassert(1 <= k && k <= m+n); aB[i] = (k <= m ? 0.0 : a[k-m]); } /* solve the system B'*rho = aB to compute the vector rho */ rho = aB, glp_btran(P, rho); /* compute coefficients at non-basic auxiliary variables */ len = 0; for (i = 1; i <= m; i++) { if (glp_get_row_stat(P, i) != GLP_BS) { alfa = - rho[i]; if (alfa != 0.0) { len++; ind[len] = i; val[len] = alfa; } } } /* compute coefficients at non-basic structural variables */ iii = xcalloc(1+m, sizeof(int)); vvv = xcalloc(1+m, sizeof(double)); for (j = 1; j <= n; j++) { if (glp_get_col_stat(P, j) != GLP_BS) { alfa = a[j]; lll = glp_get_mat_col(P, j, iii, vvv); for (t = 1; t <= lll; t++) alfa += vvv[t] * rho[iii[t]]; if (alfa != 0.0) { len++; ind[len] = m+j; val[len] = alfa; } } } xassert(len <= n); xfree(iii); xfree(vvv); xfree(aB); xfree(a); return len; } /*********************************************************************** * NAME * * glp_transform_col - transform explicitly specified column * * SYNOPSIS * * int glp_transform_col(glp_prob *P, int len, int ind[], double val[]); * * DESCRIPTION * * The routine glp_transform_col performs the same operation as the * routine glp_eval_tab_col with exception that the column to be * transformed is specified explicitly as a sparse vector. * * The explicitly specified column may be thought as if it were added * to the original system of equality constraints: * * x[1] = a[1,1]*x[m+1] + ... + a[1,n]*x[m+n] + a[1]*x * x[2] = a[2,1]*x[m+1] + ... + a[2,n]*x[m+n] + a[2]*x (1) * . . . . . . . . . . . . . . . * x[m] = a[m,1]*x[m+1] + ... + a[m,n]*x[m+n] + a[m]*x * * where x[i] are auxiliary variables, x[m+j] are structural variables, * x is a structural variable for the explicitly specified column, a[i] * are constraint coefficients for x. * * On entry row indices and numerical values of non-zero elements of * the column should be stored in locations ind[1], ..., ind[len] and * val[1], ..., val[len], where len is the number of non-zero elements. * * This routine uses the system of equality constraints and the current * basis in order to express the current basic variables through the * structural variable x in (1) (as if the transformed column were added * to the problem object and the variable x were non-basic), i.e. the * resultant column has the form: * * xB[1] = ... + alfa[1]*x * xB[2] = ... + alfa[2]*x (2) * . . . . . . * xB[m] = ... + alfa[m]*x * * where xB are basic (auxiliary and structural) variables, m is the * number of rows in the problem object. * * On exit the routine stores indices and numerical values of non-zero * elements of the resultant column (2) in locations ind[1], ..., * ind[len'] and val[1], ..., val[len'], where 0 <= len' <= m is the * number of non-zero element in the resultant column returned by the * routine. Note that indices (numbers) of basic variables stored in * the array ind correspond to original ordinal numbers of variables: * indices 1 to m mean auxiliary variables and indices m+1 to m+n mean * structural ones. * * RETURNS * * The routine returns len', which is the number of non-zero elements * in the resultant column stored in the arrays ind and val. * * BACKGROUND * * The explicitly specified column (1) is transformed in the same way * as any other column of the constraint matrix using the formula: * * alfa = inv(B) * a, (3) * * where alfa is the resultant column computed by the routine. */ int glp_transform_col(glp_prob *P, int len, int ind[], double val[]) { int i, m, t; double *a, *alfa; if (!glp_bf_exists(P)) xerror("glp_transform_col: basis factorization does not exist " "\n"); m = glp_get_num_rows(P); /* unpack the column to be transformed to the array a */ a = xcalloc(1+m, sizeof(double)); for (i = 1; i <= m; i++) a[i] = 0.0; if (!(0 <= len && len <= m)) xerror("glp_transform_col: len = %d; invalid column length\n", len); for (t = 1; t <= len; t++) { i = ind[t]; if (!(1 <= i && i <= m)) xerror("glp_transform_col: ind[%d] = %d; row index out of r" "ange\n", t, i); if (val[t] == 0.0) xerror("glp_transform_col: val[%d] = 0; zero coefficient no" "t allowed\n", t); if (a[i] != 0.0) xerror("glp_transform_col: ind[%d] = %d; duplicate row indi" "ces not allowed\n", t, i); a[i] = val[t]; } /* solve the system B*a = alfa to compute the vector alfa */ alfa = a, glp_ftran(P, alfa); /* store resultant coefficients */ len = 0; for (i = 1; i <= m; i++) { if (alfa[i] != 0.0) { len++; ind[len] = glp_get_bhead(P, i); val[len] = alfa[i]; } } xfree(a); return len; } /*********************************************************************** * NAME * * glp_prim_rtest - perform primal ratio test * * SYNOPSIS * * int glp_prim_rtest(glp_prob *P, int len, const int ind[], * const double val[], int dir, double eps); * * DESCRIPTION * * The routine glp_prim_rtest performs the primal ratio test using an * explicitly specified column of the simplex table. * * The current basic solution associated with the LP problem object * must be primal feasible. * * The explicitly specified column of the simplex table shows how the * basic variables xB depend on some non-basic variable x (which is not * necessarily presented in the problem object): * * xB[1] = ... + alfa[1] * x + ... * xB[2] = ... + alfa[2] * x + ... (*) * . . . . . . . . * xB[m] = ... + alfa[m] * x + ... * * The column (*) is specifed on entry to the routine using the sparse * format. Ordinal numbers of basic variables xB[i] should be placed in * locations ind[1], ..., ind[len], where ordinal number 1 to m denote * auxiliary variables, and ordinal numbers m+1 to m+n denote structural * variables. The corresponding non-zero coefficients alfa[i] should be * placed in locations val[1], ..., val[len]. The arrays ind and val are * not changed on exit. * * The parameter dir specifies direction in which the variable x changes * on entering the basis: +1 means increasing, -1 means decreasing. * * The parameter eps is an absolute tolerance (small positive number) * used by the routine to skip small alfa[j] of the row (*). * * The routine determines which basic variable (among specified in * ind[1], ..., ind[len]) should leave the basis in order to keep primal * feasibility. * * RETURNS * * The routine glp_prim_rtest returns the index piv in the arrays ind * and val corresponding to the pivot element chosen, 1 <= piv <= len. * If the adjacent basic solution is primal unbounded and therefore the * choice cannot be made, the routine returns zero. * * COMMENTS * * If the non-basic variable x is presented in the LP problem object, * the column (*) can be computed with the routine glp_eval_tab_col; * otherwise it can be computed with the routine glp_transform_col. */ int glp_prim_rtest(glp_prob *P, int len, const int ind[], const double val[], int dir, double eps) { int k, m, n, piv, t, type, stat; double alfa, big, beta, lb, ub, temp, teta; if (glp_get_prim_stat(P) != GLP_FEAS) xerror("glp_prim_rtest: basic solution is not primal feasible " "\n"); if (!(dir == +1 || dir == -1)) xerror("glp_prim_rtest: dir = %d; invalid parameter\n", dir); if (!(0.0 < eps && eps < 1.0)) xerror("glp_prim_rtest: eps = %g; invalid parameter\n", eps); m = glp_get_num_rows(P); n = glp_get_num_cols(P); /* initial settings */ piv = 0, teta = DBL_MAX, big = 0.0; /* walk through the entries of the specified column */ for (t = 1; t <= len; t++) { /* get the ordinal number of basic variable */ k = ind[t]; if (!(1 <= k && k <= m+n)) xerror("glp_prim_rtest: ind[%d] = %d; variable number out o" "f range\n", t, k); /* determine type, bounds, status and primal value of basic variable xB[i] = x[k] in the current basic solution */ if (k <= m) { type = glp_get_row_type(P, k); lb = glp_get_row_lb(P, k); ub = glp_get_row_ub(P, k); stat = glp_get_row_stat(P, k); beta = glp_get_row_prim(P, k); } else { type = glp_get_col_type(P, k-m); lb = glp_get_col_lb(P, k-m); ub = glp_get_col_ub(P, k-m); stat = glp_get_col_stat(P, k-m); beta = glp_get_col_prim(P, k-m); } if (stat != GLP_BS) xerror("glp_prim_rtest: ind[%d] = %d; non-basic variable no" "t allowed\n", t, k); /* determine influence coefficient at basic variable xB[i] in the explicitly specified column and turn to the case of increasing the variable x in order to simplify the program logic */ alfa = (dir > 0 ? + val[t] : - val[t]); /* analyze main cases */ if (type == GLP_FR) { /* xB[i] is free variable */ continue; } else if (type == GLP_LO) lo: { /* xB[i] has an lower bound */ if (alfa > - eps) continue; temp = (lb - beta) / alfa; } else if (type == GLP_UP) up: { /* xB[i] has an upper bound */ if (alfa < + eps) continue; temp = (ub - beta) / alfa; } else if (type == GLP_DB) { /* xB[i] has both lower and upper bounds */ if (alfa < 0.0) goto lo; else goto up; } else if (type == GLP_FX) { /* xB[i] is fixed variable */ if (- eps < alfa && alfa < + eps) continue; temp = 0.0; } else xassert(type != type); /* if the value of the variable xB[i] violates its lower or upper bound (slightly, because the current basis is assumed to be primal feasible), temp is negative; we can think this happens due to round-off errors and the value is exactly on the bound; this allows replacing temp by zero */ if (temp < 0.0) temp = 0.0; /* apply the minimal ratio test */ if (teta > temp || teta == temp && big < fabs(alfa)) piv = t, teta = temp, big = fabs(alfa); } /* return index of the pivot element chosen */ return piv; } /*********************************************************************** * NAME * * glp_dual_rtest - perform dual ratio test * * SYNOPSIS * * int glp_dual_rtest(glp_prob *P, int len, const int ind[], * const double val[], int dir, double eps); * * DESCRIPTION * * The routine glp_dual_rtest performs the dual ratio test using an * explicitly specified row of the simplex table. * * The current basic solution associated with the LP problem object * must be dual feasible. * * The explicitly specified row of the simplex table is a linear form * that shows how some basic variable x (which is not necessarily * presented in the problem object) depends on non-basic variables xN: * * x = alfa[1] * xN[1] + alfa[2] * xN[2] + ... + alfa[n] * xN[n]. (*) * * The row (*) is specified on entry to the routine using the sparse * format. Ordinal numbers of non-basic variables xN[j] should be placed * in locations ind[1], ..., ind[len], where ordinal numbers 1 to m * denote auxiliary variables, and ordinal numbers m+1 to m+n denote * structural variables. The corresponding non-zero coefficients alfa[j] * should be placed in locations val[1], ..., val[len]. The arrays ind * and val are not changed on exit. * * The parameter dir specifies direction in which the variable x changes * on leaving the basis: +1 means that x goes to its lower bound, and -1 * means that x goes to its upper bound. * * The parameter eps is an absolute tolerance (small positive number) * used by the routine to skip small alfa[j] of the row (*). * * The routine determines which non-basic variable (among specified in * ind[1], ..., ind[len]) should enter the basis in order to keep dual * feasibility. * * RETURNS * * The routine glp_dual_rtest returns the index piv in the arrays ind * and val corresponding to the pivot element chosen, 1 <= piv <= len. * If the adjacent basic solution is dual unbounded and therefore the * choice cannot be made, the routine returns zero. * * COMMENTS * * If the basic variable x is presented in the LP problem object, the * row (*) can be computed with the routine glp_eval_tab_row; otherwise * it can be computed with the routine glp_transform_row. */ int glp_dual_rtest(glp_prob *P, int len, const int ind[], const double val[], int dir, double eps) { int k, m, n, piv, t, stat; double alfa, big, cost, obj, temp, teta; if (glp_get_dual_stat(P) != GLP_FEAS) xerror("glp_dual_rtest: basic solution is not dual feasible\n") ; if (!(dir == +1 || dir == -1)) xerror("glp_dual_rtest: dir = %d; invalid parameter\n", dir); if (!(0.0 < eps && eps < 1.0)) xerror("glp_dual_rtest: eps = %g; invalid parameter\n", eps); m = glp_get_num_rows(P); n = glp_get_num_cols(P); /* take into account optimization direction */ obj = (glp_get_obj_dir(P) == GLP_MIN ? +1.0 : -1.0); /* initial settings */ piv = 0, teta = DBL_MAX, big = 0.0; /* walk through the entries of the specified row */ for (t = 1; t <= len; t++) { /* get ordinal number of non-basic variable */ k = ind[t]; if (!(1 <= k && k <= m+n)) xerror("glp_dual_rtest: ind[%d] = %d; variable number out o" "f range\n", t, k); /* determine status and reduced cost of non-basic variable x[k] = xN[j] in the current basic solution */ if (k <= m) { stat = glp_get_row_stat(P, k); cost = glp_get_row_dual(P, k); } else { stat = glp_get_col_stat(P, k-m); cost = glp_get_col_dual(P, k-m); } if (stat == GLP_BS) xerror("glp_dual_rtest: ind[%d] = %d; basic variable not al" "lowed\n", t, k); /* determine influence coefficient at non-basic variable xN[j] in the explicitly specified row and turn to the case of increasing the variable x in order to simplify the program logic */ alfa = (dir > 0 ? + val[t] : - val[t]); /* analyze main cases */ if (stat == GLP_NL) { /* xN[j] is on its lower bound */ if (alfa < + eps) continue; temp = (obj * cost) / alfa; } else if (stat == GLP_NU) { /* xN[j] is on its upper bound */ if (alfa > - eps) continue; temp = (obj * cost) / alfa; } else if (stat == GLP_NF) { /* xN[j] is non-basic free variable */ if (- eps < alfa && alfa < + eps) continue; temp = 0.0; } else if (stat == GLP_NS) { /* xN[j] is non-basic fixed variable */ continue; } else xassert(stat != stat); /* if the reduced cost of the variable xN[j] violates its zero bound (slightly, because the current basis is assumed to be dual feasible), temp is negative; we can think this happens due to round-off errors and the reduced cost is exact zero; this allows replacing temp by zero */ if (temp < 0.0) temp = 0.0; /* apply the minimal ratio test */ if (teta > temp || teta == temp && big < fabs(alfa)) piv = t, teta = temp, big = fabs(alfa); } /* return index of the pivot element chosen */ return piv; } /*********************************************************************** * NAME * * glp_analyze_row - simulate one iteration of dual simplex method * * SYNOPSIS * * int glp_analyze_row(glp_prob *P, int len, const int ind[], * const double val[], int type, double rhs, double eps, int *piv, * double *x, double *dx, double *y, double *dy, double *dz); * * DESCRIPTION * * Let the current basis be optimal or dual feasible, and there be * specified a row (constraint), which is violated by the current basic * solution. The routine glp_analyze_row simulates one iteration of the * dual simplex method to determine some information on the adjacent * basis (see below), where the specified row becomes active constraint * (i.e. its auxiliary variable becomes non-basic). * * The current basic solution associated with the problem object passed * to the routine must be dual feasible, and its primal components must * be defined. * * The row to be analyzed must be previously transformed either with * the routine glp_eval_tab_row (if the row is in the problem object) * or with the routine glp_transform_row (if the row is external, i.e. * not in the problem object). This is needed to express the row only * through (auxiliary and structural) variables, which are non-basic in * the current basis: * * y = alfa[1] * xN[1] + alfa[2] * xN[2] + ... + alfa[n] * xN[n], * * where y is an auxiliary variable of the row, alfa[j] is an influence * coefficient, xN[j] is a non-basic variable. * * The row is passed to the routine in sparse format. Ordinal numbers * of non-basic variables are stored in locations ind[1], ..., ind[len], * where numbers 1 to m denote auxiliary variables while numbers m+1 to * m+n denote structural variables. Corresponding non-zero coefficients * alfa[j] are stored in locations val[1], ..., val[len]. The arrays * ind and val are ot changed on exit. * * The parameters type and rhs specify the row type and its right-hand * side as follows: * * type = GLP_LO: y = sum alfa[j] * xN[j] >= rhs * * type = GLP_UP: y = sum alfa[j] * xN[j] <= rhs * * The parameter eps is an absolute tolerance (small positive number) * used by the routine to skip small coefficients alfa[j] on performing * the dual ratio test. * * If the operation was successful, the routine stores the following * information to corresponding location (if some parameter is NULL, * its value is not stored): * * piv index in the array ind and val, 1 <= piv <= len, determining * the non-basic variable, which would enter the adjacent basis; * * x value of the non-basic variable in the current basis; * * dx difference between values of the non-basic variable in the * adjacent and current bases, dx = x.new - x.old; * * y value of the row (i.e. of its auxiliary variable) in the * current basis; * * dy difference between values of the row in the adjacent and * current bases, dy = y.new - y.old; * * dz difference between values of the objective function in the * adjacent and current bases, dz = z.new - z.old. Note that in * case of minimization dz >= 0, and in case of maximization * dz <= 0, i.e. in the adjacent basis the objective function * always gets worse (degrades). */ int _glp_analyze_row(glp_prob *P, int len, const int ind[], const double val[], int type, double rhs, double eps, int *_piv, double *_x, double *_dx, double *_y, double *_dy, double *_dz) { int t, k, dir, piv, ret = 0; double x, dx, y, dy, dz; if (P->pbs_stat == GLP_UNDEF) xerror("glp_analyze_row: primal basic solution components are " "undefined\n"); if (P->dbs_stat != GLP_FEAS) xerror("glp_analyze_row: basic solution is not dual feasible\n" ); /* compute the row value y = sum alfa[j] * xN[j] in the current basis */ if (!(0 <= len && len <= P->n)) xerror("glp_analyze_row: len = %d; invalid row length\n", len); y = 0.0; for (t = 1; t <= len; t++) { /* determine value of x[k] = xN[j] in the current basis */ k = ind[t]; if (!(1 <= k && k <= P->m+P->n)) xerror("glp_analyze_row: ind[%d] = %d; row/column index out" " of range\n", t, k); if (k <= P->m) { /* x[k] is auxiliary variable */ if (P->row[k]->stat == GLP_BS) xerror("glp_analyze_row: ind[%d] = %d; basic auxiliary v" "ariable is not allowed\n", t, k); x = P->row[k]->prim; } else { /* x[k] is structural variable */ if (P->col[k-P->m]->stat == GLP_BS) xerror("glp_analyze_row: ind[%d] = %d; basic structural " "variable is not allowed\n", t, k); x = P->col[k-P->m]->prim; } y += val[t] * x; } /* check if the row is primal infeasible in the current basis, i.e. the constraint is violated at the current point */ if (type == GLP_LO) { if (y >= rhs) { /* the constraint is not violated */ ret = 1; goto done; } /* in the adjacent basis y goes to its lower bound */ dir = +1; } else if (type == GLP_UP) { if (y <= rhs) { /* the constraint is not violated */ ret = 1; goto done; } /* in the adjacent basis y goes to its upper bound */ dir = -1; } else xerror("glp_analyze_row: type = %d; invalid parameter\n", type); /* compute dy = y.new - y.old */ dy = rhs - y; /* perform dual ratio test to determine which non-basic variable should enter the adjacent basis to keep it dual feasible */ piv = glp_dual_rtest(P, len, ind, val, dir, eps); if (piv == 0) { /* no dual feasible adjacent basis exists */ ret = 2; goto done; } /* non-basic variable x[k] = xN[j] should enter the basis */ k = ind[piv]; xassert(1 <= k && k <= P->m+P->n); /* determine its value in the current basis */ if (k <= P->m) x = P->row[k]->prim; else x = P->col[k-P->m]->prim; /* compute dx = x.new - x.old = dy / alfa[j] */ xassert(val[piv] != 0.0); dx = dy / val[piv]; /* compute dz = z.new - z.old = d[j] * dx, where d[j] is reduced cost of xN[j] in the current basis */ if (k <= P->m) dz = P->row[k]->dual * dx; else dz = P->col[k-P->m]->dual * dx; /* store the analysis results */ if (_piv != NULL) *_piv = piv; if (_x != NULL) *_x = x; if (_dx != NULL) *_dx = dx; if (_y != NULL) *_y = y; if (_dy != NULL) *_dy = dy; if (_dz != NULL) *_dz = dz; done: return ret; } #if 0 int main(void) { /* example program for the routine glp_analyze_row */ glp_prob *P; glp_smcp parm; int i, k, len, piv, ret, ind[1+100]; double rhs, x, dx, y, dy, dz, val[1+100]; P = glp_create_prob(); /* read plan.mps (see glpk/examples) */ ret = glp_read_mps(P, GLP_MPS_DECK, NULL, "plan.mps"); glp_assert(ret == 0); /* and solve it to optimality */ ret = glp_simplex(P, NULL); glp_assert(ret == 0); glp_assert(glp_get_status(P) == GLP_OPT); /* the optimal objective value is 296.217 */ /* we would like to know what happens if we would add a new row (constraint) to plan.mps: .01 * bin1 + .01 * bin2 + .02 * bin4 + .02 * bin5 <= 12 */ /* first, we specify this new row */ glp_create_index(P); len = 0; ind[++len] = glp_find_col(P, "BIN1"), val[len] = .01; ind[++len] = glp_find_col(P, "BIN2"), val[len] = .01; ind[++len] = glp_find_col(P, "BIN4"), val[len] = .02; ind[++len] = glp_find_col(P, "BIN5"), val[len] = .02; rhs = 12; /* then we can compute value of the row (i.e. of its auxiliary variable) in the current basis to see if the constraint is violated */ y = 0.0; for (k = 1; k <= len; k++) y += val[k] * glp_get_col_prim(P, ind[k]); glp_printf("y = %g\n", y); /* this prints y = 15.1372, so the constraint is violated, since we require that y <= rhs = 12 */ /* now we transform the row to express it only through non-basic (auxiliary and artificial) variables */ len = glp_transform_row(P, len, ind, val); /* finally, we simulate one step of the dual simplex method to obtain necessary information for the adjacent basis */ ret = _glp_analyze_row(P, len, ind, val, GLP_UP, rhs, 1e-9, &piv, &x, &dx, &y, &dy, &dz); glp_assert(ret == 0); glp_printf("k = %d, x = %g; dx = %g; y = %g; dy = %g; dz = %g\n", ind[piv], x, dx, y, dy, dz); /* this prints dz = 5.64418 and means that in the adjacent basis the objective function would be 296.217 + 5.64418 = 301.861 */ /* now we actually include the row into the problem object; note that the arrays ind and val are clobbered, so we need to build them once again */ len = 0; ind[++len] = glp_find_col(P, "BIN1"), val[len] = .01; ind[++len] = glp_find_col(P, "BIN2"), val[len] = .01; ind[++len] = glp_find_col(P, "BIN4"), val[len] = .02; ind[++len] = glp_find_col(P, "BIN5"), val[len] = .02; rhs = 12; i = glp_add_rows(P, 1); glp_set_row_bnds(P, i, GLP_UP, 0, rhs); glp_set_mat_row(P, i, len, ind, val); /* and perform one dual simplex iteration */ glp_init_smcp(&parm); parm.meth = GLP_DUAL; parm.it_lim = 1; glp_simplex(P, &parm); /* the current objective value is 301.861 */ return 0; } #endif /*********************************************************************** * NAME * * glp_analyze_bound - analyze active bound of non-basic variable * * SYNOPSIS * * void glp_analyze_bound(glp_prob *P, int k, double *limit1, int *var1, * double *limit2, int *var2); * * DESCRIPTION * * The routine glp_analyze_bound analyzes the effect of varying the * active bound of specified non-basic variable. * * The non-basic variable is specified by the parameter k, where * 1 <= k <= m means auxiliary variable of corresponding row while * m+1 <= k <= m+n means structural variable (column). * * Note that the current basic solution must be optimal, and the basis * factorization must exist. * * Results of the analysis have the following meaning. * * value1 is the minimal value of the active bound, at which the basis * still remains primal feasible and thus optimal. -DBL_MAX means that * the active bound has no lower limit. * * var1 is the ordinal number of an auxiliary (1 to m) or structural * (m+1 to n) basic variable, which reaches its bound first and thereby * limits further decreasing the active bound being analyzed. * if value1 = -DBL_MAX, var1 is set to 0. * * value2 is the maximal value of the active bound, at which the basis * still remains primal feasible and thus optimal. +DBL_MAX means that * the active bound has no upper limit. * * var2 is the ordinal number of an auxiliary (1 to m) or structural * (m+1 to n) basic variable, which reaches its bound first and thereby * limits further increasing the active bound being analyzed. * if value2 = +DBL_MAX, var2 is set to 0. */ void glp_analyze_bound(glp_prob *P, int k, double *value1, int *var1, double *value2, int *var2) { GLPROW *row; GLPCOL *col; int m, n, stat, kase, p, len, piv, *ind; double x, new_x, ll, uu, xx, delta, *val; /* sanity checks */ if (P == NULL || P->magic != GLP_PROB_MAGIC) xerror("glp_analyze_bound: P = %p; invalid problem object\n", P); m = P->m, n = P->n; if (!(P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS)) xerror("glp_analyze_bound: optimal basic solution required\n"); if (!(m == 0 || P->valid)) xerror("glp_analyze_bound: basis factorization required\n"); if (!(1 <= k && k <= m+n)) xerror("glp_analyze_bound: k = %d; variable number out of rang" "e\n", k); /* retrieve information about the specified non-basic variable x[k] whose active bound is to be analyzed */ if (k <= m) { row = P->row[k]; stat = row->stat; x = row->prim; } else { col = P->col[k-m]; stat = col->stat; x = col->prim; } if (stat == GLP_BS) xerror("glp_analyze_bound: k = %d; basic variable not allowed " "\n", k); /* allocate working arrays */ ind = xcalloc(1+m, sizeof(int)); val = xcalloc(1+m, sizeof(double)); /* compute column of the simplex table corresponding to the non-basic variable x[k] */ len = glp_eval_tab_col(P, k, ind, val); xassert(0 <= len && len <= m); /* perform analysis */ for (kase = -1; kase <= +1; kase += 2) { /* kase < 0 means active bound of x[k] is decreasing; kase > 0 means active bound of x[k] is increasing */ /* use the primal ratio test to determine some basic variable x[p] which reaches its bound first */ piv = glp_prim_rtest(P, len, ind, val, kase, 1e-9); if (piv == 0) { /* nothing limits changing the active bound of x[k] */ p = 0; new_x = (kase < 0 ? -DBL_MAX : +DBL_MAX); goto store; } /* basic variable x[p] limits changing the active bound of x[k]; determine its value in the current basis */ xassert(1 <= piv && piv <= len); p = ind[piv]; if (p <= m) { row = P->row[p]; ll = glp_get_row_lb(P, row->i); uu = glp_get_row_ub(P, row->i); stat = row->stat; xx = row->prim; } else { col = P->col[p-m]; ll = glp_get_col_lb(P, col->j); uu = glp_get_col_ub(P, col->j); stat = col->stat; xx = col->prim; } xassert(stat == GLP_BS); /* determine delta x[p] = bound of x[p] - value of x[p] */ if (kase < 0 && val[piv] > 0.0 || kase > 0 && val[piv] < 0.0) { /* delta x[p] < 0, so x[p] goes toward its lower bound */ xassert(ll != -DBL_MAX); delta = ll - xx; } else { /* delta x[p] > 0, so x[p] goes toward its upper bound */ xassert(uu != +DBL_MAX); delta = uu - xx; } /* delta x[p] = alfa[p,k] * delta x[k], so new x[k] = x[k] + delta x[k] = x[k] + delta x[p] / alfa[p,k] is the value of x[k] in the adjacent basis */ xassert(val[piv] != 0.0); new_x = x + delta / val[piv]; store: /* store analysis results */ if (kase < 0) { if (value1 != NULL) *value1 = new_x; if (var1 != NULL) *var1 = p; } else { if (value2 != NULL) *value2 = new_x; if (var2 != NULL) *var2 = p; } } /* free working arrays */ xfree(ind); xfree(val); return; } /*********************************************************************** * NAME * * glp_analyze_coef - analyze objective coefficient at basic variable * * SYNOPSIS * * void glp_analyze_coef(glp_prob *P, int k, double *coef1, int *var1, * double *value1, double *coef2, int *var2, double *value2); * * DESCRIPTION * * The routine glp_analyze_coef analyzes the effect of varying the * objective coefficient at specified basic variable. * * The basic variable is specified by the parameter k, where * 1 <= k <= m means auxiliary variable of corresponding row while * m+1 <= k <= m+n means structural variable (column). * * Note that the current basic solution must be optimal, and the basis * factorization must exist. * * Results of the analysis have the following meaning. * * coef1 is the minimal value of the objective coefficient, at which * the basis still remains dual feasible and thus optimal. -DBL_MAX * means that the objective coefficient has no lower limit. * * var1 is the ordinal number of an auxiliary (1 to m) or structural * (m+1 to n) non-basic variable, whose reduced cost reaches its zero * bound first and thereby limits further decreasing the objective * coefficient being analyzed. If coef1 = -DBL_MAX, var1 is set to 0. * * value1 is value of the basic variable being analyzed in an adjacent * basis, which is defined as follows. Let the objective coefficient * reaches its minimal value (coef1) and continues decreasing. Then the * reduced cost of the limiting non-basic variable (var1) becomes dual * infeasible and the current basis becomes non-optimal that forces the * limiting non-basic variable to enter the basis replacing there some * basic variable that leaves the basis to keep primal feasibility. * Should note that on determining the adjacent basis current bounds * of the basic variable being analyzed are ignored as if it were free * (unbounded) variable, so it cannot leave the basis. It may happen * that no dual feasible adjacent basis exists, in which case value1 is * set to -DBL_MAX or +DBL_MAX. * * coef2 is the maximal value of the objective coefficient, at which * the basis still remains dual feasible and thus optimal. +DBL_MAX * means that the objective coefficient has no upper limit. * * var2 is the ordinal number of an auxiliary (1 to m) or structural * (m+1 to n) non-basic variable, whose reduced cost reaches its zero * bound first and thereby limits further increasing the objective * coefficient being analyzed. If coef2 = +DBL_MAX, var2 is set to 0. * * value2 is value of the basic variable being analyzed in an adjacent * basis, which is defined exactly in the same way as value1 above with * exception that now the objective coefficient is increasing. */ void glp_analyze_coef(glp_prob *P, int k, double *coef1, int *var1, double *value1, double *coef2, int *var2, double *value2) { GLPROW *row; GLPCOL *col; int m, n, type, stat, kase, p, q, dir, clen, cpiv, rlen, rpiv, *cind, *rind; double lb, ub, coef, x, lim_coef, new_x, d, delta, ll, uu, xx, *rval, *cval; /* sanity checks */ if (P == NULL || P->magic != GLP_PROB_MAGIC) xerror("glp_analyze_coef: P = %p; invalid problem object\n", P); m = P->m, n = P->n; if (!(P->pbs_stat == GLP_FEAS && P->dbs_stat == GLP_FEAS)) xerror("glp_analyze_coef: optimal basic solution required\n"); if (!(m == 0 || P->valid)) xerror("glp_analyze_coef: basis factorization required\n"); if (!(1 <= k && k <= m+n)) xerror("glp_analyze_coef: k = %d; variable number out of range" "\n", k); /* retrieve information about the specified basic variable x[k] whose objective coefficient c[k] is to be analyzed */ if (k <= m) { row = P->row[k]; type = row->type; lb = row->lb; ub = row->ub; coef = 0.0; stat = row->stat; x = row->prim; } else { col = P->col[k-m]; type = col->type; lb = col->lb; ub = col->ub; coef = col->coef; stat = col->stat; x = col->prim; } if (stat != GLP_BS) xerror("glp_analyze_coef: k = %d; non-basic variable not allow" "ed\n", k); /* allocate working arrays */ cind = xcalloc(1+m, sizeof(int)); cval = xcalloc(1+m, sizeof(double)); rind = xcalloc(1+n, sizeof(int)); rval = xcalloc(1+n, sizeof(double)); /* compute row of the simplex table corresponding to the basic variable x[k] */ rlen = glp_eval_tab_row(P, k, rind, rval); xassert(0 <= rlen && rlen <= n); /* perform analysis */ for (kase = -1; kase <= +1; kase += 2) { /* kase < 0 means objective coefficient c[k] is decreasing; kase > 0 means objective coefficient c[k] is increasing */ /* note that decreasing c[k] is equivalent to increasing dual variable lambda[k] and vice versa; we need to correctly set the dir flag as required by the routine glp_dual_rtest */ if (P->dir == GLP_MIN) dir = - kase; else if (P->dir == GLP_MAX) dir = + kase; else xassert(P != P); /* use the dual ratio test to determine non-basic variable x[q] whose reduced cost d[q] reaches zero bound first */ rpiv = glp_dual_rtest(P, rlen, rind, rval, dir, 1e-9); if (rpiv == 0) { /* nothing limits changing c[k] */ lim_coef = (kase < 0 ? -DBL_MAX : +DBL_MAX); q = 0; /* x[k] keeps its current value */ new_x = x; goto store; } /* non-basic variable x[q] limits changing coefficient c[k]; determine its status and reduced cost d[k] in the current basis */ xassert(1 <= rpiv && rpiv <= rlen); q = rind[rpiv]; xassert(1 <= q && q <= m+n); if (q <= m) { row = P->row[q]; stat = row->stat; d = row->dual; } else { col = P->col[q-m]; stat = col->stat; d = col->dual; } /* note that delta d[q] = new d[q] - d[q] = - d[q], because new d[q] = 0; delta d[q] = alfa[k,q] * delta c[k], so delta c[k] = delta d[q] / alfa[k,q] = - d[q] / alfa[k,q] */ xassert(rval[rpiv] != 0.0); delta = - d / rval[rpiv]; /* compute new c[k] = c[k] + delta c[k], which is the limiting value of the objective coefficient c[k] */ lim_coef = coef + delta; /* let c[k] continue decreasing/increasing that makes d[q] dual infeasible and forces x[q] to enter the basis; to perform the primal ratio test we need to know in which direction x[q] changes on entering the basis; we determine that analyzing the sign of delta d[q] (see above), since d[q] may be close to zero having wrong sign */ /* let, for simplicity, the problem is minimization */ if (kase < 0 && rval[rpiv] > 0.0 || kase > 0 && rval[rpiv] < 0.0) { /* delta d[q] < 0, so d[q] being non-negative will become negative, so x[q] will increase */ dir = +1; } else { /* delta d[q] > 0, so d[q] being non-positive will become positive, so x[q] will decrease */ dir = -1; } /* if the problem is maximization, correct the direction */ if (P->dir == GLP_MAX) dir = - dir; /* check that we didn't make a silly mistake */ if (dir > 0) xassert(stat == GLP_NL || stat == GLP_NF); else xassert(stat == GLP_NU || stat == GLP_NF); /* compute column of the simplex table corresponding to the non-basic variable x[q] */ clen = glp_eval_tab_col(P, q, cind, cval); /* make x[k] temporarily free (unbounded) */ if (k <= m) { row = P->row[k]; row->type = GLP_FR; row->lb = row->ub = 0.0; } else { col = P->col[k-m]; col->type = GLP_FR; col->lb = col->ub = 0.0; } /* use the primal ratio test to determine some basic variable which leaves the basis */ cpiv = glp_prim_rtest(P, clen, cind, cval, dir, 1e-9); /* restore original bounds of the basic variable x[k] */ if (k <= m) { row = P->row[k]; row->type = type; row->lb = lb, row->ub = ub; } else { col = P->col[k-m]; col->type = type; col->lb = lb, col->ub = ub; } if (cpiv == 0) { /* non-basic variable x[q] can change unlimitedly */ if (dir < 0 && rval[rpiv] > 0.0 || dir > 0 && rval[rpiv] < 0.0) { /* delta x[k] = alfa[k,q] * delta x[q] < 0 */ new_x = -DBL_MAX; } else { /* delta x[k] = alfa[k,q] * delta x[q] > 0 */ new_x = +DBL_MAX; } goto store; } /* some basic variable x[p] limits changing non-basic variable x[q] in the adjacent basis */ xassert(1 <= cpiv && cpiv <= clen); p = cind[cpiv]; xassert(1 <= p && p <= m+n); xassert(p != k); if (p <= m) { row = P->row[p]; xassert(row->stat == GLP_BS); ll = glp_get_row_lb(P, row->i); uu = glp_get_row_ub(P, row->i); xx = row->prim; } else { col = P->col[p-m]; xassert(col->stat == GLP_BS); ll = glp_get_col_lb(P, col->j); uu = glp_get_col_ub(P, col->j); xx = col->prim; } /* determine delta x[p] = new x[p] - x[p] */ if (dir < 0 && cval[cpiv] > 0.0 || dir > 0 && cval[cpiv] < 0.0) { /* delta x[p] < 0, so x[p] goes toward its lower bound */ xassert(ll != -DBL_MAX); delta = ll - xx; } else { /* delta x[p] > 0, so x[p] goes toward its upper bound */ xassert(uu != +DBL_MAX); delta = uu - xx; } /* compute new x[k] = x[k] + alfa[k,q] * delta x[q], where delta x[q] = delta x[p] / alfa[p,q] */ xassert(cval[cpiv] != 0.0); new_x = x + (rval[rpiv] / cval[cpiv]) * delta; store: /* store analysis results */ if (kase < 0) { if (coef1 != NULL) *coef1 = lim_coef; if (var1 != NULL) *var1 = q; if (value1 != NULL) *value1 = new_x; } else { if (coef2 != NULL) *coef2 = lim_coef; if (var2 != NULL) *var2 = q; if (value2 != NULL) *value2 = new_x; } } /* free working arrays */ xfree(cind); xfree(cval); xfree(rind); xfree(rval); return; } /* eof */ Rglpk/src/GLPK/glpios10.c0000644000176000001440000003003412245352174014514 0ustar ripleyusers/* glpios10.c (feasibility pump heuristic) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpios.h" #include "rng.h" /*********************************************************************** * NAME * * ios_feas_pump - feasibility pump heuristic * * SYNOPSIS * * #include "glpios.h" * void ios_feas_pump(glp_tree *T); * * DESCRIPTION * * The routine ios_feas_pump is a simple implementation of the Feasi- * bility Pump heuristic. * * REFERENCES * * M.Fischetti, F.Glover, and A.Lodi. "The feasibility pump." Math. * Program., Ser. A 104, pp. 91-104 (2005). */ struct VAR { /* binary variable */ int j; /* ordinal number */ int x; /* value in the rounded solution (0 or 1) */ double d; /* sorting key */ }; static int fcmp(const void *x, const void *y) { /* comparison routine */ const struct VAR *vx = x, *vy = y; if (vx->d > vy->d) return -1; else if (vx->d < vy->d) return +1; else return 0; } void ios_feas_pump(glp_tree *T) { glp_prob *P = T->mip; int n = P->n; glp_prob *lp = NULL; struct VAR *var = NULL; RNG *rand = NULL; GLPCOL *col; glp_smcp parm; int j, k, new_x, nfail, npass, nv, ret, stalling; double dist, tol; xassert(glp_get_status(P) == GLP_OPT); /* this heuristic is applied only once on the root level */ if (!(T->curr->level == 0 && T->curr->solved == 1)) goto done; /* determine number of binary variables */ nv = 0; for (j = 1; j <= n; j++) { col = P->col[j]; /* if x[j] is continuous, skip it */ if (col->kind == GLP_CV) continue; /* if x[j] is fixed, skip it */ if (col->type == GLP_FX) continue; /* x[j] is non-fixed integer */ xassert(col->kind == GLP_IV); if (col->type == GLP_DB && col->lb == 0.0 && col->ub == 1.0) { /* x[j] is binary */ nv++; } else { /* x[j] is general integer */ if (T->parm->msg_lev >= GLP_MSG_ALL) xprintf("FPUMP heuristic cannot be applied due to genera" "l integer variables\n"); goto done; } } /* there must be at least one binary variable */ if (nv == 0) goto done; if (T->parm->msg_lev >= GLP_MSG_ALL) xprintf("Applying FPUMP heuristic...\n"); /* build the list of binary variables */ var = xcalloc(1+nv, sizeof(struct VAR)); k = 0; for (j = 1; j <= n; j++) { col = P->col[j]; if (col->kind == GLP_IV && col->type == GLP_DB) var[++k].j = j; } xassert(k == nv); /* create working problem object */ lp = glp_create_prob(); more: /* copy the original problem object to keep it intact */ glp_copy_prob(lp, P, GLP_OFF); /* we are interested to find an integer feasible solution, which is better than the best known one */ if (P->mip_stat == GLP_FEAS) { int *ind; double *val, bnd; /* add a row and make it identical to the objective row */ glp_add_rows(lp, 1); ind = xcalloc(1+n, sizeof(int)); val = xcalloc(1+n, sizeof(double)); for (j = 1; j <= n; j++) { ind[j] = j; val[j] = P->col[j]->coef; } glp_set_mat_row(lp, lp->m, n, ind, val); xfree(ind); xfree(val); /* introduce upper (minimization) or lower (maximization) bound to the original objective function; note that this additional constraint is not violated at the optimal point to LP relaxation */ #if 0 /* modified by xypron */ if (P->dir == GLP_MIN) { bnd = P->mip_obj - 0.10 * (1.0 + fabs(P->mip_obj)); if (bnd < P->obj_val) bnd = P->obj_val; glp_set_row_bnds(lp, lp->m, GLP_UP, 0.0, bnd - P->c0); } else if (P->dir == GLP_MAX) { bnd = P->mip_obj + 0.10 * (1.0 + fabs(P->mip_obj)); if (bnd > P->obj_val) bnd = P->obj_val; glp_set_row_bnds(lp, lp->m, GLP_LO, bnd - P->c0, 0.0); } else xassert(P != P); #else bnd = 0.1 * P->obj_val + 0.9 * P->mip_obj; /* xprintf("bnd = %f\n", bnd); */ if (P->dir == GLP_MIN) glp_set_row_bnds(lp, lp->m, GLP_UP, 0.0, bnd - P->c0); else if (P->dir == GLP_MAX) glp_set_row_bnds(lp, lp->m, GLP_LO, bnd - P->c0, 0.0); else xassert(P != P); #endif } /* reset pass count */ npass = 0; /* invalidate the rounded point */ for (k = 1; k <= nv; k++) var[k].x = -1; pass: /* next pass starts here */ npass++; if (T->parm->msg_lev >= GLP_MSG_ALL) xprintf("Pass %d\n", npass); /* initialize minimal distance between the basic point and the rounded one obtained during this pass */ dist = DBL_MAX; /* reset failure count (the number of succeeded iterations failed to improve the distance) */ nfail = 0; /* if it is not the first pass, perturb the last rounded point rather than construct it from the basic solution */ if (npass > 1) { double rho, temp; if (rand == NULL) rand = rng_create_rand(); for (k = 1; k <= nv; k++) { j = var[k].j; col = lp->col[j]; rho = rng_uniform(rand, -0.3, 0.7); if (rho < 0.0) rho = 0.0; temp = fabs((double)var[k].x - col->prim); if (temp + rho > 0.5) var[k].x = 1 - var[k].x; } goto skip; } loop: /* innermost loop begins here */ /* round basic solution (which is assumed primal feasible) */ stalling = 1; for (k = 1; k <= nv; k++) { col = lp->col[var[k].j]; if (col->prim < 0.5) { /* rounded value is 0 */ new_x = 0; } else { /* rounded value is 1 */ new_x = 1; } if (var[k].x != new_x) { stalling = 0; var[k].x = new_x; } } /* if the rounded point has not changed (stalling), choose and flip some its entries heuristically */ if (stalling) { /* compute d[j] = |x[j] - round(x[j])| */ for (k = 1; k <= nv; k++) { col = lp->col[var[k].j]; var[k].d = fabs(col->prim - (double)var[k].x); } /* sort the list of binary variables by descending d[j] */ qsort(&var[1], nv, sizeof(struct VAR), fcmp); /* choose and flip some rounded components */ for (k = 1; k <= nv; k++) { if (k >= 5 && var[k].d < 0.35 || k >= 10) break; var[k].x = 1 - var[k].x; } } skip: /* check if the time limit has been exhausted */ if (T->parm->tm_lim < INT_MAX && (double)(T->parm->tm_lim - 1) <= 1000.0 * xdifftime(xtime(), T->tm_beg)) goto done; /* build the objective, which is the distance between the current (basic) point and the rounded one */ lp->dir = GLP_MIN; lp->c0 = 0.0; for (j = 1; j <= n; j++) lp->col[j]->coef = 0.0; for (k = 1; k <= nv; k++) { j = var[k].j; if (var[k].x == 0) lp->col[j]->coef = +1.0; else { lp->col[j]->coef = -1.0; lp->c0 += 1.0; } } /* minimize the distance with the simplex method */ glp_init_smcp(&parm); if (T->parm->msg_lev <= GLP_MSG_ERR) parm.msg_lev = T->parm->msg_lev; else if (T->parm->msg_lev <= GLP_MSG_ALL) { parm.msg_lev = GLP_MSG_ON; parm.out_dly = 10000; } ret = glp_simplex(lp, &parm); if (ret != 0) { if (T->parm->msg_lev >= GLP_MSG_ERR) xprintf("Warning: glp_simplex returned %d\n", ret); goto done; } ret = glp_get_status(lp); if (ret != GLP_OPT) { if (T->parm->msg_lev >= GLP_MSG_ERR) xprintf("Warning: glp_get_status returned %d\n", ret); goto done; } if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("delta = %g\n", lp->obj_val); /* check if the basic solution is integer feasible; note that it may be so even if the minimial distance is positive */ tol = 0.3 * T->parm->tol_int; for (k = 1; k <= nv; k++) { col = lp->col[var[k].j]; if (tol < col->prim && col->prim < 1.0 - tol) break; } if (k > nv) { /* okay; the basic solution seems to be integer feasible */ double *x = xcalloc(1+n, sizeof(double)); for (j = 1; j <= n; j++) { x[j] = lp->col[j]->prim; if (P->col[j]->kind == GLP_IV) x[j] = floor(x[j] + 0.5); } #if 1 /* modified by xypron */ /* reset direction and right-hand side of objective */ lp->c0 = P->c0; lp->dir = P->dir; /* fix integer variables */ for (k = 1; k <= nv; k++) #if 0 /* 18/VI-2013; fixed by mao * this bug causes numerical instability, because column statuses * are not changed appropriately */ { lp->col[var[k].j]->lb = x[var[k].j]; lp->col[var[k].j]->ub = x[var[k].j]; lp->col[var[k].j]->type = GLP_FX; } #else glp_set_col_bnds(lp, var[k].j, GLP_FX, x[var[k].j], 0.); #endif /* copy original objective function */ for (j = 1; j <= n; j++) lp->col[j]->coef = P->col[j]->coef; /* solve original LP and copy result */ ret = glp_simplex(lp, &parm); if (ret != 0) { if (T->parm->msg_lev >= GLP_MSG_ERR) xprintf("Warning: glp_simplex returned %d\n", ret); goto done; } ret = glp_get_status(lp); if (ret != GLP_OPT) { if (T->parm->msg_lev >= GLP_MSG_ERR) xprintf("Warning: glp_get_status returned %d\n", ret); goto done; } for (j = 1; j <= n; j++) if (P->col[j]->kind != GLP_IV) x[j] = lp->col[j]->prim; #endif ret = glp_ios_heur_sol(T, x); xfree(x); if (ret == 0) { /* the integer solution is accepted */ if (ios_is_hopeful(T, T->curr->bound)) { /* it is reasonable to apply the heuristic once again */ goto more; } else { /* the best known integer feasible solution just found is close to optimal solution to LP relaxation */ goto done; } } } /* the basic solution is fractional */ if (dist == DBL_MAX || lp->obj_val <= dist - 1e-6 * (1.0 + dist)) { /* the distance is reducing */ nfail = 0, dist = lp->obj_val; } else { /* improving the distance failed */ nfail++; } if (nfail < 3) goto loop; if (npass < 5) goto pass; done: /* delete working objects */ if (lp != NULL) glp_delete_prob(lp); if (var != NULL) xfree(var); if (rand != NULL) rng_delete_rand(rand); return; } /* eof */ Rglpk/src/GLPK/proxy/0000755000176000001440000000000012175147600014071 5ustar ripleyusersRglpk/src/GLPK/proxy/proxy.c0000644000176000001440000010315412245352174015424 0ustar ripleyusers/* proxy.c (proximity search heuristic algorithm) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Author: Giorgio Sartor <0gioker0@gmail.com>. * * Copyright (C) 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . * ************************************************************************ * * THIS CODE IS AN IMPLEMENTATION OF THE ALGORITHM PROPOSED IN * * M. Fischetti, M. Monaci, * "Proximity Search for 0-1 Mixed-Integer Convex Programming" * Technical Report DEI, University of Padua, March 2013. * * AVAILABLE AT * http://www.dei.unipd.it/~fisch/papers/proximity_search.pdf * * THE CODE HAS BEEN WRITTEN BY GIORGIO SARTOR, " 0gioker0@gmail.com " * * BASIC IDEA: * * The initial feasible solution x_tilde is defined. This initial * solution can be found by an ad-hoc heuristic and proxy can be used to * refine it by exploiting an underlying MIP model whose solution from * scratch turned out to be problematic. Otherwise, x_tilde can be found * by running the GLPK mip solver until a first feasible solution is * found, setting a conservative time limit of 10 minutes (by default). * Time limit can be modified passing variable tlim [ms]. * * Then the cutoff tolerance "delta" is defined. The default tolerance * is 1% of the last feasible solution obj value--rounded to integer if * all the variables and obj coefficients are integer. * * Next, the objective function c' x is replaced by the Hamming distance * between x (the actual obj coefficients) and x_tilde (the given * solution). Distance is only computed wrt the binary variables. * * The GLPK solver is then invoked to hopefully find a new incumbent * x_star with cost c' x_star <= c' x_tilde - delta. A crucial property * here is that the root-node solution of the LP relaxation is expected * to be not too different from x_tilde, as this latter solution would * be optimal without the cutoff constraint, that for a small delta can * typically be fulfilled with just local adjustments. * * If no new solution x_star is found within the time limit the * algorithm stops. Of course, if the MIP solver proved infeasibility * for the given delta, we have that c' x_tilde - delta is a valid lower * bound (in case of minimazation) on the optimal value of the original * MIP. * * The new solution x_star, if any, is possibly improved by solving a * simplified problem (refinement) where all binary variables have been * fixed to their value in x_star so as to find the best solution within * the neighborhood. * * Finally, the approach is reapplied on x_star (that replaces x_tilde) * so as to recenter the distance Hamming function and by modifying the * cutoff tolerance delta. * * In this way, there will be a series of hopefully not-too-difficult * sub-MIPs to solve, each leading to an improvement of the incumbent. * More aggressive policies on the definition of tolerance delta can * lead to a better performance, but would require an ad-hoc tuning. * ************************************************************************ * * int proxy(glp_prob *lp, double *zstar, double *xstar, * const double[] initsol, double rel_impr, int tlim, * int verbose) * * lp : GLPK problem pointer to a MIP with binary variables * * zstar : the value of objective function of the best solution found * * xstar : best solution with components xstar[1],...,xstar[ncols] * * initsol : pointer to a initial feasible solution, see * glp_ios_heur_sol * If initsol = NULL, the procedure finds the first solution * by itself. * * rel_impr : minimum relative obj improvement to be achieved at each * internal step; if <= 0.0 a default value of 0.01 (1%) is * used; for some problems (e.g., set covering with small * integer costs) a more-conservative choice of 0.001 (0.1%) * can lead to a better final solution; values larger than * 0.05 (5%) are typically too aggressive and do not work * well. * * tlim : time limit to find a new solution, in ms. * If tlim = 0, it is set to its default value, 600000 ms * * verbose : if 1 the output is activated. If 0 only errors are * displayed * * The procedure returns -1 if an error occurred, 0 otherwise (possibly, * time limit) * ***********************************************************************/ /**********************************************************************/ /* 1. INCLUDE */ /**********************************************************************/ #include "glpk.h" #include "env.h" #include "proxy.h" /**********************************************************************/ /* 2. PARAMETERS AND CONSTANTS */ /**********************************************************************/ #define TDAY 86400.0 #define TRUE 1 #define FALSE 0 #define EPS 1e-6 #define RINF 1e38 #define MAXVAL 1e20 #define MINVAL -1e20 /**********************************************************************/ /* 3. GLOBAL VARIABLES */ /**********************************************************************/ struct csa { int integer_obj; /* TRUE if each feasible solution has an integral cost */ int b_vars_exist; /* TRUE if there is at least one binary variable in the problem */ int i_vars_exist; /* TRUE if there is at least one general integer variable in the problem */ const double *startsol; /* Pointer to the initial solution */ int *ckind; /* Store the kind of the structural variables of the problem */ double *clb; /* Store the lower bound on the structural variables of the problem */ double *cub; /* Store the upper bound on the structural variables of the problem */ double *true_obj; /* Store the obj coefficients of the problem */ int dir; /* Minimization or maximization problem */ int ncols; /* Number of structural variables of the problem */ time_t GLOtstart; /* starting time of the algorithm */ glp_prob *lp_ref; /* glp problem for refining only*/ }; /**********************************************************************/ /* 4. FUNCTIONS PROTOTYPES */ /**********************************************************************/ static void callback(glp_tree *tree, void *info); static void get_info(struct csa *csa, glp_prob *lp); static int is_integer(struct csa *csa); static void check_integrality(struct csa *csa); static int check_ref(struct csa *csa, glp_prob *lp, double *xref); static double second(void); static int add_cutoff(struct csa *csa, glp_prob *lp); static void get_sol(struct csa *csa, glp_prob *lp, double *xstar); static double elapsed_time(struct csa *csa); static void redefine_obj(glp_prob *lp, double *xtilde, int ncols, int *ckind, double *clb, double *cub); static double update_cutoff(struct csa *csa, glp_prob *lp, double zstar, int index, double rel_impr); static double compute_delta(struct csa *csa, double z, double rel_impr); static double objval(int ncols, double *x, double *true_obj); static void array_copy(int begin, int end, double *source, double *destination); static int do_refine(struct csa *csa, glp_prob *lp_ref, int ncols, int *ckind, double *xref, int *tlim, int tref_lim, int verbose); static void deallocate(struct csa *csa, int refine); /**********************************************************************/ /* 5. FUNCTIONS */ /**********************************************************************/ int proxy(glp_prob *lp, double *zfinal, double *xfinal, const double initsol[], double rel_impr, int tlim, int verbose) { struct csa csa_, *csa = &csa_; glp_iocp parm; glp_smcp parm_lp; size_t tpeak; int refine, tref_lim, err, cutoff_row, niter, status, i, tout; double *xref, *xstar, zstar, tela, cutoff, zz; memset(csa, 0, sizeof(struct csa)); /********** **********/ /********** RETRIEVING PROBLEM INFO **********/ /********** **********/ /* getting problem direction (min or max) */ csa->dir = glp_get_obj_dir(lp); /* getting number of variables */ csa->ncols = glp_get_num_cols(lp); /* getting kind, bounds and obj coefficient of each variable information is stored in ckind, cub, clb, true_obj */ get_info(csa, lp); /* checking if the objective function is always integral */ check_integrality(csa); /* Proximity search cannot be used if there are no binary variables */ if (csa->b_vars_exist == FALSE) { if (verbose) { xprintf("The problem has not binary variables. Proximity se" "arch cannot be used.\n"); } tfree(csa->ckind); tfree(csa->clb); tfree(csa->cub); tfree(csa->true_obj); return -1; } /* checking if the problem needs refinement, i.e., not all variables are binary. If so, the routine creates a copy of the lp problem named lp_ref and initializes the solution xref to zero. */ xref = talloc(csa->ncols+1, double); #if 0 /* by mao */ memset(xref, 0, sizeof(double)*(csa->ncols+1)); #endif refine = check_ref(csa, lp, xref); #ifdef PROXY_DEBUG xprintf("REFINE = %d\n",refine); #endif /* Initializing the solution */ xstar = talloc(csa->ncols+1, double); #if 0 /* by mao */ memset(xstar, 0, sizeof(double)*(csa->ncols+1)); #endif /********** **********/ /********** FINDING FIRST SOLUTION **********/ /********** **********/ if (verbose) { xprintf("Applying PROXY heuristic...\n"); } /* get the initial time */ csa->GLOtstart = second(); /* setting the optimization parameters */ glp_init_iocp(&parm); glp_init_smcp(&parm_lp); #if 0 /* by gioker */ /* Preprocessing should be disabled because the mip passed to proxy is already preprocessed */ parm.presolve = GLP_ON; #endif #if 1 /* by mao */ /* best projection backtracking seems to be more efficient to find any integer feasible solution */ parm.bt_tech = GLP_BT_BPH; #endif /* Setting the default value of the minimum relative improvement to 1% */ if ( rel_impr <= 0.0 ) { rel_impr = 0.01; } /* Setting the default value of time limit to 10 minutes */ if (tlim <= 0) { tlim = INT_MAX; } if (verbose) { xprintf("Proxy's time limit set to %d seconds.\n",tlim/1000); xprintf("Proxy's relative improvement " "set to %2.2lf %c.\n",rel_impr*100,37); } parm_lp.tm_lim = tlim; parm.mip_gap = 9999999.9; /* to stop the optimization at the first feasible solution found */ /* finding the first solution */ if (verbose) { xprintf("Searching for a feasible solution...\n"); } /* verifying the existence of an input starting solution */ if (initsol != NULL) { csa->startsol = initsol; parm.cb_func = callback; parm.cb_info = csa; if (verbose) { xprintf("Input solution found.\n"); } } tout = glp_term_out(GLP_OFF); err = glp_simplex(lp,&parm_lp); glp_term_out(tout); status = glp_get_status(lp); if (status != GLP_OPT) { if (verbose) { xprintf("Proxy heuristic terminated.\n"); } #ifdef PROXY_DEBUG /* For debug only */ xprintf("GLP_SIMPLEX status = %d\n",status); xprintf("GLP_SIMPLEX error code = %d\n",err); #endif tfree(xref); tfree(xstar); deallocate(csa, refine); return -1; } tela = elapsed_time(csa); if (tlim-tela*1000 <= 0) { if (verbose) { xprintf("Time limit exceeded. Proxy could not " "find optimal solution to LP relaxation.\n"); xprintf("Proxy heuristic aborted.\n"); } tfree(xref); tfree(xstar); deallocate(csa, refine); return -1; } parm.tm_lim = tlim - tela*1000; tref_lim = (tlim - tela *1000) / 20; tout = glp_term_out(GLP_OFF); err = glp_intopt(lp, &parm); glp_term_out(tout); status = glp_mip_status(lp); /***** If no solution was found *****/ if (status == GLP_NOFEAS || status == GLP_UNDEF) { if (err == GLP_ETMLIM) { if (verbose) { xprintf("Time limit exceeded. Proxy could not " "find an initial integer feasible solution.\n"); xprintf("Proxy heuristic aborted.\n"); } } else { if (verbose) { xprintf("Proxy could not " "find an initial integer feasible solution.\n"); xprintf("Proxy heuristic aborted.\n"); } } tfree(xref); tfree(xstar); deallocate(csa, refine); return -1; } /* getting the first solution and its value */ get_sol(csa, lp,xstar); zstar = glp_mip_obj_val(lp); if (verbose) { xprintf(">>>>> first solution = %e;\n", zstar); } /* If a feasible solution was found but the time limit is exceeded */ if (err == GLP_ETMLIM) { if (verbose) { xprintf("Time limit exceeded. Proxy heuristic terminated.\n"); } goto done; } tela = elapsed_time(csa); tpeak = 0; glp_mem_usage(NULL, NULL, NULL, &tpeak); if (verbose) { xprintf("Time used: %3.1lf secs. Memory used: %2.1lf Mb\n", tela,(double)tpeak/1048576); xprintf("Starting proximity search...\n"); } /********** **********/ /********** PREPARING THE PROBLEM FOR PROXY **********/ /********** **********/ /* adding a dummy cutoff constraint */ cutoff_row = add_cutoff(csa, lp); /* proximity search needs minimization direction even if the problem is a maximization one */ if (csa->dir == GLP_MAX) { glp_set_obj_dir(lp, GLP_MIN); } /********** **********/ /********** STARTING PROXIMITY SEARCH **********/ /********** **********/ niter = 0; while (TRUE) { niter++; /********** CHANGING THE OBJ FUNCTION **********/ redefine_obj(lp,xstar, csa->ncols, csa->ckind, csa->clb, csa->cub); /********** UPDATING THE CUTOFF CONSTRAINT **********/ cutoff = update_cutoff(csa, lp,zstar, cutoff_row, rel_impr); #ifdef PROXY_DEBUG xprintf("TRUE_OBJ[0] = %f\n",csa->true_obj[0]); xprintf("ZSTAR = %f\n",zstar); xprintf("CUTOFF = %f\n",cutoff); #endif /********** SEARCHING FOR A BETTER SOLUTION **********/ tela = elapsed_time(csa); if (tlim-tela*1000 <= 0) { if (verbose) { xprintf("Time limit exceeded. Proxy heuristic " "terminated.\n"); } goto done; } parm_lp.tm_lim = tlim -tela*1000; tout = glp_term_out(GLP_OFF); err = glp_simplex(lp,&parm_lp); glp_term_out(tout); status = glp_get_status(lp); if (status != GLP_OPT) { if (status == GLP_NOFEAS) { if (verbose) { xprintf("Bound exceeded = %f. ",cutoff); } } if (verbose) { xprintf("Proxy heuristic terminated.\n"); } #ifdef PROXY_DEBUG xprintf("GLP_SIMPLEX status = %d\n",status); xprintf("GLP_SIMPLEX error code = %d\n",err); #endif goto done; } tela = elapsed_time(csa); if (tlim-tela*1000 <= 0) { if (verbose) { xprintf("Time limit exceeded. Proxy heuristic " "terminated.\n"); } goto done; } parm.tm_lim = tlim - tela*1000; parm.cb_func = NULL; #if 0 /* by gioker */ /* Preprocessing should be disabled because the mip passed to proxy is already preprocessed */ parm.presolve = GLP_ON; #endif tout = glp_term_out(GLP_OFF); err = glp_intopt(lp, &parm); glp_term_out(tout); /********** MANAGEMENT OF THE SOLUTION **********/ status = glp_mip_status(lp); /***** No feasible solutions *****/ if (status == GLP_NOFEAS) { if (verbose) { xprintf("Bound exceeded = %f. Proxy heuristic " "terminated.\n",cutoff); } goto done; } /***** Undefined solution *****/ if (status == GLP_UNDEF) { if (err == GLP_ETMLIM) { if (verbose) { xprintf("Time limit exceeded. Proxy heuristic " "terminated.\n"); } } else { if (verbose) { xprintf("Proxy terminated unexpectedly.\n"); #ifdef PROXY_DEBUG xprintf("GLP_INTOPT error code = %d\n",err); #endif } } goto done; } /***** Feasible solution *****/ if ((status == GLP_FEAS) || (status == GLP_OPT)) { /* getting the solution and computing its value */ get_sol(csa, lp,xstar); zz = objval(csa->ncols, xstar, csa->true_obj); /* Comparing the incumbent solution with the current best one */ #ifdef PROXY_DEBUG xprintf("ZZ = %f\n",zz); xprintf("ZSTAR = %f\n",zstar); xprintf("REFINE = %d\n",refine); #endif if (((zzdir == GLP_MIN)) || ((zz>zstar) && (csa->dir == GLP_MAX))) { /* refining (possibly) the solution */ if (refine) { /* copying the incumbent solution in the refinement one */ array_copy(1, csa->ncols +1, xstar, xref); err = do_refine(csa, csa->lp_ref, csa->ncols, csa->ckind, xref, &tlim, tref_lim, verbose); if (!err) { double zref = objval(csa->ncols, xref, csa->true_obj); if (((zrefdir == GLP_MIN)) || ((zref>zz) && (csa->dir == GLP_MAX))) { zz = zref; /* copying the refinement solution in the incumbent one */ array_copy(1, csa->ncols +1, xref, xstar); } } } zstar = zz; tela = elapsed_time(csa); if (verbose) { xprintf(">>>>> it: %3d: mip = %e; elapsed time " "%3.1lf sec.s\n", niter,zstar,tela); } } } } done: tela = elapsed_time(csa); glp_mem_usage(NULL, NULL, NULL, &tpeak); if (verbose) { xprintf("Time used: %3.1lf. Memory used: %2.1lf Mb\n", tela,(double)tpeak/1048576); } /* Exporting solution and obj val */ *zfinal = zstar; for (i=1; i < (csa->ncols + 1); i++) { xfinal[i]=xstar[i]; } /* Freeing allocated memory */ tfree(xref); tfree(xstar); deallocate(csa, refine); return 0; } /**********************************************************************/ static void callback(glp_tree *tree, void *info){ /**********************************************************************/ struct csa *csa = info; switch(glp_ios_reason(tree)) { case GLP_IHEUR: glp_ios_heur_sol(tree, csa->startsol); break; default: break; } } /**********************************************************************/ static void get_info(struct csa *csa, glp_prob *lp) /**********************************************************************/ { int i; /* Storing helpful info of the problem */ csa->ckind = talloc(csa->ncols+1, int); #if 0 /* by mao */ memset(csa->ckind, 0, sizeof(int)*(csa->ncols+1)); #endif csa->clb = talloc(csa->ncols+1, double); #if 0 /* by mao */ memset(csa->clb, 0, sizeof(double)*(csa->ncols+1)); #endif csa->cub = talloc(csa->ncols+1, double); #if 0 /* by mao */ memset(csa->cub, 0, sizeof(double)*(csa->ncols+1)); #endif csa->true_obj = talloc(csa->ncols+1, double); #if 0 /* by mao */ memset(csa->true_obj, 0, sizeof(double)*(csa->ncols+1)); #endif for( i = 1 ; i < (csa->ncols + 1); i++ ) { csa->ckind[i] = glp_get_col_kind(lp, i); csa->clb[i] = glp_get_col_lb(lp, i); csa->cub[i] = glp_get_col_ub(lp, i); csa->true_obj[i] = glp_get_obj_coef(lp, i); } csa->true_obj[0] = glp_get_obj_coef(lp, 0); } /**********************************************************************/ static int is_integer(struct csa *csa) /**********************************************************************/ { int i; csa->integer_obj = TRUE; for ( i = 1; i < (csa->ncols + 1); i++ ) { if (fabs(csa->true_obj[i]) > INT_MAX ) { csa->integer_obj = FALSE; } if (fabs(csa->true_obj[i]) <= INT_MAX) { double tmp, rem; if (fabs(csa->true_obj[i]) - floor(fabs(csa->true_obj[i])) < 0.5) { tmp = floor(fabs(csa->true_obj[i])); } else { tmp = ceil(fabs(csa->true_obj[i])); } rem = fabs(csa->true_obj[i]) - tmp; rem = fabs(rem); if (rem > EPS) { csa->integer_obj = FALSE; } } } return csa->integer_obj; } /**********************************************************************/ static void check_integrality(struct csa *csa) /**********************************************************************/ { /* Checking if the problem has binary, integer or continuos variables. integer_obj is TRUE if the problem has no continuous variables and all the obj coefficients are integer (and < INT_MAX). */ int i; csa->integer_obj = is_integer(csa); csa->b_vars_exist = FALSE; csa->i_vars_exist = FALSE; for ( i = 1; i < (csa->ncols + 1); i++ ) { if ( csa->ckind[i] == GLP_IV ){ csa->i_vars_exist = TRUE; continue; } if ( csa->ckind[i] == GLP_BV ){ csa->b_vars_exist =TRUE; continue; } csa->integer_obj = FALSE; } } /**********************************************************************/ static int check_ref(struct csa *csa, glp_prob *lp, double *xref) /**********************************************************************/ { /* checking if the problem has continuos or integer variables. If so, refinement is prepared. */ int refine = FALSE; int i; for ( i = 1; i < (csa->ncols + 1); i++ ) { if ( csa->ckind[i] != GLP_BV) { refine = TRUE; break; } } /* possibly creating a mip clone for refinement only */ if ( refine ) { csa->lp_ref = glp_create_prob(); glp_copy_prob(csa->lp_ref, lp, GLP_ON); } return refine; } /**********************************************************************/ static double second(void) /**********************************************************************/ { #if 0 /* by mao */ return ((double)clock()/(double)CLOCKS_PER_SEC); #else return xtime() / 1000.0; #endif } /**********************************************************************/ static int add_cutoff(struct csa *csa, glp_prob *lp) /**********************************************************************/ { /* Adding a cutoff constraint to set an upper bound (in case of minimaztion) on the obj value of the next solution, i.e., the next value of the true obj function that we would like to find */ /* store non-zero coefficients in the objective function */ int *obj_index = talloc(csa->ncols+1, int); #if 0 /* by mao */ memset(obj_index, 0, sizeof(int)*(csa->ncols+1)); #endif double *obj_value = talloc(csa->ncols+1, double); #if 0 /* by mao */ memset(obj_value, 0, sizeof(double)*(csa->ncols+1)); #endif int obj_nzcnt = 0; int i, irow; const char *rowname; for ( i = 1; i < (csa->ncols + 1); i++ ) { if ( fabs(csa->true_obj[i]) > EPS ) { obj_nzcnt++; obj_index[obj_nzcnt] = i; obj_value[obj_nzcnt] = csa->true_obj[i]; } } irow = glp_add_rows(lp, 1); rowname = "Cutoff"; glp_set_row_name(lp, irow, rowname); if (csa->dir == GLP_MIN) { /* minimization problem */ glp_set_row_bnds(lp, irow, GLP_UP, MAXVAL, MAXVAL); } else { /* maximization problem */ glp_set_row_bnds(lp, irow, GLP_LO, MINVAL, MINVAL); } glp_set_mat_row(lp, irow, obj_nzcnt, obj_index, obj_value); tfree(obj_index); tfree(obj_value); return irow; } /**********************************************************************/ static void get_sol(struct csa *csa, glp_prob *lp, double *xstar) /**********************************************************************/ { /* Retrieving and storing the coefficients of the solution */ int i; for (i = 1; i < (csa->ncols +1); i++) { xstar[i] = glp_mip_col_val(lp, i); } } /**********************************************************************/ static double elapsed_time(struct csa *csa) /**********************************************************************/ { double tela = second() - csa->GLOtstart; if ( tela < 0 ) tela += TDAY; return(tela); } /**********************************************************************/ static void redefine_obj(glp_prob *lp, double *xtilde, int ncols, int *ckind, double *clb, double *cub) /**********************************************************************/ /* Redefine the lp objective function obj as the distance-to-integrality (Hamming distance) from xtilde (the incumbent feasible solution), wrt to binary vars only */ { int j; double *delta = talloc(ncols+1, double); #if 0 /* by mao */ memset(delta, 0, sizeof(double)*(ncols+1)); #endif for ( j = 1; j < (ncols +1); j++ ) { delta[j] = 0.0; /* skip continuous variables */ if ( ckind[j] == GLP_CV ) continue; /* skip integer variables that have been fixed */ if ( cub[j]-clb[j] < 0.5 ) continue; /* binary variable */ if ( ckind[j] == GLP_BV ) { if ( xtilde[j] > 0.5 ) { delta[j] = -1.0; } else { delta[j] = 1.0; } } } /* changing the obj coeff. for all variables, including continuous ones */ for ( j = 1; j < (ncols +1); j++ ) { glp_set_obj_coef(lp, j, delta[j]); } glp_set_obj_coef(lp, 0, 0.0); tfree(delta); } /**********************************************************************/ static double update_cutoff(struct csa *csa, glp_prob *lp, double zstar, int cutoff_row, double rel_impr) /**********************************************************************/ { /* Updating the cutoff constraint with the value we would like to find during the next optimization */ double cutoff; zstar -= csa->true_obj[0]; if (csa->dir == GLP_MIN) { cutoff = zstar - compute_delta(csa, zstar, rel_impr); glp_set_row_bnds(lp, cutoff_row, GLP_UP, cutoff, cutoff); } else { cutoff = zstar + compute_delta(csa, zstar, rel_impr); glp_set_row_bnds(lp, cutoff_row, GLP_LO, cutoff, cutoff); } return cutoff; } /**********************************************************************/ static double compute_delta(struct csa *csa, double z, double rel_impr) /**********************************************************************/ { /* Computing the offset for the next best solution */ double delta = rel_impr * fabs(z); if ( csa->integer_obj ) delta = ceil(delta); return(delta); } /**********************************************************************/ static double objval(int ncols, double *x, double *true_obj) /**********************************************************************/ { /* Computing the true cost of x (using the original obj coeff.s) */ int j; double z = 0.0; for ( j = 1; j < (ncols +1); j++ ) { z += x[j] * true_obj[j]; } return z + true_obj[0]; } /**********************************************************************/ static void array_copy(int begin, int end, double *source, double *destination) /**********************************************************************/ { int i; for (i = begin; i < end; i++) { destination[i] = source[i]; } } /**********************************************************************/ static int do_refine(struct csa *csa, glp_prob *lp_ref, int ncols, int *ckind, double *xref, int *tlim, int tref_lim, int verbose) /**********************************************************************/ { /* Refinement is applied when the variables of the problem are not all binary. Binary variables are fixed to their value and remaining ones are optimized. If there are only continuos variables (in addition to those binary) the problem becomes just an LP. Otherwise, it remains a MIP but of smaller size. */ int j, tout; double refineStart = second(); double val, tela; if ( glp_get_num_cols(lp_ref) != ncols ) { if (verbose) { xprintf("Error in Proxy refinement: "); xprintf("wrong number of columns (%d vs %d).\n", ncols, glp_get_num_cols(lp_ref)); } return 1; } val = -1.0; /* fixing all binary variables to their current value in xref */ for ( j = 1; j < (ncols + 1); j++ ) { if ( ckind[j] == GLP_BV ) { val = 0.0; if ( xref[j] > 0.5 ) val = 1.0; glp_set_col_bnds(lp_ref, j, GLP_FX, val, val); } } /* re-optimizing (refining) if some bound has been changed */ if ( val > -1.0 ) { glp_iocp parm_ref; glp_smcp parm_ref_lp; int err, status; glp_init_iocp(&parm_ref); parm_ref.presolve = GLP_ON; glp_init_smcp(&parm_ref_lp); /* If there are no general integer variable the problem becomes an LP (after fixing the binary variables) and can be solved quickly. Otherwise the problem is still a MIP problem and a timelimit has to be set. */ parm_ref.tm_lim = tref_lim; if (parm_ref.tm_lim > *tlim) { parm_ref.tm_lim = *tlim; } parm_ref_lp.tm_lim = parm_ref.tm_lim; #ifdef PROXY_DEBUG xprintf("***** REFINING *****\n"); #endif tout = glp_term_out(GLP_OFF); if (csa->i_vars_exist == TRUE) { err = glp_intopt(lp_ref, &parm_ref); } else { err = glp_simplex(lp_ref, &parm_ref_lp); } glp_term_out(tout); if (csa->i_vars_exist == TRUE) { status = glp_mip_status(lp_ref); } else { status = glp_get_status(lp_ref); } #ifdef PROXY_DEBUG xprintf("STATUS REFINING = %d\n",status); #endif if (status == GLP_UNDEF) { if (err == GLP_ETMLIM) { #ifdef PROXY_DEBUG xprintf("Time limit exceeded on Proxy refining.\n"); #endif return 1; } } for( j = 1 ; j < (ncols + 1); j++ ){ if (ckind[j] != GLP_BV) { if (csa->i_vars_exist == TRUE) { xref[j] = glp_mip_col_val(lp_ref, j); } else{ xref[j] = glp_get_col_prim(lp_ref, j); } } } } tela = second() - refineStart; *tlim = *tlim - tela*1000; return 0; } /**********************************************************************/ static void deallocate(struct csa *csa, int refine) /**********************************************************************/ { /* Deallocating routine */ if (refine) { glp_delete_prob(csa->lp_ref); } tfree(csa->ckind); tfree(csa->clb); tfree(csa->cub); tfree(csa->true_obj); } /* eof */ Rglpk/src/GLPK/proxy/main.c0000644000176000001440000000405712245352174015171 0ustar ripleyusers/* Last update: 08-May-2013 */ #include #include #include #include "glpk.h" #include "proxy.h" /**********************************************************************/ int main(int argc, char **argv) /**********************************************************************/ { glp_prob *lp; int ncols, status; double *initsol, zstar, *xstar; /* check arguments */ if ( (argc == 1) || (argc > 3) ) { printf("ERROR: Usage: ts <(possibly) xml initsols>\n" ); exit(1); } /* creating the problem */ lp = glp_create_prob(); glp_set_prob_name(lp, "Proxy"); /* reading the problem */ glp_term_out(GLP_OFF); #if 0 /* by mao */ status = glp_read_lp(lp, NULL, argv[1]); #else status = glp_read_mps(lp, GLP_MPS_FILE, NULL, argv[1]); #endif glp_term_out(GLP_ON); if ( status ) { printf("Problem %s does not exist!!!, status %d\n", argv[1], status); exit(1); } ncols = glp_get_num_cols(lp); initsol = (double *) calloc(ncols+1, sizeof(double)); if (argc == 3) { FILE *fp=fopen(argv[2],"r"); char tmp[256]={0x0}; int counter = 1; while(fp!=NULL && fgets(tmp, sizeof(tmp),fp)!=NULL) { char *valini = strstr(tmp, "value"); if (valini!=NULL){ int num; double dnum; valini +=7; sscanf(valini, "%d%*s",&num); dnum = (double)num; initsol[counter] = dnum; counter++; } } fclose(fp); } xstar = (double *) calloc(ncols+1, sizeof(double)); if (argc == 3) { status = proxy(lp, &zstar, xstar, initsol, 0.0, 0, 1); } else { status = proxy(lp, &zstar, xstar, NULL, 0.0, 0, 1); } printf("Status = %d; ZSTAR = %f\n",status,zstar); /* int i; for (i=1; i< ncols+1; i++) { printf("XSTAR[%d] = %f\n",i, xstar[i]); } */ glp_delete_prob(lp); return 0; } Rglpk/src/GLPK/proxy/proxy.h0000644000176000001440000000244412245352174015431 0ustar ripleyusers/* proxy.h (proximity search heuristic algorithm) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Author: Giorgio Sartor <0gioker0@gmail.com>. * * Copyright (C) 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef PROXY_H #define PROXY_H #define proxy _glp_proxy int proxy(glp_prob *lp, double *zstar, double *xstar, const double initsol[], double rel_impr, int tlim, int verbose); #endif /* eof */ Rglpk/src/GLPK/proxy/proxy1.c0000644000176000001440000000206212245352174015501 0ustar ripleyusers/* proxy1.c */ /* (reserved for copyright notice) */ #include "glpios.h" #include "proxy.h" void ios_proxy_heur(glp_tree *T) { glp_prob *prob; int j, status; double *xstar, zstar; /* this heuristic is applied only once on the root level */ if (!(T->curr->level == 0 && T->curr->solved == 1)) goto done; prob = glp_create_prob(); glp_copy_prob(prob, T->mip, 0); xstar = xcalloc(1+prob->n, sizeof(double)); for (j = 1; j <= prob->n; j++) xstar[j] = 0.0; if (T->mip->mip_stat != GLP_FEAS) status = proxy(prob, &zstar, xstar, NULL, 0.0, T->parm->ps_tm_lim, 1); else { double *xinit = xcalloc(1+prob->n, sizeof(double)); for (j = 1; j <= prob->n; j++) xinit[j] = T->mip->col[j]->mipx; status = proxy(prob, &zstar, xstar, xinit, 0.0, T->parm->ps_tm_lim, 1); xfree(xinit); } if (status == 0) glp_ios_heur_sol(T, xstar); xfree(xstar); glp_delete_prob(prob); done: return; } /* eof */ Rglpk/src/GLPK/triang.h0000644000176000001440000000247512245352174014357 0ustar ripleyusers/* triang.h (find maximal triangular part of rectangular matrix) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef TRIANG_H #define TRIANG_H #define triang _glp_triang int triang(int m, int n, int (*mat)(void *info, int k, int ind[], double val[]), void *info, double tol, int rn[], int cn[]); /* find maximal triangular part of rectangular matrix */ #endif /* eof */ Rglpk/src/GLPK/rng1.c0000644000176000001440000000420612245352174013727 0ustar ripleyusers/* rng1.c (pseudo-random number generator) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2003, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #include "rng.h" /*********************************************************************** * NAME * * rng_unif_01 - obtain pseudo-random number in the range [0, 1] * * SYNOPSIS * * #include "rng.h" * double rng_unif_01(RNG *rand); * * RETURNS * * The routine rng_unif_01 returns a next pseudo-random number which is * uniformly distributed in the range [0, 1]. */ double rng_unif_01(RNG *rand) { double x; x = (double)rng_next_rand(rand) / 2147483647.0; xassert(0.0 <= x && x <= 1.0); return x; } /*********************************************************************** * NAME * * rng_uniform - obtain pseudo-random number in the range [a, b] * * SYNOPSIS * * #include "rng.h" * double rng_uniform(RNG *rand, double a, double b); * * RETURNS * * The routine rng_uniform returns a next pseudo-random number which is * uniformly distributed in the range [a, b]. */ double rng_uniform(RNG *rand, double a, double b) { double x; xassert(a < b); x = rng_unif_01(rand); x = a * (1.0 - x) + b * x; xassert(a <= x && x <= b); return x; } /* eof */ Rglpk/src/GLPK/glplpx02.c0000644000176000001440000002377712245352174014546 0ustar ripleyusers/* glplpx02.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpapi.h" /*********************************************************************** * NAME * * lpx_put_solution - store basic solution components * * SYNOPSIS * * void lpx_put_solution(glp_prob *lp, int inval, const int *p_stat, * const int *d_stat, const double *obj_val, const int r_stat[], * const double r_prim[], const double r_dual[], const int c_stat[], * const double c_prim[], const double c_dual[]) * * DESCRIPTION * * The routine lpx_put_solution stores basic solution components to the * specified problem object. * * The parameter inval is the basis factorization invalidity flag. * If this flag is clear, the current status of the basis factorization * remains unchanged. If this flag is set, the routine invalidates the * basis factorization. * * The parameter p_stat is a pointer to the status of primal basic * solution, which should be specified as follows: * * 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. * * If the parameter p_stat is NULL, the current status of primal basic * solution remains unchanged. * * The parameter d_stat is a pointer to the status of dual basic * solution, which should be specified as follows: * * 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. * * If the parameter d_stat is NULL, the current status of dual basic * solution remains unchanged. * * The parameter obj_val is a pointer to the objective function value. * If it is NULL, the current value of the objective function remains * unchanged. * * The array element r_stat[i], 1 <= i <= m (where m is the number of * rows in the problem object), specifies the status of i-th auxiliary * variable, which should be specified as follows: * * 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. * * If the parameter r_stat is NULL, the current statuses of auxiliary * variables remain unchanged. * * The array element r_prim[i], 1 <= i <= m (where m is the number of * rows in the problem object), specifies a primal value of i-th * auxiliary variable. If the parameter r_prim is NULL, the current * primal values of auxiliary variables remain unchanged. * * The array element r_dual[i], 1 <= i <= m (where m is the number of * rows in the problem object), specifies a dual value (reduced cost) * of i-th auxiliary variable. If the parameter r_dual is NULL, the * current dual values of auxiliary variables remain unchanged. * * The array element c_stat[j], 1 <= j <= n (where n is the number of * columns in the problem object), specifies the status of j-th * structural variable, which should be specified as follows: * * 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. * * If the parameter c_stat is NULL, the current statuses of structural * variables remain unchanged. * * The array element c_prim[j], 1 <= j <= n (where n is the number of * columns in the problem object), specifies a primal value of j-th * structural variable. If the parameter c_prim is NULL, the current * primal values of structural variables remain unchanged. * * The array element c_dual[j], 1 <= j <= n (where n is the number of * columns in the problem object), specifies a dual value (reduced cost) * of j-th structural variable. If the parameter c_dual is NULL, the * current dual values of structural variables remain unchanged. */ void lpx_put_solution(glp_prob *lp, int inval, const int *p_stat, const int *d_stat, const double *obj_val, const int r_stat[], const double r_prim[], const double r_dual[], const int c_stat[], const double c_prim[], const double c_dual[]) { GLPROW *row; GLPCOL *col; int i, j; /* invalidate the basis factorization, if required */ if (inval) lp->valid = 0; /* store primal status */ if (p_stat != NULL) { if (!(*p_stat == GLP_UNDEF || *p_stat == GLP_FEAS || *p_stat == GLP_INFEAS || *p_stat == GLP_NOFEAS)) xerror("lpx_put_solution: p_stat = %d; invalid primal statu" "s\n", *p_stat); lp->pbs_stat = *p_stat; } /* store dual status */ if (d_stat != NULL) { if (!(*d_stat == GLP_UNDEF || *d_stat == GLP_FEAS || *d_stat == GLP_INFEAS || *d_stat == GLP_NOFEAS)) xerror("lpx_put_solution: d_stat = %d; invalid dual status " "\n", *d_stat); lp->dbs_stat = *d_stat; } /* store objective function value */ if (obj_val != NULL) lp->obj_val = *obj_val; /* store row solution components */ for (i = 1; i <= lp->m; i++) { row = lp->row[i]; if (r_stat != NULL) { if (!(r_stat[i] == GLP_BS || row->type == GLP_FR && r_stat[i] == GLP_NF || row->type == GLP_LO && r_stat[i] == GLP_NL || row->type == GLP_UP && r_stat[i] == GLP_NU || row->type == GLP_DB && r_stat[i] == GLP_NL || row->type == GLP_DB && r_stat[i] == GLP_NU || row->type == GLP_FX && r_stat[i] == GLP_NS)) xerror("lpx_put_solution: r_stat[%d] = %d; invalid row s" "tatus\n", i, r_stat[i]); row->stat = r_stat[i]; } if (r_prim != NULL) row->prim = r_prim[i]; if (r_dual != NULL) row->dual = r_dual[i]; } /* store column solution components */ for (j = 1; j <= lp->n; j++) { col = lp->col[j]; if (c_stat != NULL) { if (!(c_stat[j] == GLP_BS || col->type == GLP_FR && c_stat[j] == GLP_NF || col->type == GLP_LO && c_stat[j] == GLP_NL || col->type == GLP_UP && c_stat[j] == GLP_NU || col->type == GLP_DB && c_stat[j] == GLP_NL || col->type == GLP_DB && c_stat[j] == GLP_NU || col->type == GLP_FX && c_stat[j] == GLP_NS)) xerror("lpx_put_solution: c_stat[%d] = %d; invalid colum" "n status\n", j, c_stat[j]); col->stat = c_stat[j]; } if (c_prim != NULL) col->prim = c_prim[j]; if (c_dual != NULL) col->dual = c_dual[j]; } return; } /*---------------------------------------------------------------------- -- lpx_put_mip_soln - store mixed integer solution components. -- -- *Synopsis* -- -- #include "glplpx.h" -- void lpx_put_mip_soln(glp_prob *lp, int i_stat, double row_mipx[], -- double col_mipx[]); -- -- *Description* -- -- The routine lpx_put_mip_soln stores solution components obtained by -- branch-and-bound solver into the specified problem object. -- -- NOTE: This routine is intended for internal use only. */ void lpx_put_mip_soln(glp_prob *lp, int i_stat, double row_mipx[], double col_mipx[]) { GLPROW *row; GLPCOL *col; int i, j; double sum; /* store mixed integer status */ #if 0 if (!(i_stat == LPX_I_UNDEF || i_stat == LPX_I_OPT || i_stat == LPX_I_FEAS || i_stat == LPX_I_NOFEAS)) fault("lpx_put_mip_soln: i_stat = %d; invalid mixed integer st" "atus", i_stat); lp->i_stat = i_stat; #else switch (i_stat) { case LPX_I_UNDEF: lp->mip_stat = GLP_UNDEF; break; case LPX_I_OPT: lp->mip_stat = GLP_OPT; break; case LPX_I_FEAS: lp->mip_stat = GLP_FEAS; break; case LPX_I_NOFEAS: lp->mip_stat = GLP_NOFEAS; break; default: xerror("lpx_put_mip_soln: i_stat = %d; invalid mixed intege" "r status\n", i_stat); } #endif /* store row solution components */ if (row_mipx != NULL) { for (i = 1; i <= lp->m; i++) { row = lp->row[i]; row->mipx = row_mipx[i]; } } /* store column solution components */ if (col_mipx != NULL) { for (j = 1; j <= lp->n; j++) { col = lp->col[j]; col->mipx = col_mipx[j]; } } /* if the solution is claimed to be integer feasible, check it */ if (lp->mip_stat == GLP_OPT || lp->mip_stat == GLP_FEAS) { for (j = 1; j <= lp->n; j++) { col = lp->col[j]; if (col->kind == GLP_IV && col->mipx != floor(col->mipx)) xerror("lpx_put_mip_soln: col_mipx[%d] = %.*g; must be i" "ntegral\n", j, DBL_DIG, col->mipx); } } /* compute the objective function value */ sum = lp->c0; for (j = 1; j <= lp->n; j++) { col = lp->col[j]; sum += col->coef * col->mipx; } lp->mip_obj = sum; return; } /* eof */ Rglpk/src/GLPK/minisat/0000755000176000001440000000000012175147600014354 5ustar ripleyusersRglpk/src/GLPK/minisat/minisat.h0000644000176000001440000001617612245352174016206 0ustar ripleyusers/* minisat.h */ /* Modified by Andrew Makhorin , August 2011 */ /*********************************************************************** * MiniSat -- Copyright (c) 2005, Niklas Sorensson * http://www.cs.chalmers.se/Cs/Research/FormalMethods/MiniSat/ * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. ***********************************************************************/ /* Modified to compile with MS Visual Studio 6.0 by Alan Mishchenko */ #ifndef MINISAT_H #define MINISAT_H /*====================================================================*/ /* Simple types: */ typedef int bool; #define true 1 #define false 0 typedef int lit; #if 0 /* by mao */ typedef char lbool; #else typedef int lbool; #endif #define var_Undef (int)(-1) #define lit_Undef (lit)(-2) #define l_Undef (lbool)0 #define l_True (lbool)1 #define l_False (lbool)(-1) #define toLit(v) (lit)((v) + (v)) #define lit_neg(l) (lit)((l) ^ 1) #define lit_var(l) (int)((l) >> 1) #define lit_sign(l) (int)((l) & 1) /*====================================================================*/ /* Vectors: */ /* vector of 32-bit intergers (added for 64-bit portability) */ typedef struct /* veci_t */ { int size; int cap; int* ptr; } veci; #define veci_new(v) \ { (v)->size = 0; \ (v)->cap = 4; \ (v)->ptr = (int*)malloc(sizeof(int)*(v)->cap); \ } #define veci_delete(v) free((v)->ptr) #define veci_begin(v) ((v)->ptr) #define veci_size(v) ((v)->size) #define veci_resize(v, k) (void)((v)->size = (k)) /* only safe to shrink !! */ #define veci_push(v, e) \ { if ((v)->size == (v)->cap) \ { int newsize = (v)->cap * 2+1; \ (v)->ptr = (int*)realloc((v)->ptr,sizeof(int)*newsize); \ (v)->cap = newsize; \ } \ (v)->ptr[(v)->size++] = (e); \ } /* vector of 32- or 64-bit pointers */ typedef struct /* vecp_t */ { int size; int cap; void** ptr; } vecp; #define vecp_new(v) \ { (v)->size = 0; \ (v)->cap = 4; \ (v)->ptr = (void**)malloc(sizeof(void*)*(v)->cap); \ } #define vecp_delete(v) free((v)->ptr) #define vecp_begin(v) ((v)->ptr) #define vecp_size(v) ((v)->size) #define vecp_resize(v, k) (void)((v)->size = (k)) /* only safe to shrink !! */ #define vecp_push(v, e) \ { if ((v)->size == (v)->cap) \ { int newsize = (v)->cap * 2+1; \ (v)->ptr = (void**)realloc((v)->ptr,sizeof(void*)*newsize); \ (v)->cap = newsize; \ } \ (v)->ptr[(v)->size++] = (e); \ } /*====================================================================*/ /* Solver representation: */ typedef struct /* clause_t */ { int size_learnt; lit lits[1]; } clause; typedef struct /* stats_t */ { double starts, decisions, propagations, inspects, conflicts; double clauses, clauses_literals, learnts, learnts_literals, max_literals, tot_literals; } stats; typedef struct /* solver_t */ { int size; /* nof variables */ int cap; /* size of varmaps */ int qhead; /* Head index of queue. */ int qtail; /* Tail index of queue. */ /* clauses */ vecp clauses; /* List of problem constraints. (contains: clause*) */ vecp learnts; /* List of learnt clauses. (contains: clause*) */ /* activities */ double var_inc; /* Amount to bump next variable with. */ double var_decay; /* INVERSE decay factor for variable activity: stores 1/decay. */ float cla_inc; /* Amount to bump next clause with. */ float cla_decay; /* INVERSE decay factor for clause activity: stores 1/decay. */ vecp* wlists; double* activity; /* A heuristic measurement of the activity of a variable. */ lbool* assigns; /* Current values of variables. */ int* orderpos; /* Index in variable order. */ clause** reasons; int* levels; lit* trail; clause* binary; /* A temporary binary clause */ lbool* tags; veci tagged; /* (contains: var) */ veci stack; /* (contains: var) */ veci order; /* Variable order. (heap) (contains: var) */ veci trail_lim; /* Separator indices for different decision levels in 'trail'. (contains: int) */ veci model; /* If problem is solved, this vector contains the model (contains: lbool). */ int root_level; /* Level of first proper decision. */ int simpdb_assigns;/* Number of top-level assignments at last 'simplifyDB()'. */ int simpdb_props; /* Number of propagations before next 'simplifyDB()'. */ double random_seed; double progress_estimate; int verbosity; /* Verbosity level. 0=silent, 1=some progress report, 2=everything */ stats stats; } solver; /*====================================================================*/ /* Public interface: */ #if 1 /* by mao; to keep namespace clean */ #define solver_new _glp_minisat_new #define solver_delete _glp_minisat_delete #define solver_addclause _glp_minisat_addclause #define solver_simplify _glp_minisat_simplify #define solver_solve _glp_minisat_solve #define solver_nvars _glp_minisat_nvars #define solver_nclauses _glp_minisat_nclauses #define solver_nconflicts _glp_minisat_nconflicts #define solver_setnvars _glp_minisat_setnvars #define solver_propagate _glp_minisat_propagate #define solver_reducedb _glp_minisat_reducedb #endif solver* solver_new(void); void solver_delete(solver* s); bool solver_addclause(solver* s, lit* begin, lit* end); bool solver_simplify(solver* s); bool solver_solve(solver* s, lit* begin, lit* end); int solver_nvars(solver* s); int solver_nclauses(solver* s); int solver_nconflicts(solver* s); void solver_setnvars(solver* s,int n); #endif /* eof */ Rglpk/src/GLPK/minisat/README0000644000176000001440000000160712175147600015240 0ustar ripleyusersNOTE: Files in this subdirectory are NOT part of the GLPK package, but are used with GLPK. The original code was modified according to GLPK requirements by Andrew Makhorin . ************************************************************************ MiniSat-C v1.14.1 ======================================== * Fixed some serious bugs. * Tweaked to be Visual Studio friendly (by Alan Mishchenko). This disabled reading of gzipped DIMACS files and signal handling, but none of these features are essential (and easy to re-enable, if wanted). MiniSat-C v1.14 ======================================== Ok, we get it. You hate C++. You hate templates. We agree; C++ is a seriously messed up language. Although we are more pragmatic about the quirks and maldesigns in C++, we sympathize with you. So here is a pure C version of MiniSat, put together by Niklas Sorensson. Rglpk/src/GLPK/minisat/minisat.c0000644000176000001440000011176412245352174016200 0ustar ripleyusers/* minisat.c */ /* Modified by Andrew Makhorin , August 2011 */ /*********************************************************************** * MiniSat -- Copyright (c) 2005, Niklas Sorensson * http://www.cs.chalmers.se/Cs/Research/FormalMethods/MiniSat/ * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. ***********************************************************************/ /* Modified to compile with MS Visual Studio 6.0 by Alan Mishchenko */ #include "env.h" #include "minisat.h" #if 1 /* by mao */ static void *ymalloc(int size) { void *ptr; xassert(size > 0); ptr = malloc(size); if (ptr == NULL) xerror("MiniSat: no memory available\n"); return ptr; } static void *yrealloc(void *ptr, int size) { xassert(size > 0); if (ptr == NULL) ptr = malloc(size); else ptr = realloc(ptr, size); if (ptr == NULL) xerror("MiniSat: no memory available\n"); return ptr; } static void yfree(void *ptr) { xassert(ptr != NULL); free(ptr); return; } #define assert xassert #define printf xprintf #define fflush(f) /* nop */ #define malloc ymalloc #define realloc yrealloc #define free yfree #define inline /* empty */ #endif /*====================================================================*/ /* Debug: */ #if 0 #define VERBOSEDEBUG 1 #endif /* For derivation output (verbosity level 2) */ #define L_IND "%-*d" #define L_ind solver_dlevel(s)*3+3,solver_dlevel(s) #define L_LIT "%sx%d" #define L_lit(p) lit_sign(p)?"~":"", (lit_var(p)) #if 0 /* by mao */ /* Just like 'assert()' but expression will be evaluated in the release version as well. */ static inline void check(int expr) { assert(expr); } #endif #if 0 /* by mao */ static void printlits(lit* begin, lit* end) { int i; for (i = 0; i < end - begin; i++) printf(L_LIT" ",L_lit(begin[i])); } #endif /*====================================================================*/ /* Random numbers: */ /* Returns a random float 0 <= x < 1. Seed must never be 0. */ static inline double drand(double* seed) { int q; *seed *= 1389796; q = (int)(*seed / 2147483647); *seed -= (double)q * 2147483647; return *seed / 2147483647; } /* Returns a random integer 0 <= x < size. Seed must never be 0. */ static inline int irand(double* seed, int size) { return (int)(drand(seed) * size); } /*====================================================================*/ /* Predeclarations: */ static void sort(void** array, int size, int(*comp)(const void *, const void *)); /*====================================================================*/ /* Clause datatype + minor functions: */ #if 0 /* by mao; see minisat.h */ struct clause_t { int size_learnt; lit lits[0]; }; #endif #define clause_size(c) ((c)->size_learnt >> 1) #define clause_begin(c) ((c)->lits) #define clause_learnt(c) ((c)->size_learnt & 1) #define clause_activity(c) \ (*((float*)&(c)->lits[(c)->size_learnt>>1])) #define clause_setactivity(c, a) \ (void)(*((float*)&(c)->lits[(c)->size_learnt>>1]) = (a)) /*====================================================================*/ /* Encode literals in clause pointers: */ #define clause_from_lit(l) \ (clause*)((unsigned long)(l) + (unsigned long)(l) + 1) #define clause_is_lit(c) \ ((unsigned long)(c) & 1) #define clause_read_lit(c) \ (lit)((unsigned long)(c) >> 1) /*====================================================================*/ /* Simple helpers: */ #define solver_dlevel(s) \ (int)veci_size(&(s)->trail_lim) #define solver_read_wlist(s, l) \ (vecp *)(&(s)->wlists[l]) static inline void vecp_remove(vecp* v, void* e) { void** ws = vecp_begin(v); int j = 0; for (; ws[j] != e ; j++); assert(j < vecp_size(v)); for (; j < vecp_size(v)-1; j++) ws[j] = ws[j+1]; vecp_resize(v,vecp_size(v)-1); } /*====================================================================*/ /* Variable order functions: */ static inline void order_update(solver* s, int v) { /* updateorder */ int* orderpos = s->orderpos; double* activity = s->activity; int* heap = veci_begin(&s->order); int i = orderpos[v]; int x = heap[i]; int parent = (i - 1) / 2; assert(s->orderpos[v] != -1); while (i != 0 && activity[x] > activity[heap[parent]]){ heap[i] = heap[parent]; orderpos[heap[i]] = i; i = parent; parent = (i - 1) / 2; } heap[i] = x; orderpos[x] = i; } #define order_assigned(s, v) /* nop */ static inline void order_unassigned(solver* s, int v) { /* undoorder */ int* orderpos = s->orderpos; if (orderpos[v] == -1){ orderpos[v] = veci_size(&s->order); veci_push(&s->order,v); order_update(s,v); } } static int order_select(solver* s, float random_var_freq) { /* selectvar */ int* heap; double* activity; int* orderpos; lbool* values = s->assigns; /* Random decision: */ if (drand(&s->random_seed) < random_var_freq){ int next = irand(&s->random_seed,s->size); assert(next >= 0 && next < s->size); if (values[next] == l_Undef) return next; } /* Activity based decision: */ heap = veci_begin(&s->order); activity = s->activity; orderpos = s->orderpos; while (veci_size(&s->order) > 0){ int next = heap[0]; int size = veci_size(&s->order)-1; int x = heap[size]; veci_resize(&s->order,size); orderpos[next] = -1; if (size > 0){ double act = activity[x]; int i = 0; int child = 1; while (child < size){ if (child+1 < size && activity[heap[child]] < activity[heap[child+1]]) child++; assert(child < size); if (act >= activity[heap[child]]) break; heap[i] = heap[child]; orderpos[heap[i]] = i; i = child; child = 2 * child + 1; } heap[i] = x; orderpos[heap[i]] = i; } if (values[next] == l_Undef) return next; } return var_Undef; } /*====================================================================*/ /* Activity functions: */ static inline void act_var_rescale(solver* s) { double* activity = s->activity; int i; for (i = 0; i < s->size; i++) activity[i] *= 1e-100; s->var_inc *= 1e-100; } static inline void act_var_bump(solver* s, int v) { double* activity = s->activity; if ((activity[v] += s->var_inc) > 1e100) act_var_rescale(s); /* printf("bump %d %f\n", v-1, activity[v]); */ if (s->orderpos[v] != -1) order_update(s,v); } static inline void act_var_decay(solver* s) { s->var_inc *= s->var_decay; } static inline void act_clause_rescale(solver* s) { clause** cs = (clause**)vecp_begin(&s->learnts); int i; for (i = 0; i < vecp_size(&s->learnts); i++){ float a = clause_activity(cs[i]); clause_setactivity(cs[i], a * (float)1e-20); } s->cla_inc *= (float)1e-20; } static inline void act_clause_bump(solver* s, clause *c) { float a = clause_activity(c) + s->cla_inc; clause_setactivity(c,a); if (a > 1e20) act_clause_rescale(s); } static inline void act_clause_decay(solver* s) { s->cla_inc *= s->cla_decay; } /*====================================================================*/ /* Clause functions: */ /* pre: size > 1 && no variable occurs twice */ static clause* clause_new(solver* s, lit* begin, lit* end, int learnt) { int size; clause* c; int i; assert(end - begin > 1); assert(learnt >= 0 && learnt < 2); size = end - begin; c = (clause*)malloc(sizeof(clause) + sizeof(lit) * size + learnt * sizeof(float)); c->size_learnt = (size << 1) | learnt; #if 0 /* by mao; meaningless non-portable check */ assert(((unsigned int)c & 1) == 0); #endif for (i = 0; i < size; i++) c->lits[i] = begin[i]; if (learnt) *((float*)&c->lits[size]) = 0.0; assert(begin[0] >= 0); assert(begin[0] < s->size*2); assert(begin[1] >= 0); assert(begin[1] < s->size*2); assert(lit_neg(begin[0]) < s->size*2); assert(lit_neg(begin[1]) < s->size*2); /* vecp_push(solver_read_wlist(s,lit_neg(begin[0])),(void*)c); */ /* vecp_push(solver_read_wlist(s,lit_neg(begin[1])),(void*)c); */ vecp_push(solver_read_wlist(s,lit_neg(begin[0])), (void*)(size > 2 ? c : clause_from_lit(begin[1]))); vecp_push(solver_read_wlist(s,lit_neg(begin[1])), (void*)(size > 2 ? c : clause_from_lit(begin[0]))); return c; } static void clause_remove(solver* s, clause* c) { lit* lits = clause_begin(c); assert(lit_neg(lits[0]) < s->size*2); assert(lit_neg(lits[1]) < s->size*2); /* vecp_remove(solver_read_wlist(s,lit_neg(lits[0])),(void*)c); */ /* vecp_remove(solver_read_wlist(s,lit_neg(lits[1])),(void*)c); */ assert(lits[0] < s->size*2); vecp_remove(solver_read_wlist(s,lit_neg(lits[0])), (void*)(clause_size(c) > 2 ? c : clause_from_lit(lits[1]))); vecp_remove(solver_read_wlist(s,lit_neg(lits[1])), (void*)(clause_size(c) > 2 ? c : clause_from_lit(lits[0]))); if (clause_learnt(c)){ s->stats.learnts--; s->stats.learnts_literals -= clause_size(c); }else{ s->stats.clauses--; s->stats.clauses_literals -= clause_size(c); } free(c); } static lbool clause_simplify(solver* s, clause* c) { lit* lits = clause_begin(c); lbool* values = s->assigns; int i; assert(solver_dlevel(s) == 0); for (i = 0; i < clause_size(c); i++){ lbool sig = !lit_sign(lits[i]); sig += sig - 1; if (values[lit_var(lits[i])] == sig) return l_True; } return l_False; } /*====================================================================*/ /* Minor (solver) functions: */ void solver_setnvars(solver* s,int n) { int var; if (s->cap < n){ while (s->cap < n) s->cap = s->cap*2+1; s->wlists = (vecp*) realloc(s->wlists, sizeof(vecp)*s->cap*2); s->activity = (double*) realloc(s->activity, sizeof(double)*s->cap); s->assigns = (lbool*) realloc(s->assigns, sizeof(lbool)*s->cap); s->orderpos = (int*) realloc(s->orderpos, sizeof(int)*s->cap); s->reasons = (clause**)realloc(s->reasons, sizeof(clause*)*s->cap); s->levels = (int*) realloc(s->levels, sizeof(int)*s->cap); s->tags = (lbool*) realloc(s->tags, sizeof(lbool)*s->cap); s->trail = (lit*) realloc(s->trail, sizeof(lit)*s->cap); } for (var = s->size; var < n; var++){ vecp_new(&s->wlists[2*var]); vecp_new(&s->wlists[2*var+1]); s->activity [var] = 0; s->assigns [var] = l_Undef; s->orderpos [var] = veci_size(&s->order); s->reasons [var] = (clause*)0; s->levels [var] = 0; s->tags [var] = l_Undef; /* does not hold because variables enqueued at top level will not be reinserted in the heap assert(veci_size(&s->order) == var); */ veci_push(&s->order,var); order_update(s, var); } s->size = n > s->size ? n : s->size; } static inline bool enqueue(solver* s, lit l, clause* from) { lbool* values = s->assigns; int v = lit_var(l); lbool val = values[v]; lbool sig; #ifdef VERBOSEDEBUG printf(L_IND"enqueue("L_LIT")\n", L_ind, L_lit(l)); #endif /* lbool */ sig = !lit_sign(l); sig += sig - 1; if (val != l_Undef){ return val == sig; }else{ /* New fact -- store it. */ int* levels; clause** reasons; #ifdef VERBOSEDEBUG printf(L_IND"bind("L_LIT")\n", L_ind, L_lit(l)); #endif /* int* */ levels = s->levels; /* clause** */ reasons = s->reasons; values [v] = sig; levels [v] = solver_dlevel(s); reasons[v] = from; s->trail[s->qtail++] = l; order_assigned(s, v); return true; } } static inline void assume(solver* s, lit l){ assert(s->qtail == s->qhead); assert(s->assigns[lit_var(l)] == l_Undef); #ifdef VERBOSEDEBUG printf(L_IND"assume("L_LIT")\n", L_ind, L_lit(l)); #endif veci_push(&s->trail_lim,s->qtail); enqueue(s,l,(clause*)0); } static inline void solver_canceluntil(solver* s, int level) { lit* trail; lbool* values; clause** reasons; int bound; int c; if (solver_dlevel(s) <= level) return; trail = s->trail; values = s->assigns; reasons = s->reasons; bound = (veci_begin(&s->trail_lim))[level]; for (c = s->qtail-1; c >= bound; c--) { int x = lit_var(trail[c]); values [x] = l_Undef; reasons[x] = (clause*)0; } for (c = s->qhead-1; c >= bound; c--) order_unassigned(s,lit_var(trail[c])); s->qhead = s->qtail = bound; veci_resize(&s->trail_lim,level); } static void solver_record(solver* s, veci* cls) { lit* begin = veci_begin(cls); lit* end = begin + veci_size(cls); clause* c = (veci_size(cls) > 1) ? clause_new(s,begin,end,1) : (clause*)0; enqueue(s,*begin,c); assert(veci_size(cls) > 0); if (c != 0) { vecp_push(&s->learnts,c); act_clause_bump(s,c); s->stats.learnts++; s->stats.learnts_literals += veci_size(cls); } } static double solver_progress(solver* s) { lbool* values = s->assigns; int* levels = s->levels; int i; double progress = 0; double F = 1.0 / s->size; for (i = 0; i < s->size; i++) if (values[i] != l_Undef) progress += pow(F, levels[i]); return progress / s->size; } /*====================================================================*/ /* Major methods: */ static bool solver_lit_removable(solver* s, lit l, int minl) { lbool* tags = s->tags; clause** reasons = s->reasons; int* levels = s->levels; int top = veci_size(&s->tagged); assert(lit_var(l) >= 0 && lit_var(l) < s->size); assert(reasons[lit_var(l)] != 0); veci_resize(&s->stack,0); veci_push(&s->stack,lit_var(l)); while (veci_size(&s->stack) > 0){ clause* c; int v = veci_begin(&s->stack)[veci_size(&s->stack)-1]; assert(v >= 0 && v < s->size); veci_resize(&s->stack,veci_size(&s->stack)-1); assert(reasons[v] != 0); c = reasons[v]; if (clause_is_lit(c)){ int v = lit_var(clause_read_lit(c)); if (tags[v] == l_Undef && levels[v] != 0){ if (reasons[v] != 0 && ((1 << (levels[v] & 31)) & minl)){ veci_push(&s->stack,v); tags[v] = l_True; veci_push(&s->tagged,v); }else{ int* tagged = veci_begin(&s->tagged); int j; for (j = top; j < veci_size(&s->tagged); j++) tags[tagged[j]] = l_Undef; veci_resize(&s->tagged,top); return false; } } }else{ lit* lits = clause_begin(c); int i, j; for (i = 1; i < clause_size(c); i++){ int v = lit_var(lits[i]); if (tags[v] == l_Undef && levels[v] != 0){ if (reasons[v] != 0 && ((1 << (levels[v] & 31)) & minl)){ veci_push(&s->stack,lit_var(lits[i])); tags[v] = l_True; veci_push(&s->tagged,v); }else{ int* tagged = veci_begin(&s->tagged); for (j = top; j < veci_size(&s->tagged); j++) tags[tagged[j]] = l_Undef; veci_resize(&s->tagged,top); return false; } } } } } return true; } static void solver_analyze(solver* s, clause* c, veci* learnt) { lit* trail = s->trail; lbool* tags = s->tags; clause** reasons = s->reasons; int* levels = s->levels; int cnt = 0; lit p = lit_Undef; int ind = s->qtail-1; lit* lits; int i, j, minl; int* tagged; veci_push(learnt,lit_Undef); do{ assert(c != 0); if (clause_is_lit(c)){ lit q = clause_read_lit(c); assert(lit_var(q) >= 0 && lit_var(q) < s->size); if (tags[lit_var(q)] == l_Undef && levels[lit_var(q)] > 0){ tags[lit_var(q)] = l_True; veci_push(&s->tagged,lit_var(q)); act_var_bump(s,lit_var(q)); if (levels[lit_var(q)] == solver_dlevel(s)) cnt++; else veci_push(learnt,q); } }else{ if (clause_learnt(c)) act_clause_bump(s,c); lits = clause_begin(c); /* printlits(lits,lits+clause_size(c)); printf("\n"); */ for (j = (p == lit_Undef ? 0 : 1); j < clause_size(c); j++){ lit q = lits[j]; assert(lit_var(q) >= 0 && lit_var(q) < s->size); if (tags[lit_var(q)] == l_Undef && levels[lit_var(q)] > 0){ tags[lit_var(q)] = l_True; veci_push(&s->tagged,lit_var(q)); act_var_bump(s,lit_var(q)); if (levels[lit_var(q)] == solver_dlevel(s)) cnt++; else veci_push(learnt,q); } } } while (tags[lit_var(trail[ind--])] == l_Undef); p = trail[ind+1]; c = reasons[lit_var(p)]; cnt--; }while (cnt > 0); *veci_begin(learnt) = lit_neg(p); lits = veci_begin(learnt); minl = 0; for (i = 1; i < veci_size(learnt); i++){ int lev = levels[lit_var(lits[i])]; minl |= 1 << (lev & 31); } /* simplify (full) */ for (i = j = 1; i < veci_size(learnt); i++){ if (reasons[lit_var(lits[i])] == 0 || !solver_lit_removable(s,lits[i],minl)) lits[j++] = lits[i]; } /* update size of learnt + statistics */ s->stats.max_literals += veci_size(learnt); veci_resize(learnt,j); s->stats.tot_literals += j; /* clear tags */ tagged = veci_begin(&s->tagged); for (i = 0; i < veci_size(&s->tagged); i++) tags[tagged[i]] = l_Undef; veci_resize(&s->tagged,0); #ifdef DEBUG for (i = 0; i < s->size; i++) assert(tags[i] == l_Undef); #endif #ifdef VERBOSEDEBUG printf(L_IND"Learnt {", L_ind); for (i = 0; i < veci_size(learnt); i++) printf(" "L_LIT, L_lit(lits[i])); #endif if (veci_size(learnt) > 1){ int max_i = 1; int max = levels[lit_var(lits[1])]; lit tmp; for (i = 2; i < veci_size(learnt); i++) if (levels[lit_var(lits[i])] > max){ max = levels[lit_var(lits[i])]; max_i = i; } tmp = lits[1]; lits[1] = lits[max_i]; lits[max_i] = tmp; } #ifdef VERBOSEDEBUG { int lev = veci_size(learnt) > 1 ? levels[lit_var(lits[1])] : 0; printf(" } at level %d\n", lev); } #endif } clause* solver_propagate(solver* s) { lbool* values = s->assigns; clause* confl = (clause*)0; lit* lits; /* printf("solver_propagate\n"); */ while (confl == 0 && s->qtail - s->qhead > 0){ lit p = s->trail[s->qhead++]; vecp* ws = solver_read_wlist(s,p); clause **begin = (clause**)vecp_begin(ws); clause **end = begin + vecp_size(ws); clause **i, **j; s->stats.propagations++; s->simpdb_props--; /* printf("checking lit %d: "L_LIT"\n", veci_size(ws), L_lit(p)); */ for (i = j = begin; i < end; ){ if (clause_is_lit(*i)){ *j++ = *i; if (!enqueue(s,clause_read_lit(*i),clause_from_lit(p))){ confl = s->binary; (clause_begin(confl))[1] = lit_neg(p); (clause_begin(confl))[0] = clause_read_lit(*i++); /* Copy the remaining watches: */ while (i < end) *j++ = *i++; } }else{ lit false_lit; lbool sig; lits = clause_begin(*i); /* Make sure the false literal is data[1]: */ false_lit = lit_neg(p); if (lits[0] == false_lit){ lits[0] = lits[1]; lits[1] = false_lit; } assert(lits[1] == false_lit); /* printf("checking clause: "); printlits(lits, lits+clause_size(*i)); printf("\n"); */ /* If 0th watch is true, then clause is already satisfied. */ sig = !lit_sign(lits[0]); sig += sig - 1; if (values[lit_var(lits[0])] == sig){ *j++ = *i; }else{ /* Look for new watch: */ lit* stop = lits + clause_size(*i); lit* k; for (k = lits + 2; k < stop; k++){ lbool sig = lit_sign(*k); sig += sig - 1; if (values[lit_var(*k)] != sig){ lits[1] = *k; *k = false_lit; vecp_push(solver_read_wlist(s, lit_neg(lits[1])),*i); goto next; } } *j++ = *i; /* Clause is unit under assignment: */ if (!enqueue(s,lits[0], *i)){ confl = *i++; /* Copy the remaining watches: */ while (i < end) *j++ = *i++; } } } next: i++; } s->stats.inspects += j - (clause**)vecp_begin(ws); vecp_resize(ws,j - (clause**)vecp_begin(ws)); } return confl; } static inline int clause_cmp (const void* x, const void* y) { return clause_size((clause*)x) > 2 && (clause_size((clause*)y) == 2 || clause_activity((clause*)x) < clause_activity((clause*)y)) ? -1 : 1; } void solver_reducedb(solver* s) { int i, j; double extra_lim = s->cla_inc / vecp_size(&s->learnts); /* Remove any clause below this activity */ clause** learnts = (clause**)vecp_begin(&s->learnts); clause** reasons = s->reasons; sort(vecp_begin(&s->learnts), vecp_size(&s->learnts), clause_cmp); for (i = j = 0; i < vecp_size(&s->learnts) / 2; i++){ if (clause_size(learnts[i]) > 2 && reasons[lit_var(*clause_begin(learnts[i]))] != learnts[i]) clause_remove(s,learnts[i]); else learnts[j++] = learnts[i]; } for (; i < vecp_size(&s->learnts); i++){ if (clause_size(learnts[i]) > 2 && reasons[lit_var(*clause_begin(learnts[i]))] != learnts[i] && clause_activity(learnts[i]) < extra_lim) clause_remove(s,learnts[i]); else learnts[j++] = learnts[i]; } /* printf("reducedb deleted %d\n", vecp_size(&s->learnts) - j); */ vecp_resize(&s->learnts,j); } static lbool solver_search(solver* s, int nof_conflicts, int nof_learnts) { int* levels = s->levels; double var_decay = 0.95; double clause_decay = 0.999; double random_var_freq = 0.02; int conflictC = 0; veci learnt_clause; assert(s->root_level == solver_dlevel(s)); s->stats.starts++; s->var_decay = (float)(1 / var_decay ); s->cla_decay = (float)(1 / clause_decay); veci_resize(&s->model,0); veci_new(&learnt_clause); for (;;){ clause* confl = solver_propagate(s); if (confl != 0){ /* CONFLICT */ int blevel; #ifdef VERBOSEDEBUG printf(L_IND"**CONFLICT**\n", L_ind); #endif s->stats.conflicts++; conflictC++; if (solver_dlevel(s) == s->root_level){ veci_delete(&learnt_clause); return l_False; } veci_resize(&learnt_clause,0); solver_analyze(s, confl, &learnt_clause); blevel = veci_size(&learnt_clause) > 1 ? levels[lit_var(veci_begin(&learnt_clause)[1])] : s->root_level; blevel = s->root_level > blevel ? s->root_level : blevel; solver_canceluntil(s,blevel); solver_record(s,&learnt_clause); act_var_decay(s); act_clause_decay(s); }else{ /* NO CONFLICT */ int next; if (nof_conflicts >= 0 && conflictC >= nof_conflicts){ /* Reached bound on number of conflicts: */ s->progress_estimate = solver_progress(s); solver_canceluntil(s,s->root_level); veci_delete(&learnt_clause); return l_Undef; } if (solver_dlevel(s) == 0) /* Simplify the set of problem clauses: */ solver_simplify(s); if (nof_learnts >= 0 && vecp_size(&s->learnts) - s->qtail >= nof_learnts) /* Reduce the set of learnt clauses: */ solver_reducedb(s); /* New variable decision: */ s->stats.decisions++; next = order_select(s,(float)random_var_freq); if (next == var_Undef){ /* Model found: */ lbool* values = s->assigns; int i; for (i = 0; i < s->size; i++) veci_push(&s->model,(int)values[i]); solver_canceluntil(s,s->root_level); veci_delete(&learnt_clause); /* veci apa; veci_new(&apa); for (i = 0; i < s->size; i++) veci_push(&apa,(int)(s->model.ptr[i] == l_True ? toLit(i) : lit_neg(toLit(i)))); printf("model: "); printlits((lit*)apa.ptr, (lit*)apa.ptr + veci_size(&apa)); printf("\n"); veci_delete(&apa); */ return l_True; } assume(s,lit_neg(toLit(next))); } } #if 0 /* by mao; unreachable code */ return l_Undef; /* cannot happen */ #endif } /*====================================================================*/ /* External solver functions: */ solver* solver_new(void) { solver* s = (solver*)malloc(sizeof(solver)); /* initialize vectors */ vecp_new(&s->clauses); vecp_new(&s->learnts); veci_new(&s->order); veci_new(&s->trail_lim); veci_new(&s->tagged); veci_new(&s->stack); veci_new(&s->model); /* initialize arrays */ s->wlists = 0; s->activity = 0; s->assigns = 0; s->orderpos = 0; s->reasons = 0; s->levels = 0; s->tags = 0; s->trail = 0; /* initialize other vars */ s->size = 0; s->cap = 0; s->qhead = 0; s->qtail = 0; s->cla_inc = 1; s->cla_decay = 1; s->var_inc = 1; s->var_decay = 1; s->root_level = 0; s->simpdb_assigns = 0; s->simpdb_props = 0; s->random_seed = 91648253; s->progress_estimate = 0; s->binary = (clause*)malloc(sizeof(clause) + sizeof(lit)*2); s->binary->size_learnt = (2 << 1); s->verbosity = 0; s->stats.starts = 0; s->stats.decisions = 0; s->stats.propagations = 0; s->stats.inspects = 0; s->stats.conflicts = 0; s->stats.clauses = 0; s->stats.clauses_literals = 0; s->stats.learnts = 0; s->stats.learnts_literals = 0; s->stats.max_literals = 0; s->stats.tot_literals = 0; return s; } void solver_delete(solver* s) { int i; for (i = 0; i < vecp_size(&s->clauses); i++) free(vecp_begin(&s->clauses)[i]); for (i = 0; i < vecp_size(&s->learnts); i++) free(vecp_begin(&s->learnts)[i]); /* delete vectors */ vecp_delete(&s->clauses); vecp_delete(&s->learnts); veci_delete(&s->order); veci_delete(&s->trail_lim); veci_delete(&s->tagged); veci_delete(&s->stack); veci_delete(&s->model); free(s->binary); /* delete arrays */ if (s->wlists != 0){ int i; for (i = 0; i < s->size*2; i++) vecp_delete(&s->wlists[i]); /* if one is different from null, all are */ free(s->wlists); free(s->activity ); free(s->assigns ); free(s->orderpos ); free(s->reasons ); free(s->levels ); free(s->trail ); free(s->tags ); } free(s); } bool solver_addclause(solver* s, lit* begin, lit* end) { lit *i,*j; int maxvar; lbool* values; lit last; if (begin == end) return false; /* printlits(begin,end); printf("\n"); */ /* insertion sort */ maxvar = lit_var(*begin); for (i = begin + 1; i < end; i++){ lit l = *i; maxvar = lit_var(l) > maxvar ? lit_var(l) : maxvar; for (j = i; j > begin && *(j-1) > l; j--) *j = *(j-1); *j = l; } solver_setnvars(s,maxvar+1); /* printlits(begin,end); printf("\n"); */ values = s->assigns; /* delete duplicates */ last = lit_Undef; for (i = j = begin; i < end; i++){ /* printf("lit: "L_LIT", value = %d\n", L_lit(*i), (lit_sign(*i) ? -values[lit_var(*i)] : values[lit_var(*i)])); */ lbool sig = !lit_sign(*i); sig += sig - 1; if (*i == lit_neg(last) || sig == values[lit_var(*i)]) return true; /* tautology */ else if (*i != last && values[lit_var(*i)] == l_Undef) last = *j++ = *i; } /* printf("final: "); printlits(begin,j); printf("\n"); */ if (j == begin) /* empty clause */ return false; else if (j - begin == 1) /* unit clause */ return enqueue(s,*begin,(clause*)0); /* create new clause */ vecp_push(&s->clauses,clause_new(s,begin,j,0)); s->stats.clauses++; s->stats.clauses_literals += j - begin; return true; } bool solver_simplify(solver* s) { clause** reasons; int type; assert(solver_dlevel(s) == 0); if (solver_propagate(s) != 0) return false; if (s->qhead == s->simpdb_assigns || s->simpdb_props > 0) return true; reasons = s->reasons; for (type = 0; type < 2; type++){ vecp* cs = type ? &s->learnts : &s->clauses; clause** cls = (clause**)vecp_begin(cs); int i, j; for (j = i = 0; i < vecp_size(cs); i++){ if (reasons[lit_var(*clause_begin(cls[i]))] != cls[i] && clause_simplify(s,cls[i]) == l_True) clause_remove(s,cls[i]); else cls[j++] = cls[i]; } vecp_resize(cs,j); } s->simpdb_assigns = s->qhead; /* (shouldn't depend on 'stats' really, but it will do for now) */ s->simpdb_props = (int)(s->stats.clauses_literals + s->stats.learnts_literals); return true; } bool solver_solve(solver* s, lit* begin, lit* end) { double nof_conflicts = 100; double nof_learnts = solver_nclauses(s) / 3; lbool status = l_Undef; lbool* values = s->assigns; lit* i; /* printf("solve: "); printlits(begin, end); printf("\n"); */ for (i = begin; i < end; i++){ switch (lit_sign(*i) ? -values[lit_var(*i)] : values[lit_var(*i)]){ case 1: /* l_True: */ break; case 0: /* l_Undef */ assume(s, *i); if (solver_propagate(s) == NULL) break; /* falltrough */ case -1: /* l_False */ solver_canceluntil(s, 0); return false; } } s->root_level = solver_dlevel(s); if (s->verbosity >= 1){ printf("==================================[MINISAT]============" "=======================\n"); printf("| Conflicts | ORIGINAL | LEARNT " " | Progress |\n"); printf("| | Clauses Literals | Limit Clauses Litera" "ls Lit/Cl | |\n"); printf("=======================================================" "=======================\n"); } while (status == l_Undef){ double Ratio = (s->stats.learnts == 0)? 0.0 : s->stats.learnts_literals / (double)s->stats.learnts; if (s->verbosity >= 1){ printf("| %9.0f | %7.0f %8.0f | %7.0f %7.0f %8.0f %7.1f | %" "6.3f %% |\n", (double)s->stats.conflicts, (double)s->stats.clauses, (double)s->stats.clauses_literals, (double)nof_learnts, (double)s->stats.learnts, (double)s->stats.learnts_literals, Ratio, s->progress_estimate*100); fflush(stdout); } status = solver_search(s,(int)nof_conflicts, (int)nof_learnts); nof_conflicts *= 1.5; nof_learnts *= 1.1; } if (s->verbosity >= 1) printf("=======================================================" "=======================\n"); solver_canceluntil(s,0); return status != l_False; } int solver_nvars(solver* s) { return s->size; } int solver_nclauses(solver* s) { return vecp_size(&s->clauses); } int solver_nconflicts(solver* s) { return (int)s->stats.conflicts; } /*====================================================================*/ /* Sorting functions (sigh): */ static inline void selectionsort(void** array, int size, int(*comp)(const void *, const void *)) { int i, j, best_i; void* tmp; for (i = 0; i < size-1; i++){ best_i = i; for (j = i+1; j < size; j++){ if (comp(array[j], array[best_i]) < 0) best_i = j; } tmp = array[i]; array[i] = array[best_i]; array[best_i] = tmp; } } static void sortrnd(void** array, int size, int(*comp)(const void *, const void *), double* seed) { if (size <= 15) selectionsort(array, size, comp); else{ void* pivot = array[irand(seed, size)]; void* tmp; int i = -1; int j = size; for(;;){ do i++; while(comp(array[i], pivot)<0); do j--; while(comp(pivot, array[j])<0); if (i >= j) break; tmp = array[i]; array[i] = array[j]; array[j] = tmp; } sortrnd(array , i , comp, seed); sortrnd(&array[i], size-i, comp, seed); } } static void sort(void** array, int size, int(*comp)(const void *, const void *)) { double seed = 91648253; sortrnd(array,size,comp,&seed); } /* eof */ Rglpk/src/GLPK/minisat/LICENSE0000644000176000001440000000206012175147600015357 0ustar ripleyusersMiniSat -- Copyright (c) 2005, Niklas Sorensson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Rglpk/src/GLPK/glpsdf.h0000644000176000001440000000364712245352174014354 0ustar ripleyusers/* glpsdf.h */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPSDF_H #define GLPSDF_H typedef struct glp_data glp_data; /* plain data file */ glp_data *glp_sdf_open_file(const char *fname); /* open plain data file */ void glp_sdf_set_jump(glp_data *data, void *jump); /* set up error handling */ void glp_sdf_error(glp_data *data, const char *fmt, ...); /* print error message */ void glp_sdf_warning(glp_data *data, const char *fmt, ...); /* print warning message */ int glp_sdf_read_int(glp_data *data); /* read integer number */ double glp_sdf_read_num(glp_data *data); /* read floating-point number */ const char *glp_sdf_read_item(glp_data *data); /* read data item */ const char *glp_sdf_read_text(glp_data *data); /* read text until end of line */ int glp_sdf_line(glp_data *data); /* determine current line number */ void glp_sdf_close_file(glp_data *data); /* close plain data file */ #endif /* eof */ Rglpk/src/GLPK/glphbm.h0000644000176000001440000001103412245352174014333 0ustar ripleyusers/* glphbm.h (Harwell-Boeing sparse matrix format) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPHBM_H #define GLPHBM_H typedef struct HBM HBM; struct HBM { /* sparse matrix in Harwell-Boeing format; for details see the report: I.S.Duff, R.G.Grimes, J.G.Lewis. User's Guide for the Harwell-Boeing Sparse Matrix Collection (Release I), 1992 */ char title[72+1]; /* matrix title (informative) */ char key[8+1]; /* matrix key (informative) */ char mxtype[3+1]; /* matrix type: R.. real matrix C.. complex matrix P.. pattern only (no numerical values supplied) .S. symmetric (lower triangle + main diagonal) .U. unsymmetric .H. hermitian (lower triangle + main diagonal) .Z. skew symmetric (lower triangle only) .R. rectangular ..A assembled ..E elemental (unassembled) */ char rhstyp[3+1]; /* optional types: F.. right-hand sides in dense format M.. right-hand sides in same format as matrix .G. starting vector(s) (guess) is supplied ..X exact solution vector(s) is supplied */ char ptrfmt[16+1]; /* format for pointers */ char indfmt[16+1]; /* format for row (or variable) indices */ char valfmt[20+1]; /* format for numerical values of coefficient matrix */ char rhsfmt[20+1]; /* format for numerical values of right-hand sides */ int totcrd; /* total number of cards excluding header */ int ptrcrd; /* number of cards for ponters */ int indcrd; /* number of cards for row (or variable) indices */ int valcrd; /* number of cards for numerical values */ int rhscrd; /* number of lines for right-hand sides; including starting guesses and solution vectors if present; zero indicates no right-hand side data is present */ int nrow; /* number of rows (or variables) */ int ncol; /* number of columns (or elements) */ int nnzero; /* number of row (or variable) indices; equal to number of entries for assembled matrix */ int neltvl; /* number of elemental matrix entries; zero in case of assembled matrix */ int nrhs; /* number of right-hand sides */ int nrhsix; /* number of row indices; ignored in case of unassembled matrix */ int nrhsvl; /* total number of entries in all right-hand sides */ int nguess; /* total number of entries in all starting guesses */ int nexact; /* total number of entries in all solution vectors */ int *colptr; /* alias: eltptr */ /* column pointers (in case of assembled matrix); elemental matrix pointers (in case of unassembled matrix) */ int *rowind; /* alias: varind */ /* row indices (in case of assembled matrix); variable indices (in case of unassembled matrix) */ int *rhsptr; /* right-hand side pointers */ int *rhsind; /* right-hand side indices */ double *values; /* matrix values */ double *rhsval; /* right-hand side values */ double *sguess; /* starting guess values */ double *xexact; /* solution vector values */ }; #define hbm_read_mat _glp_hbm_read_mat HBM *hbm_read_mat(const char *fname); /* read sparse matrix in Harwell-Boeing format */ #define hbm_free_mat _glp_hbm_free_mat void hbm_free_mat(HBM *hbm); /* free sparse matrix in Harwell-Boeing format */ #endif /* eof */ Rglpk/src/GLPK/glpbfd.c0000644000176000001440000004027512245352174014324 0ustar ripleyusers/* glpbfd.c (LP basis factorization driver) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpapi.h" #if 0 /* 27/IV-2013 */ #include "glpfhv.h" #else #include "fhvint.h" #endif #include "glplpf.h" /* CAUTION: DO NOT CHANGE THE LIMIT BELOW */ #define M_MAX 100000000 /* = 100*10^6 */ /* maximal order of the basis matrix */ struct BFD { /* LP basis factorization */ int valid; /* factorization is valid only if this flag is set */ int type; /* factorization type: GLP_BF_FT - LUF + Forrest-Tomlin GLP_BF_BG - LUF + Schur compl. + Bartels-Golub GLP_BF_GR - LUF + Schur compl. + Givens rotation */ #if 0 /* 27/IV-2013 */ FHV *fhv; /* LP basis factorization (GLP_BF_FT) */ #else FHVINT *fi; /* interface to FHV-factorization (GLP_BF_FT) */ #endif LPF *lpf; /* LP basis factorization (GLP_BF_BG, GLP_BF_GR) */ int lu_size; /* luf.sv_size */ double piv_tol; /* luf.piv_tol */ int piv_lim; /* luf.piv_lim */ int suhl; /* luf.suhl */ double eps_tol; /* luf.eps_tol */ double max_gro; /* luf.max_gro */ int nfs_max; /* fhv.hh_max */ double upd_tol; /* fhv.upd_tol */ int nrs_max; /* lpf.n_max */ int rs_size; /* lpf.v_size */ /* internal control parameters */ int upd_lim; /* the factorization update limit */ int upd_cnt; /* the factorization update count */ }; /*********************************************************************** * NAME * * bfd_create_it - create LP basis factorization * * SYNOPSIS * * #include "glpbfd.h" * BFD *bfd_create_it(void); * * DESCRIPTION * * The routine bfd_create_it creates a program object, which represents * a factorization of LP basis. * * RETURNS * * The routine bfd_create_it returns a pointer to the object created. */ BFD *bfd_create_it(void) { BFD *bfd; bfd = xmalloc(sizeof(BFD)); bfd->valid = 0; bfd->type = GLP_BF_FT; #if 0 /* 27/IV-2013 */ bfd->fhv = NULL; #else bfd->fi = NULL; #endif bfd->lpf = NULL; bfd->lu_size = 0; bfd->piv_tol = 0.10; bfd->piv_lim = 4; bfd->suhl = 1; bfd->eps_tol = 1e-15; bfd->max_gro = 1e+10; bfd->nfs_max = 100; bfd->upd_tol = 1e-6; bfd->nrs_max = 100; bfd->rs_size = 1000; bfd->upd_lim = -1; bfd->upd_cnt = 0; return bfd; } /**********************************************************************/ void bfd_set_parm(BFD *bfd, const void *_parm) { /* change LP basis factorization control parameters */ const glp_bfcp *parm = _parm; xassert(bfd != NULL); bfd->type = parm->type; bfd->lu_size = parm->lu_size; bfd->piv_tol = parm->piv_tol; bfd->piv_lim = parm->piv_lim; bfd->suhl = parm->suhl; bfd->eps_tol = parm->eps_tol; bfd->max_gro = parm->max_gro; bfd->nfs_max = parm->nfs_max; bfd->upd_tol = parm->upd_tol; bfd->nrs_max = parm->nrs_max; bfd->rs_size = parm->rs_size; return; } /*********************************************************************** * NAME * * bfd_factorize - compute LP basis factorization * * SYNOPSIS * * #include "glpbfd.h" * int bfd_factorize(BFD *bfd, int m, int bh[], int (*col)(void *info, * int j, int ind[], double val[]), void *info); * * DESCRIPTION * * The routine bfd_factorize computes the factorization of the basis * matrix B specified by the routine col. * * The parameter bfd specified the basis factorization data structure * created with the routine bfd_create_it. * * The parameter m specifies the order of B, m > 0. * * The array bh specifies the basis header: bh[j], 1 <= j <= m, is the * number of j-th column of B in some original matrix. The array bh is * optional and can be specified as NULL. * * The formal routine col specifies the matrix B to be factorized. To * obtain j-th column of A the routine bfd_factorize calls the routine * col with the parameter j (1 <= j <= n). In response the routine col * should store row indices and numerical values of non-zero elements * of j-th column of B to locations ind[1,...,len] and val[1,...,len], * respectively, where len is the number of non-zeros in j-th column * returned on exit. Neither zero nor duplicate elements are allowed. * * The parameter info is a transit pointer passed to the routine col. * * RETURNS * * 0 The factorization has been successfully computed. * * BFD_ESING * The specified matrix is singular within the working precision. * * BFD_ECOND * The specified matrix is ill-conditioned. * * For more details see comments to the routine luf_factorize. */ int bfd_factorize(BFD *bfd, int m, const int bh[], int (*col) (void *info, int j, int ind[], double val[]), void *info) #if 0 /* 06/VI-2013 */ { LUF *luf; #else { #endif int nov, ret; xassert(bfd != NULL); xassert(1 <= m && m <= M_MAX); /* invalidate the factorization */ bfd->valid = 0; /* create the factorization, if necessary */ nov = 0; switch (bfd->type) { case GLP_BF_FT: if (bfd->lpf != NULL) lpf_delete_it(bfd->lpf), bfd->lpf = NULL; #if 0 /* 27/IV-2013 */ if (bfd->fhv == NULL) bfd->fhv = fhv_create_it(), nov = 1; #else if (bfd->fi == NULL) bfd->fi = fhvint_create(), nov = 1; #endif break; case GLP_BF_BG: case GLP_BF_GR: #if 0 /* 27/IV-2013 */ if (bfd->fhv != NULL) fhv_delete_it(bfd->fhv), bfd->fhv = NULL; #else if (bfd->fi != NULL) fhvint_delete(bfd->fi), bfd->fi = NULL; #endif if (bfd->lpf == NULL) bfd->lpf = lpf_create_it(), nov = 1; break; default: xassert(bfd != bfd); } #if 0 /* 06/VI-2013 */ /* set control parameters specific to LUF */ #if 0 /* 27/IV-2013 */ if (bfd->fhv != NULL) luf = bfd->fhv->luf; #else if (bfd->fi != NULL) goto skip; #endif else if (bfd->lpf != NULL) luf = bfd->lpf->luf; else xassert(bfd != bfd); if (nov) luf->new_sva = bfd->lu_size; luf->piv_tol = bfd->piv_tol; luf->piv_lim = bfd->piv_lim; luf->suhl = bfd->suhl; luf->eps_tol = bfd->eps_tol; luf->max_gro = bfd->max_gro; #endif #if 0 /* 27/IV-2013 */ /* set control parameters specific to FHV */ if (bfd->fhv != NULL) { if (nov) bfd->fhv->hh_max = bfd->nfs_max; bfd->fhv->upd_tol = bfd->upd_tol; } #endif /* set control parameters specific to LPF */ if (bfd->lpf != NULL) { if (nov) bfd->lpf->n_max = bfd->nrs_max; if (nov) bfd->lpf->v_size = bfd->rs_size; } #if 0 /* 27/IV-2013 */ /* try to factorize the basis matrix */ if (bfd->fhv != NULL) { switch (fhv_factorize(bfd->fhv, m, col, info)) { case 0: break; case FHV_ESING: ret = BFD_ESING; goto done; case FHV_ECOND: ret = BFD_ECOND; goto done; default: xassert(bfd != bfd); } } #else skip: /* try to factorize the basis matrix */ if (bfd->fi != NULL) { /* FIXME */ if (fhvint_factorize(bfd->fi, m, col, info) != 0) { ret = BFD_ESING; goto done; } /* printf("*** FACTORIZED; m = %d ***\n", m); */ } #endif else if (bfd->lpf != NULL) { switch (lpf_factorize(bfd->lpf, m, bh, col, info)) { case 0: /* set the Schur complement update type */ switch (bfd->type) { case GLP_BF_BG: /* Bartels-Golub update */ bfd->lpf->scf->t_opt = SCF_TBG; break; case GLP_BF_GR: /* Givens rotation update */ bfd->lpf->scf->t_opt = SCF_TGR; break; default: xassert(bfd != bfd); } break; case LPF_ESING: ret = BFD_ESING; goto done; case LPF_ECOND: ret = BFD_ECOND; goto done; default: xassert(bfd != bfd); } } else xassert(bfd != bfd); /* the basis matrix has been successfully factorized */ bfd->valid = 1; bfd->upd_cnt = 0; ret = 0; done: /* return to the calling program */ return ret; } /*********************************************************************** * NAME * * bfd_ftran - perform forward transformation (solve system B*x = b) * * SYNOPSIS * * #include "glpbfd.h" * void bfd_ftran(BFD *bfd, double x[]); * * DESCRIPTION * * The routine bfd_ftran performs forward transformation, i.e. solves * the system B*x = b, where B is the basis matrix, x is the vector of * unknowns to be computed, b is the vector of right-hand sides. * * On entry elements of the vector b should be stored in dense format * in locations x[1], ..., x[m], where m is the number of rows. On exit * the routine stores elements of the vector x in the same locations. */ void bfd_ftran(BFD *bfd, double x[]) { xassert(bfd != NULL); xassert(bfd->valid); #if 0 /* 27/IV-2013 */ if (bfd->fhv != NULL) fhv_ftran(bfd->fhv, x); #else if (bfd->fi != NULL) fhvint_ftran(bfd->fi, x); #endif else if (bfd->lpf != NULL) lpf_ftran(bfd->lpf, x); else xassert(bfd != bfd); return; } /*********************************************************************** * NAME * * bfd_btran - perform backward transformation (solve system B'*x = b) * * SYNOPSIS * * #include "glpbfd.h" * void bfd_btran(BFD *bfd, double x[]); * * DESCRIPTION * * The routine bfd_btran performs backward transformation, i.e. solves * the system B'*x = b, where B' is a matrix transposed to the basis * matrix B, x is the vector of unknowns to be computed, b is the vector * of right-hand sides. * * On entry elements of the vector b should be stored in dense format * in locations x[1], ..., x[m], where m is the number of rows. On exit * the routine stores elements of the vector x in the same locations. */ void bfd_btran(BFD *bfd, double x[]) { xassert(bfd != NULL); xassert(bfd->valid); #if 0 /* 27/IV-2013 */ if (bfd->fhv != NULL) fhv_btran(bfd->fhv, x); #else if (bfd->fi != NULL) fhvint_btran(bfd->fi, x); #endif else if (bfd->lpf != NULL) lpf_btran(bfd->lpf, x); else xassert(bfd != bfd); return; } /*********************************************************************** * NAME * * bfd_update_it - update LP basis factorization * * SYNOPSIS * * #include "glpbfd.h" * int bfd_update_it(BFD *bfd, int j, int bh, int len, const int ind[], * const double val[]); * * DESCRIPTION * * The routine bfd_update_it updates the factorization of the basis * matrix B after replacing its j-th column by a new vector. * * The parameter j specifies the number of column of B, which has been * replaced, 1 <= j <= m, where m is the order of B. * * The parameter bh specifies the basis header entry for the new column * of B, which is the number of the new column in some original matrix. * This parameter is optional and can be specified as 0. * * Row indices and numerical values of non-zero elements of the new * column of B should be placed in locations ind[1], ..., ind[len] and * val[1], ..., val[len], resp., where len is the number of non-zeros * in the column. Neither zero nor duplicate elements are allowed. * * RETURNS * * 0 The factorization has been successfully updated. * * BFD_ESING * New basis matrix is singular within the working precision. * * BFD_ECHECK * The factorization is inaccurate. * * BFD_ELIMIT * Factorization update limit has been reached. * * BFD_EROOM * Overflow of the sparse vector area. * * In case of non-zero return code the factorization becomes invalid. * It should not be used until it has been recomputed with the routine * bfd_factorize. */ int bfd_update_it(BFD *bfd, int j, int bh, int len, const int ind[], const double val[]) { int ret; xassert(bfd != NULL); xassert(bfd->valid); /* try to update the factorization */ #if 0 /* 27/IV-2013 */ if (bfd->fhv != NULL) { switch (fhv_update_it(bfd->fhv, j, len, ind, val)) { case 0: break; case FHV_ESING: bfd->valid = 0; ret = BFD_ESING; goto done; case FHV_ECHECK: bfd->valid = 0; ret = BFD_ECHECK; goto done; case FHV_ELIMIT: bfd->valid = 0; ret = BFD_ELIMIT; goto done; case FHV_EROOM: bfd->valid = 0; ret = BFD_EROOM; goto done; default: xassert(bfd != bfd); } } #else if (bfd->fi != NULL) { /* see fhv_ft_update for return codes */ switch (fhvint_update(bfd->fi, j, len, ind, val)) { case 0: break; case 1: bfd->valid = 0; ret = BFD_ESING; goto done; case 2: case 3: case 5: bfd->valid = 0; ret = BFD_ECHECK; goto done; case 4: bfd->valid = 0; ret = BFD_ELIMIT; goto done; default: xassert(bfd != bfd); } } #endif else if (bfd->lpf != NULL) { switch (lpf_update_it(bfd->lpf, j, bh, len, ind, val)) { case 0: break; case LPF_ESING: bfd->valid = 0; ret = BFD_ESING; goto done; case LPF_ELIMIT: bfd->valid = 0; ret = BFD_ELIMIT; goto done; default: xassert(bfd != bfd); } } else xassert(bfd != bfd); /* the factorization has been successfully updated */ /* increase the update count */ bfd->upd_cnt++; ret = 0; done: /* return to the calling program */ return ret; } /**********************************************************************/ int bfd_get_count(BFD *bfd) { /* determine factorization update count */ xassert(bfd != NULL); xassert(bfd->valid); return bfd->upd_cnt; } /*********************************************************************** * NAME * * bfd_delete_it - delete LP basis factorization * * SYNOPSIS * * #include "glpbfd.h" * void bfd_delete_it(BFD *bfd); * * DESCRIPTION * * The routine bfd_delete_it deletes LP basis factorization specified * by the parameter fhv and frees all memory allocated to this program * object. */ void bfd_delete_it(BFD *bfd) { xassert(bfd != NULL); #if 0 /* 27/IV-2013 */ if (bfd->fhv != NULL) fhv_delete_it(bfd->fhv); #else if (bfd->fi != NULL) fhvint_delete(bfd->fi); #endif if (bfd->lpf != NULL) lpf_delete_it(bfd->lpf); xfree(bfd); return; } /* eof */ Rglpk/src/GLPK/glpios03.c0000644000176000001440000014401212245352174014520 0ustar ripleyusers/* glpios03.c (branch-and-cut driver) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpios.h" /*********************************************************************** * show_progress - display current progress of the search * * This routine displays some information about current progress of the * search. * * The information includes: * * the current number of iterations performed by the simplex solver; * * the objective value for the best known integer feasible solution, * which is upper (minimization) or lower (maximization) global bound * for optimal solution of the original mip problem; * * the best local bound for active nodes, which is lower (minimization) * or upper (maximization) global bound for optimal solution of the * original mip problem; * * the relative mip gap, in percents; * * the number of open (active) subproblems; * * the number of completely explored subproblems, i.e. whose nodes have * been removed from the tree. */ static void show_progress(glp_tree *T, int bingo) { int p; double temp; char best_mip[50], best_bound[50], *rho, rel_gap[50]; /* format the best known integer feasible solution */ if (T->mip->mip_stat == GLP_FEAS) sprintf(best_mip, "%17.9e", T->mip->mip_obj); else sprintf(best_mip, "%17s", "not found yet"); /* determine reference number of an active subproblem whose local bound is best */ p = ios_best_node(T); /* format the best bound */ if (p == 0) sprintf(best_bound, "%17s", "tree is empty"); else { temp = T->slot[p].node->bound; if (temp == -DBL_MAX) sprintf(best_bound, "%17s", "-inf"); else if (temp == +DBL_MAX) sprintf(best_bound, "%17s", "+inf"); else sprintf(best_bound, "%17.9e", temp); } /* choose the relation sign between global bounds */ if (T->mip->dir == GLP_MIN) rho = ">="; else if (T->mip->dir == GLP_MAX) rho = "<="; else xassert(T != T); /* format the relative mip gap */ temp = ios_relative_gap(T); if (temp == 0.0) sprintf(rel_gap, " 0.0%%"); else if (temp < 0.001) sprintf(rel_gap, "< 0.1%%"); else if (temp <= 9.999) sprintf(rel_gap, "%5.1f%%", 100.0 * temp); else sprintf(rel_gap, "%6s", ""); /* display progress of the search */ xprintf("+%6d: %s %s %s %s %s (%d; %d)\n", T->mip->it_cnt, bingo ? ">>>>>" : "mip =", best_mip, rho, best_bound, rel_gap, T->a_cnt, T->t_cnt - T->n_cnt); T->tm_lag = xtime(); return; } /*********************************************************************** * is_branch_hopeful - check if specified branch is hopeful * * This routine checks if the specified subproblem can have an integer * optimal solution which is better than the best known one. * * The check is based on comparison of the local objective bound stored * in the subproblem descriptor and the incumbent objective value which * is the global objective bound. * * If there is a chance that the specified subproblem can have a better * integer optimal solution, the routine returns non-zero. Otherwise, if * the corresponding branch can pruned, zero is returned. */ static int is_branch_hopeful(glp_tree *T, int p) { xassert(1 <= p && p <= T->nslots); xassert(T->slot[p].node != NULL); return ios_is_hopeful(T, T->slot[p].node->bound); } /*********************************************************************** * check_integrality - check integrality of basic solution * * This routine checks if the basic solution of LP relaxation of the * current subproblem satisfies to integrality conditions, i.e. that all * variables of integer kind have integral primal values. (The solution * is assumed to be optimal.) * * For each variable of integer kind the routine computes the following * quantity: * * ii(x[j]) = min(x[j] - floor(x[j]), ceil(x[j]) - x[j]), (1) * * which is a measure of the integer infeasibility (non-integrality) of * x[j] (for example, ii(2.1) = 0.1, ii(3.7) = 0.3, ii(5.0) = 0). It is * understood that 0 <= ii(x[j]) <= 0.5, and variable x[j] is integer * feasible if ii(x[j]) = 0. However, due to floating-point arithmetic * the routine checks less restrictive condition: * * ii(x[j]) <= tol_int, (2) * * where tol_int is a given tolerance (small positive number) and marks * each variable which does not satisfy to (2) as integer infeasible by * setting its fractionality flag. * * In order to characterize integer infeasibility of the basic solution * in the whole the routine computes two parameters: ii_cnt, which is * the number of variables with the fractionality flag set, and ii_sum, * which is the sum of integer infeasibilities (1). */ static void check_integrality(glp_tree *T) { glp_prob *mip = T->mip; int j, type, ii_cnt = 0; double lb, ub, x, temp1, temp2, ii_sum = 0.0; /* walk through the set of columns (structural variables) */ for (j = 1; j <= mip->n; j++) { GLPCOL *col = mip->col[j]; T->non_int[j] = 0; /* if the column is not integer, skip it */ if (col->kind != GLP_IV) continue; /* if the column is non-basic, it is integer feasible */ if (col->stat != GLP_BS) continue; /* obtain the type and bounds of the column */ type = col->type, lb = col->lb, ub = col->ub; /* obtain value of the column in optimal basic solution */ x = col->prim; /* if the column's primal value is close to the lower bound, the column is integer feasible within given tolerance */ if (type == GLP_LO || type == GLP_DB || type == GLP_FX) { temp1 = lb - T->parm->tol_int; temp2 = lb + T->parm->tol_int; if (temp1 <= x && x <= temp2) continue; #if 0 /* the lower bound must not be violated */ xassert(x >= lb); #else if (x < lb) continue; #endif } /* if the column's primal value is close to the upper bound, the column is integer feasible within given tolerance */ if (type == GLP_UP || type == GLP_DB || type == GLP_FX) { temp1 = ub - T->parm->tol_int; temp2 = ub + T->parm->tol_int; if (temp1 <= x && x <= temp2) continue; #if 0 /* the upper bound must not be violated */ xassert(x <= ub); #else if (x > ub) continue; #endif } /* if the column's primal value is close to nearest integer, the column is integer feasible within given tolerance */ temp1 = floor(x + 0.5) - T->parm->tol_int; temp2 = floor(x + 0.5) + T->parm->tol_int; if (temp1 <= x && x <= temp2) continue; /* otherwise the column is integer infeasible */ T->non_int[j] = 1; /* increase the number of fractional-valued columns */ ii_cnt++; /* compute the sum of integer infeasibilities */ temp1 = x - floor(x); temp2 = ceil(x) - x; xassert(temp1 > 0.0 && temp2 > 0.0); ii_sum += (temp1 <= temp2 ? temp1 : temp2); } /* store ii_cnt and ii_sum to the current problem descriptor */ xassert(T->curr != NULL); T->curr->ii_cnt = ii_cnt; T->curr->ii_sum = ii_sum; /* and also display these parameters */ if (T->parm->msg_lev >= GLP_MSG_DBG) { if (ii_cnt == 0) xprintf("There are no fractional columns\n"); else if (ii_cnt == 1) xprintf("There is one fractional column, integer infeasibil" "ity is %.3e\n", ii_sum); else xprintf("There are %d fractional columns, integer infeasibi" "lity is %.3e\n", ii_cnt, ii_sum); } return; } /*********************************************************************** * record_solution - record better integer feasible solution * * This routine records optimal basic solution of LP relaxation of the * current subproblem, which being integer feasible is better than the * best known integer feasible solution. */ static void record_solution(glp_tree *T) { glp_prob *mip = T->mip; int i, j; mip->mip_stat = GLP_FEAS; mip->mip_obj = mip->obj_val; for (i = 1; i <= mip->m; i++) { GLPROW *row = mip->row[i]; row->mipx = row->prim; } for (j = 1; j <= mip->n; j++) { GLPCOL *col = mip->col[j]; if (col->kind == GLP_CV) col->mipx = col->prim; else if (col->kind == GLP_IV) { /* value of the integer column must be integral */ col->mipx = floor(col->prim + 0.5); } else xassert(col != col); } T->sol_cnt++; return; } /*********************************************************************** * fix_by_red_cost - fix non-basic integer columns by reduced costs * * This routine fixes some non-basic integer columns if their reduced * costs indicate that increasing (decreasing) the column at least by * one involves the objective value becoming worse than the incumbent * objective value. */ static void fix_by_red_cost(glp_tree *T) { glp_prob *mip = T->mip; int j, stat, fixed = 0; double obj, lb, ub, dj; /* the global bound must exist */ xassert(T->mip->mip_stat == GLP_FEAS); /* basic solution of LP relaxation must be optimal */ xassert(mip->pbs_stat == GLP_FEAS && mip->dbs_stat == GLP_FEAS); /* determine the objective function value */ obj = mip->obj_val; /* walk through the column list */ for (j = 1; j <= mip->n; j++) { GLPCOL *col = mip->col[j]; /* if the column is not integer, skip it */ if (col->kind != GLP_IV) continue; /* obtain bounds of j-th column */ lb = col->lb, ub = col->ub; /* and determine its status and reduced cost */ stat = col->stat, dj = col->dual; /* analyze the reduced cost */ switch (mip->dir) { case GLP_MIN: /* minimization */ if (stat == GLP_NL) { /* j-th column is non-basic on its lower bound */ if (dj < 0.0) dj = 0.0; if (obj + dj >= mip->mip_obj) glp_set_col_bnds(mip, j, GLP_FX, lb, lb), fixed++; } else if (stat == GLP_NU) { /* j-th column is non-basic on its upper bound */ if (dj > 0.0) dj = 0.0; if (obj - dj >= mip->mip_obj) glp_set_col_bnds(mip, j, GLP_FX, ub, ub), fixed++; } break; case GLP_MAX: /* maximization */ if (stat == GLP_NL) { /* j-th column is non-basic on its lower bound */ if (dj > 0.0) dj = 0.0; if (obj + dj <= mip->mip_obj) glp_set_col_bnds(mip, j, GLP_FX, lb, lb), fixed++; } else if (stat == GLP_NU) { /* j-th column is non-basic on its upper bound */ if (dj < 0.0) dj = 0.0; if (obj - dj <= mip->mip_obj) glp_set_col_bnds(mip, j, GLP_FX, ub, ub), fixed++; } break; default: xassert(T != T); } } if (T->parm->msg_lev >= GLP_MSG_DBG) { if (fixed == 0) /* nothing to say */; else if (fixed == 1) xprintf("One column has been fixed by reduced cost\n"); else xprintf("%d columns have been fixed by reduced costs\n", fixed); } /* fixing non-basic columns on their current bounds does not change the basic solution */ xassert(mip->pbs_stat == GLP_FEAS && mip->dbs_stat == GLP_FEAS); return; } /*********************************************************************** * branch_on - perform branching on specified variable * * This routine performs branching on j-th column (structural variable) * of the current subproblem. The specified column must be of integer * kind and must have a fractional value in optimal basic solution of * LP relaxation of the current subproblem (i.e. only columns for which * the flag non_int[j] is set are valid candidates to branch on). * * Let x be j-th structural variable, and beta be its primal fractional * value in the current basic solution. Branching on j-th variable is * dividing the current subproblem into two new subproblems, which are * identical to the current subproblem with the following exception: in * the first subproblem that begins the down-branch x has a new upper * bound x <= floor(beta), and in the second subproblem that begins the * up-branch x has a new lower bound x >= ceil(beta). * * Depending on estimation of local bounds for down- and up-branches * this routine returns the following: * * 0 - both branches have been created; * 1 - one branch is hopeless and has been pruned, so now the current * subproblem is other branch; * 2 - both branches are hopeless and have been pruned; new subproblem * selection is needed to continue the search. */ static int branch_on(glp_tree *T, int j, int next) { glp_prob *mip = T->mip; IOSNPD *node; int m = mip->m; int n = mip->n; int type, dn_type, up_type, dn_bad, up_bad, p, ret, clone[1+2]; double lb, ub, beta, new_ub, new_lb, dn_lp, up_lp, dn_bnd, up_bnd; /* determine bounds and value of x[j] in optimal solution to LP relaxation of the current subproblem */ xassert(1 <= j && j <= n); type = mip->col[j]->type; lb = mip->col[j]->lb; ub = mip->col[j]->ub; beta = mip->col[j]->prim; /* determine new bounds of x[j] for down- and up-branches */ new_ub = floor(beta); new_lb = ceil(beta); switch (type) { case GLP_FR: dn_type = GLP_UP; up_type = GLP_LO; break; case GLP_LO: xassert(lb <= new_ub); dn_type = (lb == new_ub ? GLP_FX : GLP_DB); xassert(lb + 1.0 <= new_lb); up_type = GLP_LO; break; case GLP_UP: xassert(new_ub <= ub - 1.0); dn_type = GLP_UP; xassert(new_lb <= ub); up_type = (new_lb == ub ? GLP_FX : GLP_DB); break; case GLP_DB: xassert(lb <= new_ub && new_ub <= ub - 1.0); dn_type = (lb == new_ub ? GLP_FX : GLP_DB); xassert(lb + 1.0 <= new_lb && new_lb <= ub); up_type = (new_lb == ub ? GLP_FX : GLP_DB); break; default: xassert(type != type); } /* compute local bounds to LP relaxation for both branches */ ios_eval_degrad(T, j, &dn_lp, &up_lp); /* and improve them by rounding */ dn_bnd = ios_round_bound(T, dn_lp); up_bnd = ios_round_bound(T, up_lp); /* check local bounds for down- and up-branches */ dn_bad = !ios_is_hopeful(T, dn_bnd); up_bad = !ios_is_hopeful(T, up_bnd); if (dn_bad && up_bad) { if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("Both down- and up-branches are hopeless\n"); ret = 2; goto done; } else if (up_bad) { if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("Up-branch is hopeless\n"); glp_set_col_bnds(mip, j, dn_type, lb, new_ub); T->curr->lp_obj = dn_lp; if (mip->dir == GLP_MIN) { if (T->curr->bound < dn_bnd) T->curr->bound = dn_bnd; } else if (mip->dir == GLP_MAX) { if (T->curr->bound > dn_bnd) T->curr->bound = dn_bnd; } else xassert(mip != mip); ret = 1; goto done; } else if (dn_bad) { if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("Down-branch is hopeless\n"); glp_set_col_bnds(mip, j, up_type, new_lb, ub); T->curr->lp_obj = up_lp; if (mip->dir == GLP_MIN) { if (T->curr->bound < up_bnd) T->curr->bound = up_bnd; } else if (mip->dir == GLP_MAX) { if (T->curr->bound > up_bnd) T->curr->bound = up_bnd; } else xassert(mip != mip); ret = 1; goto done; } /* both down- and up-branches seem to be hopeful */ if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("Branching on column %d, primal value is %.9e\n", j, beta); /* determine the reference number of the current subproblem */ xassert(T->curr != NULL); p = T->curr->p; T->curr->br_var = j; T->curr->br_val = beta; /* freeze the current subproblem */ ios_freeze_node(T); /* create two clones of the current subproblem; the first clone begins the down-branch, the second one begins the up-branch */ ios_clone_node(T, p, 2, clone); if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("Node %d begins down branch, node %d begins up branch " "\n", clone[1], clone[2]); /* set new upper bound of j-th column in the down-branch */ node = T->slot[clone[1]].node; xassert(node != NULL); xassert(node->up != NULL); xassert(node->b_ptr == NULL); node->b_ptr = dmp_get_atom(T->pool, sizeof(IOSBND)); node->b_ptr->k = m + j; node->b_ptr->type = (unsigned char)dn_type; node->b_ptr->lb = lb; node->b_ptr->ub = new_ub; node->b_ptr->next = NULL; node->lp_obj = dn_lp; if (mip->dir == GLP_MIN) { if (node->bound < dn_bnd) node->bound = dn_bnd; } else if (mip->dir == GLP_MAX) { if (node->bound > dn_bnd) node->bound = dn_bnd; } else xassert(mip != mip); /* set new lower bound of j-th column in the up-branch */ node = T->slot[clone[2]].node; xassert(node != NULL); xassert(node->up != NULL); xassert(node->b_ptr == NULL); node->b_ptr = dmp_get_atom(T->pool, sizeof(IOSBND)); node->b_ptr->k = m + j; node->b_ptr->type = (unsigned char)up_type; node->b_ptr->lb = new_lb; node->b_ptr->ub = ub; node->b_ptr->next = NULL; node->lp_obj = up_lp; if (mip->dir == GLP_MIN) { if (node->bound < up_bnd) node->bound = up_bnd; } else if (mip->dir == GLP_MAX) { if (node->bound > up_bnd) node->bound = up_bnd; } else xassert(mip != mip); /* suggest the subproblem to be solved next */ xassert(T->child == 0); if (next == GLP_NO_BRNCH) T->child = 0; else if (next == GLP_DN_BRNCH) T->child = clone[1]; else if (next == GLP_UP_BRNCH) T->child = clone[2]; else xassert(next != next); ret = 0; done: return ret; } /*********************************************************************** * cleanup_the_tree - prune hopeless branches from the tree * * This routine walks through the active list and checks the local * bound for every active subproblem. If the local bound indicates that * the subproblem cannot have integer optimal solution better than the * incumbent objective value, the routine deletes such subproblem that, * in turn, involves pruning the corresponding branch of the tree. */ static void cleanup_the_tree(glp_tree *T) { IOSNPD *node, *next_node; int count = 0; /* the global bound must exist */ xassert(T->mip->mip_stat == GLP_FEAS); /* walk through the list of active subproblems */ for (node = T->head; node != NULL; node = next_node) { /* deleting some active problem node may involve deleting its parents recursively; however, all its parents being created *before* it are always *precede* it in the node list, so the next problem node is never affected by such deletion */ next_node = node->next; /* if the branch is hopeless, prune it */ if (!is_branch_hopeful(T, node->p)) ios_delete_node(T, node->p), count++; } if (T->parm->msg_lev >= GLP_MSG_DBG) { if (count == 1) xprintf("One hopeless branch has been pruned\n"); else if (count > 1) xprintf("%d hopeless branches have been pruned\n", count); } return; } #if 0 /* 09/VII-2013 */ /*********************************************************************** * round_heur - simple rounding heuristic * * This routine attempts to guess an integer feasible solution by * simple rounding values of all integer variables in basic solution to * nearest integers. */ static int round_heur(glp_tree *T) { glp_prob *P = T->mip; int m = P->m; int n = P->n; int i, j, ret; double *x; /* compute rounded values of variables */ x = talloc(1+n, double); for (j = 1; j <= n; j++) { GLPCOL *col = P->col[j]; if (col->kind == GLP_IV) { /* integer variable */ x[j] = floor(col->prim + 0.5); } else if (col->type == GLP_FX) { /* fixed variable */ x[j] = col->prim; } else { /* non-integer non-fixed variable */ ret = 3; goto done; } } /* check that no constraints are violated */ for (i = 1; i <= m; i++) { GLPROW *row = P->row[i]; int type = row->type; GLPAIJ *aij; double sum; if (type == GLP_FR) continue; /* compute value of linear form */ sum = 0.0; for (aij = row->ptr; aij != NULL; aij = aij->r_next) sum += aij->val * x[aij->col->j]; /* check lower bound */ if (type == GLP_LO || type == GLP_DB || type == GLP_FX) { if (sum < row->lb - 1e-9) { /* lower bound is violated */ ret = 2; goto done; } } /* check upper bound */ if (type == GLP_UP || type == GLP_DB || type == GLP_FX) { if (sum > row->ub + 1e-9) { /* upper bound is violated */ ret = 2; goto done; } } } /* rounded solution is integer feasible */ if (glp_ios_heur_sol(T, x) == 0) { /* solution is accepted */ ret = 0; } else { /* solution is rejected */ ret = 1; } done: tfree(x); return ret; } #else /*********************************************************************** * round_heur - simple rounding heuristic * * This routine attempts to guess an integer feasible solution by * simple rounding values of all integer variables in basic solution to * nearest integers. */ static int round_heur(glp_tree *T) { glp_prob *P = T->mip; /*int m = P->m;*/ int n = P->n; int i, j, ret; double *x; /* compute rounded values of variables */ x = talloc(1+n, double); for (j = 1; j <= n; j++) { GLPCOL *col = P->col[j]; if (col->kind == GLP_IV) { /* integer variable */ x[j] = floor(col->prim + 0.5); } else if (col->type == GLP_FX) { /* fixed variable */ x[j] = col->prim; } else { /* non-integer non-fixed variable */ ret = 3; goto done; } } /* check that no constraints are violated */ for (i = 1; i <= T->orig_m; i++) { int type = T->orig_type[i]; GLPAIJ *aij; double sum; if (type == GLP_FR) continue; /* compute value of linear form */ sum = 0.0; for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next) sum += aij->val * x[aij->col->j]; /* check lower bound */ if (type == GLP_LO || type == GLP_DB || type == GLP_FX) { if (sum < T->orig_lb[i] - 1e-9) { /* lower bound is violated */ ret = 2; goto done; } } /* check upper bound */ if (type == GLP_UP || type == GLP_DB || type == GLP_FX) { if (sum > T->orig_ub[i] + 1e-9) { /* upper bound is violated */ ret = 2; goto done; } } } /* rounded solution is integer feasible */ if (glp_ios_heur_sol(T, x) == 0) { /* solution is accepted */ ret = 0; } else { /* solution is rejected */ ret = 1; } done: tfree(x); return ret; } #endif #if 0 #define round_heur round_heur2 static int round_heur(glp_tree *T) { glp_prob *lp; int *ind, ret, i, j, len; double *val; lp = glp_create_prob(); ind = talloc(1+T->mip->n, int); val = talloc(1+T->mip->n, double); glp_add_rows(lp, T->orig_m); glp_add_cols(lp, T->n); for (i = 1; i <= T->orig_m; i++) { glp_set_row_bnds(lp, i, T->orig_type[i], T->orig_lb[i], T->orig_ub[i]); len = glp_get_mat_row(T->mip, i, ind, val); glp_set_mat_row(lp, i, len, ind, val); } for (j = 1; j <= T->n; j++) { GLPCOL *col = T->mip->col[j]; glp_set_obj_coef(lp, j, col->coef); if (col->kind == GLP_IV) { /* integer variable */ glp_set_col_bnds(lp, j, GLP_FX, floor(col->prim + .5), 0); } else { glp_set_col_bnds(lp, j, T->orig_type[T->orig_m+j], T->orig_lb[T->orig_m+j], T->orig_ub[T->orig_m+j]); } } glp_term_out(GLP_OFF); glp_adv_basis(lp, 0); ret = glp_simplex(lp, NULL); glp_term_out(GLP_ON); if (ret != 0) { ret = 1; goto done; } if (glp_get_status(lp) != GLP_OPT) { ret = 2; goto done; } for (j = 1; j <= lp->n; j++) val[j] = lp->col[j]->prim; if (glp_ios_heur_sol(T, val) == 0) ret = 0; else ret = 3; done: glp_delete_prob(lp); tfree(ind); tfree(val); return ret; } #endif /**********************************************************************/ static void generate_cuts(glp_tree *T) { /* generate generic cuts with built-in generators */ if (!(T->parm->mir_cuts == GLP_ON || T->parm->gmi_cuts == GLP_ON || T->parm->cov_cuts == GLP_ON || T->parm->clq_cuts == GLP_ON)) goto done; #if 1 /* 20/IX-2008 */ { int i, max_cuts, added_cuts; max_cuts = T->n; if (max_cuts < 1000) max_cuts = 1000; added_cuts = 0; for (i = T->orig_m+1; i <= T->mip->m; i++) { if (T->mip->row[i]->origin == GLP_RF_CUT) added_cuts++; } /* xprintf("added_cuts = %d\n", added_cuts); */ if (added_cuts >= max_cuts) goto done; } #endif /* generate and add to POOL all cuts violated by x* */ if (T->parm->gmi_cuts == GLP_ON) { if (T->curr->changed < 7) ios_gmi_gen(T); } if (T->parm->mir_cuts == GLP_ON) { xassert(T->mir_gen != NULL); ios_mir_gen(T, T->mir_gen); } if (T->parm->cov_cuts == GLP_ON) { /* cover cuts works well along with mir cuts */ /*if (T->round <= 5)*/ ios_cov_gen(T); } if (T->parm->clq_cuts == GLP_ON) { if (T->clq_gen != NULL) #if 0 /* 29/VI-2013 */ { if (T->curr->level == 0 && T->curr->changed < 50 || T->curr->level > 0 && T->curr->changed < 5) #else /* FIXME */ { if (T->curr->level == 0 && T->curr->changed < 500 || T->curr->level > 0 && T->curr->changed < 50) #endif ios_clq_gen(T, T->clq_gen); } } done: return; } /**********************************************************************/ static void remove_cuts(glp_tree *T) { /* remove inactive cuts (some valueable globally valid cut might be saved in the global cut pool) */ int i, cnt = 0, *num = NULL; xassert(T->curr != NULL); for (i = T->orig_m+1; i <= T->mip->m; i++) { if (T->mip->row[i]->origin == GLP_RF_CUT && T->mip->row[i]->level == T->curr->level && T->mip->row[i]->stat == GLP_BS) { if (num == NULL) num = xcalloc(1+T->mip->m, sizeof(int)); num[++cnt] = i; } } if (cnt > 0) { glp_del_rows(T->mip, cnt, num); #if 0 xprintf("%d inactive cut(s) removed\n", cnt); #endif xfree(num); xassert(glp_factorize(T->mip) == 0); } return; } /**********************************************************************/ static void display_cut_info(glp_tree *T) { glp_prob *mip = T->mip; int i, gmi = 0, mir = 0, cov = 0, clq = 0, app = 0; for (i = mip->m; i > 0; i--) { GLPROW *row; row = mip->row[i]; /* if (row->level < T->curr->level) break; */ if (row->origin == GLP_RF_CUT) { if (row->klass == GLP_RF_GMI) gmi++; else if (row->klass == GLP_RF_MIR) mir++; else if (row->klass == GLP_RF_COV) cov++; else if (row->klass == GLP_RF_CLQ) clq++; else app++; } } xassert(T->curr != NULL); if (gmi + mir + cov + clq + app > 0) { xprintf("Cuts on level %d:", T->curr->level); if (gmi > 0) xprintf(" gmi = %d;", gmi); if (mir > 0) xprintf(" mir = %d;", mir); if (cov > 0) xprintf(" cov = %d;", cov); if (clq > 0) xprintf(" clq = %d;", clq); if (app > 0) xprintf(" app = %d;", app); xprintf("\n"); } return; } /*********************************************************************** * NAME * * ios_driver - branch-and-cut driver * * SYNOPSIS * * #include "glpios.h" * int ios_driver(glp_tree *T); * * DESCRIPTION * * The routine ios_driver is a branch-and-cut driver. It controls the * MIP solution process. * * RETURNS * * 0 The MIP problem instance has been successfully solved. This code * does not necessarily mean that the solver has found optimal * solution. It only means that the solution process was successful. * * GLP_EFAIL * The search was prematurely terminated due to the solver failure. * * GLP_EMIPGAP * The search was prematurely terminated, because the relative mip * gap tolerance has been reached. * * GLP_ETMLIM * The search was prematurely terminated, because the time limit has * been exceeded. * * GLP_ESTOP * The search was prematurely terminated by application. */ int ios_driver(glp_tree *T) { int p, curr_p, p_stat, d_stat, ret; #if 1 /* carry out to glp_tree */ int pred_p = 0; /* if the current subproblem has been just created due to branching, pred_p is the reference number of its parent subproblem, otherwise pred_p is zero */ #endif #if 1 /* 18/VII-2013 */ int bad_cut; double old_obj; #endif #if 0 /* 10/VI-2013 */ glp_long ttt = T->tm_beg; #else double ttt = T->tm_beg; #endif #if 0 ((glp_iocp *)T->parm)->msg_lev = GLP_MSG_DBG; #endif /* on entry to the B&B driver it is assumed that the active list contains the only active (i.e. root) subproblem, which is the original MIP problem to be solved */ loop: /* main loop starts here */ /* at this point the current subproblem does not exist */ xassert(T->curr == NULL); /* if the active list is empty, the search is finished */ if (T->head == NULL) { if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("Active list is empty!\n"); #if 0 /* 10/VI-2013 */ xassert(dmp_in_use(T->pool).lo == 0); #else xassert(dmp_in_use(T->pool) == 0); #endif ret = 0; goto done; } /* select some active subproblem to continue the search */ xassert(T->next_p == 0); /* let the application program select subproblem */ if (T->parm->cb_func != NULL) { xassert(T->reason == 0); T->reason = GLP_ISELECT; T->parm->cb_func(T, T->parm->cb_info); T->reason = 0; if (T->stop) { ret = GLP_ESTOP; goto done; } } if (T->next_p != 0) { /* the application program has selected something */ ; } else if (T->a_cnt == 1) { /* the only active subproblem exists, so select it */ xassert(T->head->next == NULL); T->next_p = T->head->p; } else if (T->child != 0) { /* select one of branching childs suggested by the branching heuristic */ T->next_p = T->child; } else { /* select active subproblem as specified by the backtracking technique option */ T->next_p = ios_choose_node(T); } /* the active subproblem just selected becomes current */ ios_revive_node(T, T->next_p); T->next_p = T->child = 0; /* invalidate pred_p, if it is not the reference number of the parent of the current subproblem */ if (T->curr->up != NULL && T->curr->up->p != pred_p) pred_p = 0; /* determine the reference number of the current subproblem */ p = T->curr->p; if (T->parm->msg_lev >= GLP_MSG_DBG) { xprintf("-----------------------------------------------------" "-------------------\n"); xprintf("Processing node %d at level %d\n", p, T->curr->level); } /* if it is the root subproblem, initialize cut generators */ if (p == 1) { if (T->parm->gmi_cuts == GLP_ON) { if (T->parm->msg_lev >= GLP_MSG_ALL) xprintf("Gomory's cuts enabled\n"); } if (T->parm->mir_cuts == GLP_ON) { if (T->parm->msg_lev >= GLP_MSG_ALL) xprintf("MIR cuts enabled\n"); xassert(T->mir_gen == NULL); T->mir_gen = ios_mir_init(T); } if (T->parm->cov_cuts == GLP_ON) { if (T->parm->msg_lev >= GLP_MSG_ALL) xprintf("Cover cuts enabled\n"); } if (T->parm->clq_cuts == GLP_ON) { xassert(T->clq_gen == NULL); if (T->parm->msg_lev >= GLP_MSG_ALL) xprintf("Clique cuts enabled\n"); T->clq_gen = ios_clq_init(T); } } #if 1 /* 18/VII-2013 */ bad_cut = 0; #endif more: /* minor loop starts here */ /* at this point the current subproblem needs either to be solved for the first time or re-optimized due to reformulation */ /* display current progress of the search */ if (T->parm->msg_lev >= GLP_MSG_DBG || T->parm->msg_lev >= GLP_MSG_ON && (double)(T->parm->out_frq - 1) <= 1000.0 * xdifftime(xtime(), T->tm_lag)) show_progress(T, 0); if (T->parm->msg_lev >= GLP_MSG_ALL && xdifftime(xtime(), ttt) >= 60.0) #if 0 /* 16/II-2012 */ { glp_long total; glp_mem_usage(NULL, NULL, &total, NULL); xprintf("Time used: %.1f secs. Memory used: %.1f Mb.\n", xdifftime(xtime(), T->tm_beg), xltod(total) / 1048576.0); ttt = xtime(); } #else { size_t total; glp_mem_usage(NULL, NULL, &total, NULL); xprintf("Time used: %.1f secs. Memory used: %.1f Mb.\n", xdifftime(xtime(), T->tm_beg), (double)total / 1048576.0); ttt = xtime(); } #endif /* check the mip gap */ if (T->parm->mip_gap > 0.0 && ios_relative_gap(T) <= T->parm->mip_gap) { if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("Relative gap tolerance reached; search terminated " "\n"); ret = GLP_EMIPGAP; goto done; } /* check if the time limit has been exhausted */ if (T->parm->tm_lim < INT_MAX && (double)(T->parm->tm_lim - 1) <= 1000.0 * xdifftime(xtime(), T->tm_beg)) { if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("Time limit exhausted; search terminated\n"); ret = GLP_ETMLIM; goto done; } /* let the application program preprocess the subproblem */ if (T->parm->cb_func != NULL) { xassert(T->reason == 0); T->reason = GLP_IPREPRO; T->parm->cb_func(T, T->parm->cb_info); T->reason = 0; if (T->stop) { ret = GLP_ESTOP; goto done; } } /* perform basic preprocessing */ if (T->parm->pp_tech == GLP_PP_NONE) ; else if (T->parm->pp_tech == GLP_PP_ROOT) { if (T->curr->level == 0) { if (ios_preprocess_node(T, 100)) goto fath; } } else if (T->parm->pp_tech == GLP_PP_ALL) { if (ios_preprocess_node(T, T->curr->level == 0 ? 100 : 10)) goto fath; } else xassert(T != T); /* preprocessing may improve the global bound */ if (!is_branch_hopeful(T, p)) { xprintf("*** not tested yet ***\n"); goto fath; } /* solve LP relaxation of the current subproblem */ if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("Solving LP relaxation...\n"); ret = ios_solve_node(T); if (!(ret == 0 || ret == GLP_EOBJLL || ret == GLP_EOBJUL)) { if (T->parm->msg_lev >= GLP_MSG_ERR) xprintf("ios_driver: unable to solve current LP relaxation;" " glp_simplex returned %d\n", ret); ret = GLP_EFAIL; goto done; } /* analyze status of the basic solution to LP relaxation found */ p_stat = T->mip->pbs_stat; d_stat = T->mip->dbs_stat; if (p_stat == GLP_FEAS && d_stat == GLP_FEAS) { /* LP relaxation has optimal solution */ if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("Found optimal solution to LP relaxation\n"); } else if (d_stat == GLP_NOFEAS) { /* LP relaxation has no dual feasible solution */ /* since the current subproblem cannot have a larger feasible region than its parent, there is something wrong */ if (T->parm->msg_lev >= GLP_MSG_ERR) xprintf("ios_driver: current LP relaxation has no dual feas" "ible solution\n"); ret = GLP_EFAIL; goto done; } else if (p_stat == GLP_INFEAS && d_stat == GLP_FEAS) { /* LP relaxation has no primal solution which is better than the incumbent objective value */ xassert(T->mip->mip_stat == GLP_FEAS); if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("LP relaxation has no solution better than incumben" "t objective value\n"); /* prune the branch */ goto fath; } else if (p_stat == GLP_NOFEAS) { /* LP relaxation has no primal feasible solution */ if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("LP relaxation has no feasible solution\n"); /* prune the branch */ goto fath; } else { /* other cases cannot appear */ xassert(T->mip != T->mip); } /* at this point basic solution to LP relaxation of the current subproblem is optimal */ xassert(p_stat == GLP_FEAS && d_stat == GLP_FEAS); xassert(T->curr != NULL); T->curr->lp_obj = T->mip->obj_val; /* thus, it defines a local bound to integer optimal solution of the current subproblem */ { double bound = T->mip->obj_val; /* some local bound to the current subproblem could be already set before, so we should only improve it */ bound = ios_round_bound(T, bound); if (T->mip->dir == GLP_MIN) { if (T->curr->bound < bound) T->curr->bound = bound; } else if (T->mip->dir == GLP_MAX) { if (T->curr->bound > bound) T->curr->bound = bound; } else xassert(T->mip != T->mip); if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("Local bound is %.9e\n", bound); } /* if the local bound indicates that integer optimal solution of the current subproblem cannot be better than the global bound, prune the branch */ if (!is_branch_hopeful(T, p)) { if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("Current branch is hopeless and can be pruned\n"); goto fath; } /* let the application program generate additional rows ("lazy" constraints) */ xassert(T->reopt == 0); xassert(T->reinv == 0); if (T->parm->cb_func != NULL) { xassert(T->reason == 0); T->reason = GLP_IROWGEN; T->parm->cb_func(T, T->parm->cb_info); T->reason = 0; if (T->stop) { ret = GLP_ESTOP; goto done; } if (T->reopt) { /* some rows were added; re-optimization is needed */ T->reopt = T->reinv = 0; goto more; } if (T->reinv) { /* no rows were added, however, some inactive rows were removed */ T->reinv = 0; xassert(glp_factorize(T->mip) == 0); } } /* check if the basic solution is integer feasible */ check_integrality(T); /* if the basic solution satisfies to all integrality conditions, it is a new, better integer feasible solution */ if (T->curr->ii_cnt == 0) { if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("New integer feasible solution found\n"); if (T->parm->msg_lev >= GLP_MSG_ALL) display_cut_info(T); record_solution(T); if (T->parm->msg_lev >= GLP_MSG_ON) show_progress(T, 1); #if 1 /* 11/VII-2013 */ ios_process_sol(T); #endif /* make the application program happy */ if (T->parm->cb_func != NULL) { xassert(T->reason == 0); T->reason = GLP_IBINGO; T->parm->cb_func(T, T->parm->cb_info); T->reason = 0; if (T->stop) { ret = GLP_ESTOP; goto done; } } /* since the current subproblem has been fathomed, prune its branch */ goto fath; } /* at this point basic solution to LP relaxation of the current subproblem is optimal, but integer infeasible */ /* try to fix some non-basic structural variables of integer kind on their current bounds due to reduced costs */ if (T->mip->mip_stat == GLP_FEAS) fix_by_red_cost(T); /* let the application program try to find some solution to the original MIP with a primal heuristic */ if (T->parm->cb_func != NULL) { xassert(T->reason == 0); T->reason = GLP_IHEUR; T->parm->cb_func(T, T->parm->cb_info); T->reason = 0; if (T->stop) { ret = GLP_ESTOP; goto done; } /* check if the current branch became hopeless */ if (!is_branch_hopeful(T, p)) { if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("Current branch became hopeless and can be prune" "d\n"); goto fath; } } /* try to find solution with the feasibility pump heuristic */ if (T->parm->fp_heur) { xassert(T->reason == 0); T->reason = GLP_IHEUR; ios_feas_pump(T); T->reason = 0; /* check if the current branch became hopeless */ if (!is_branch_hopeful(T, p)) { if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("Current branch became hopeless and can be prune" "d\n"); goto fath; } } #if 1 /* 25/V-2013 */ /* try to find solution with the proximity search heuristic */ if (T->parm->ps_heur) { xassert(T->reason == 0); T->reason = GLP_IHEUR; ios_proxy_heur(T); T->reason = 0; /* check if the current branch became hopeless */ if (!is_branch_hopeful(T, p)) { if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("Current branch became hopeless and can be prune" "d\n"); goto fath; } } #endif #if 1 /* 09/VII-2013 */ /* try to find solution with a simple rounding heuristic */ { xassert(T->reason == 0); T->reason = GLP_IHEUR; round_heur(T); T->reason = 0; /* check if the current branch became hopeless */ if (!is_branch_hopeful(T, p)) { if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("Current branch became hopeless and can be prune" "d\n"); goto fath; } } #endif /* it's time to generate cutting planes */ xassert(T->local != NULL); xassert(T->local->size == 0); /* let the application program generate some cuts; note that it can add cuts either to the local cut pool or directly to the current subproblem */ if (T->parm->cb_func != NULL) { xassert(T->reason == 0); T->reason = GLP_ICUTGEN; T->parm->cb_func(T, T->parm->cb_info); T->reason = 0; if (T->stop) { ret = GLP_ESTOP; goto done; } } #if 1 /* 18/VII-2013 */ if (T->curr->changed > 0) { double degrad = fabs(T->curr->lp_obj - old_obj); if (degrad < 1e-4 * (1.0 + fabs(old_obj))) bad_cut++; else bad_cut = 0; } old_obj = T->curr->lp_obj; if (bad_cut == 0 || (T->curr->level == 0 && bad_cut <= 3)) #endif /* try to generate generic cuts with built-in generators (as suggested by Prof. Fischetti et al. the built-in cuts are not generated at each branching node; an intense attempt of generating new cuts is only made at the root node, and then a moderate effort is spent after each backtracking step) */ if (T->curr->level == 0 || pred_p == 0) { xassert(T->reason == 0); T->reason = GLP_ICUTGEN; generate_cuts(T); T->reason = 0; } /* if the local cut pool is not empty, select useful cuts and add them to the current subproblem */ if (T->local->size > 0) { xassert(T->reason == 0); T->reason = GLP_ICUTGEN; ios_process_cuts(T); T->reason = 0; } /* clear the local cut pool */ ios_clear_pool(T, T->local); /* perform re-optimization, if necessary */ if (T->reopt) { T->reopt = 0; T->curr->changed++; goto more; } /* no cuts were generated; remove inactive cuts */ remove_cuts(T); if (T->parm->msg_lev >= GLP_MSG_ALL && T->curr->level == 0) display_cut_info(T); /* update history information used on pseudocost branching */ if (T->pcost != NULL) ios_pcost_update(T); /* it's time to perform branching */ xassert(T->br_var == 0); xassert(T->br_sel == 0); /* let the application program choose variable to branch on */ if (T->parm->cb_func != NULL) { xassert(T->reason == 0); xassert(T->br_var == 0); xassert(T->br_sel == 0); T->reason = GLP_IBRANCH; T->parm->cb_func(T, T->parm->cb_info); T->reason = 0; if (T->stop) { ret = GLP_ESTOP; goto done; } } /* if nothing has been chosen, choose some variable as specified by the branching technique option */ if (T->br_var == 0) T->br_var = ios_choose_var(T, &T->br_sel); /* perform actual branching */ curr_p = T->curr->p; ret = branch_on(T, T->br_var, T->br_sel); T->br_var = T->br_sel = 0; if (ret == 0) { /* both branches have been created */ pred_p = curr_p; goto loop; } else if (ret == 1) { /* one branch is hopeless and has been pruned, so now the current subproblem is other branch */ /* the current subproblem should be considered as a new one, since one bound of the branching variable was changed */ T->curr->solved = T->curr->changed = 0; #if 1 /* 18/VII-2013 */ /* bad_cut = 0; */ #endif goto more; } else if (ret == 2) { /* both branches are hopeless and have been pruned; new subproblem selection is needed to continue the search */ goto fath; } else xassert(ret != ret); fath: /* the current subproblem has been fathomed */ if (T->parm->msg_lev >= GLP_MSG_DBG) xprintf("Node %d fathomed\n", p); /* freeze the current subproblem */ ios_freeze_node(T); /* and prune the corresponding branch of the tree */ ios_delete_node(T, p); /* if a new integer feasible solution has just been found, other branches may become hopeless and therefore must be pruned */ if (T->mip->mip_stat == GLP_FEAS) cleanup_the_tree(T); /* new subproblem selection is needed due to backtracking */ pred_p = 0; goto loop; done: /* display progress of the search on exit from the solver */ if (T->parm->msg_lev >= GLP_MSG_ON) show_progress(T, 0); if (T->mir_gen != NULL) ios_mir_term(T->mir_gen), T->mir_gen = NULL; if (T->clq_gen != NULL) ios_clq_term(T->clq_gen), T->clq_gen = NULL; /* return to the calling program */ return ret; } /* eof */ Rglpk/src/GLPK/bignum.c0000644000176000001440000002246312245352174014346 0ustar ripleyusers/* bignum.c (bignum arithmetic) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2006, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #include "bignum.h" /*********************************************************************** * Two routines below are intended to multiply and divide unsigned * integer numbers of arbitrary precision. * * The routines assume that an unsigned integer number is represented in * the positional numeral system with the base 2^16 = 65536, i.e. each * "digit" of the number is in the range [0, 65535] and represented as * a 16-bit value of the unsigned short type. In other words, a number x * has the following representation: * * n-1 * x = sum d[j] * 65536^j, * j=0 * * where n is the number of places (positions), and d[j] is j-th "digit" * of x, 0 <= d[j] <= 65535. ***********************************************************************/ /*********************************************************************** * NAME * * bigmul - multiply unsigned integer numbers of arbitrary precision * * SYNOPSIS * * #include "bignum.h" * void bigmul(int n, int m, unsigned short x[], unsigned short y[]); * * DESCRIPTION * * The routine bigmul multiplies unsigned integer numbers of arbitrary * precision. * * n is the number of digits of multiplicand, n >= 1; * * m is the number of digits of multiplier, m >= 1; * * x is an array containing digits of the multiplicand in elements * x[m], x[m+1], ..., x[n+m-1]. Contents of x[0], x[1], ..., x[m-1] are * ignored on entry. * * y is an array containing digits of the multiplier in elements y[0], * y[1], ..., y[m-1]. * * On exit digits of the product are stored in elements x[0], x[1], ..., * x[n+m-1]. The array y is not changed. */ void bigmul(int n, int m, unsigned short x[], unsigned short y[]) { int i, j; unsigned int t; xassert(n >= 1); xassert(m >= 1); for (j = 0; j < m; j++) x[j] = 0; for (i = 0; i < n; i++) { if (x[i+m]) { t = 0; for (j = 0; j < m; j++) { t += (unsigned int)x[i+m] * (unsigned int)y[j] + (unsigned int)x[i+j]; x[i+j] = (unsigned short)t; t >>= 16; } x[i+m] = (unsigned short)t; } } return; } /*********************************************************************** * NAME * * bigdiv - divide unsigned integer numbers of arbitrary precision * * SYNOPSIS * * #include "bignum.h" * void bigdiv(int n, int m, unsigned short x[], unsigned short y[]); * * DESCRIPTION * * The routine bigdiv divides one unsigned integer number of arbitrary * precision by another with the algorithm described in [1]. * * n is the difference between the number of digits of dividend and the * number of digits of divisor, n >= 0. * * m is the number of digits of divisor, m >= 1. * * x is an array containing digits of the dividend in elements x[0], * x[1], ..., x[n+m-1]. * * y is an array containing digits of the divisor in elements y[0], * y[1], ..., y[m-1]. The highest digit y[m-1] must be non-zero. * * On exit n+1 digits of the quotient are stored in elements x[m], * x[m+1], ..., x[n+m], and m digits of the remainder are stored in * elements x[0], x[1], ..., x[m-1]. The array y is changed but then * restored. * * REFERENCES * * 1. D. Knuth. The Art of Computer Programming. Vol. 2: Seminumerical * Algorithms. Stanford University, 1969. */ void bigdiv(int n, int m, unsigned short x[], unsigned short y[]) { int i, j; unsigned int t; unsigned short d, q, r; xassert(n >= 0); xassert(m >= 1); xassert(y[m-1] != 0); /* special case when divisor has the only digit */ if (m == 1) { d = 0; for (i = n; i >= 0; i--) { t = ((unsigned int)d << 16) + (unsigned int)x[i]; x[i+1] = (unsigned short)(t / y[0]); d = (unsigned short)(t % y[0]); } x[0] = d; goto done; } /* multiply dividend and divisor by a normalizing coefficient in * order to provide the condition y[m-1] >= base / 2 */ d = (unsigned short)(0x10000 / ((unsigned int)y[m-1] + 1)); if (d == 1) x[n+m] = 0; else { t = 0; for (i = 0; i < n+m; i++) { t += (unsigned int)x[i] * (unsigned int)d; x[i] = (unsigned short)t; t >>= 16; } x[n+m] = (unsigned short)t; t = 0; for (j = 0; j < m; j++) { t += (unsigned int)y[j] * (unsigned int)d; y[j] = (unsigned short)t; t >>= 16; } } /* main loop */ for (i = n; i >= 0; i--) { /* estimate and correct the current digit of quotient */ if (x[i+m] < y[m-1]) { t = ((unsigned int)x[i+m] << 16) + (unsigned int)x[i+m-1]; q = (unsigned short)(t / (unsigned int)y[m-1]); r = (unsigned short)(t % (unsigned int)y[m-1]); if (q == 0) goto putq; else goto test; } q = 0; r = x[i+m-1]; decr: q--; /* if q = 0 then q-- = 0xFFFF */ t = (unsigned int)r + (unsigned int)y[m-1]; r = (unsigned short)t; if (t > 0xFFFF) goto msub; test: t = (unsigned int)y[m-2] * (unsigned int)q; if ((unsigned short)(t >> 16) > r) goto decr; if ((unsigned short)(t >> 16) < r) goto msub; if ((unsigned short)t > x[i+m-2]) goto decr; msub: /* now subtract divisor multiplied by the current digit of * quotient from the current dividend */ if (q == 0) goto putq; t = 0; for (j = 0; j < m; j++) { t += (unsigned int)y[j] * (unsigned int)q; if (x[i+j] < (unsigned short)t) t += 0x10000; x[i+j] -= (unsigned short)t; t >>= 16; } if (x[i+m] >= (unsigned short)t) goto putq; /* perform correcting addition, because the current digit of * quotient is greater by one than its correct value */ q--; t = 0; for (j = 0; j < m; j++) { t += (unsigned int)x[i+j] + (unsigned int)y[j]; x[i+j] = (unsigned short)t; t >>= 16; } putq: /* store the current digit of quotient */ x[i+m] = q; } /* divide divisor and remainder by the normalizing coefficient in * order to restore their original values */ if (d > 1) { t = 0; for (i = m-1; i >= 0; i--) { t = (t << 16) + (unsigned int)x[i]; x[i] = (unsigned short)(t / (unsigned int)d); t %= (unsigned int)d; } t = 0; for (j = m-1; j >= 0; j--) { t = (t << 16) + (unsigned int)y[j]; y[j] = (unsigned short)(t / (unsigned int)d); t %= (unsigned int)d; } } done: return; } /**********************************************************************/ #ifdef GLP_TEST #include #include #include #include "rng.h" #define N_MAX 7 /* maximal number of digits in multiplicand */ #define M_MAX 5 /* maximal number of digits in multiplier */ #define N_TEST 1000000 /* number of tests */ int main(void) { RNG *rand; int d, j, n, m, test; unsigned short x[N_MAX], y[M_MAX], z[N_MAX+M_MAX]; rand = rng_create_rand(); for (test = 1; test <= N_TEST; test++) { /* x[0,...,n-1] := multiplicand */ n = 1 + rng_unif_rand(rand, N_MAX-1); assert(1 <= n && n <= N_MAX); for (j = 0; j < n; j++) { d = rng_unif_rand(rand, 65536); assert(0 <= d && d <= 65535); x[j] = (unsigned short)d; } /* y[0,...,m-1] := multiplier */ m = 1 + rng_unif_rand(rand, M_MAX-1); assert(1 <= m && m <= M_MAX); for (j = 0; j < m; j++) { d = rng_unif_rand(rand, 65536); assert(0 <= d && d <= 65535); y[j] = (unsigned short)d; } if (y[m-1] == 0) y[m-1] = 1; /* z[0,...,n+m-1] := x * y */ for (j = 0; j < n; j++) z[m+j] = x[j]; bigmul(n, m, z, y); /* z[0,...,m-1] := z mod y, z[m,...,n+m-1] := z div y */ bigdiv(n, m, z, y); /* z mod y must be 0 */ for (j = 0; j < m; j++) assert(z[j] == 0); /* z div y must be x */ for (j = 0; j < n; j++) assert(z[m+j] == x[j]); } fprintf(stderr, "%d tests successfully passed\n", N_TEST); rng_delete_rand(rand); return 0; } #endif /* eof */ Rglpk/src/GLPK/glpavl.c0000644000176000001440000002624512245352174014354 0ustar ripleyusers/* glpavl.c (binary search tree) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpavl.h" #include "env.h" AVL *avl_create_tree(int (*fcmp)(void *info, const void *key1, const void *key2), void *info) { /* create AVL tree */ AVL *tree; tree = xmalloc(sizeof(AVL)); tree->pool = dmp_create_pool(); tree->root = NULL; tree->fcmp = fcmp; tree->info = info; tree->size = 0; tree->height = 0; return tree; } int avl_strcmp(void *info, const void *key1, const void *key2) { /* compare character string keys */ xassert(info == info); return strcmp(key1, key2); } static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node); AVLNODE *avl_insert_node(AVL *tree, const void *key) { /* insert new node into AVL tree */ AVLNODE *p, *q, *r; short int flag; /* find an appropriate point for insertion */ p = NULL; q = tree->root; while (q != NULL) { p = q; if (tree->fcmp(tree->info, key, p->key) <= 0) { flag = 0; q = p->left; p->rank++; } else { flag = 1; q = p->right; } } /* create new node and insert it into the tree */ r = dmp_get_atom(tree->pool, sizeof(AVLNODE)); r->key = key; r->type = 0; r->link = NULL; r->rank = 1; r->up = p; r->flag = (short int)(p == NULL ? 0 : flag); r->bal = 0; r->left = NULL; r->right = NULL; tree->size++; if (p == NULL) tree->root = r; else if (flag == 0) p->left = r; else p->right = r; /* go upstairs to the root and correct all subtrees affected by insertion */ while (p != NULL) { if (flag == 0) { /* the height of the left subtree of [p] is increased */ if (p->bal > 0) { p->bal = 0; break; } if (p->bal < 0) { rotate_subtree(tree, p); break; } p->bal = -1; flag = p->flag; p = p->up; } else { /* the height of the right subtree of [p] is increased */ if (p->bal < 0) { p->bal = 0; break; } if (p->bal > 0) { rotate_subtree(tree, p); break; } p->bal = +1; flag = p->flag; p = p->up; } } /* if the root has been reached, the height of the entire tree is increased */ if (p == NULL) tree->height++; return r; } void avl_set_node_type(AVLNODE *node, int type) { /* assign the type field of specified node */ node->type = type; return; } void avl_set_node_link(AVLNODE *node, void *link) { /* assign the link field of specified node */ node->link = link; return; } AVLNODE *avl_find_node(AVL *tree, const void *key) { /* find node in AVL tree */ AVLNODE *p; int c; p = tree->root; while (p != NULL) { c = tree->fcmp(tree->info, key, p->key); if (c == 0) break; p = (c < 0 ? p->left : p->right); } return p; } int avl_get_node_type(AVLNODE *node) { /* retrieve the type field of specified node */ return node->type; } void *avl_get_node_link(AVLNODE *node) { /* retrieve the link field of specified node */ return node->link; } static AVLNODE *find_next_node(AVL *tree, AVLNODE *node) { /* find next node in AVL tree */ AVLNODE *p, *q; if (tree->root == NULL) return NULL; p = node; q = (p == NULL ? tree->root : p->right); if (q == NULL) { /* go upstairs from the left subtree */ for (;;) { q = p->up; if (q == NULL) break; if (p->flag == 0) break; p = q; } } else { /* go downstairs into the right subtree */ for (;;) { p = q->left; if (p == NULL) break; q = p; } } return q; } void avl_delete_node(AVL *tree, AVLNODE *node) { /* delete specified node from AVL tree */ AVLNODE *f, *p, *q, *r, *s, *x, *y; short int flag; p = node; /* if both subtrees of the specified node are non-empty, the node should be interchanged with the next one, at least one subtree of which is always empty */ if (p->left == NULL || p->right == NULL) goto skip; f = p->up; q = p->left; r = find_next_node(tree, p); s = r->right; if (p->right == r) { if (f == NULL) tree->root = r; else if (p->flag == 0) f->left = r; else f->right = r; r->rank = p->rank; r->up = f; r->flag = p->flag; r->bal = p->bal; r->left = q; r->right = p; q->up = r; p->rank = 1; p->up = r; p->flag = 1; p->bal = (short int)(s == NULL ? 0 : +1); p->left = NULL; p->right = s; if (s != NULL) s->up = p; } else { x = p->right; y = r->up; if (f == NULL) tree->root = r; else if (p->flag == 0) f->left = r; else f->right = r; r->rank = p->rank; r->up = f; r->flag = p->flag; r->bal = p->bal; r->left = q; r->right = x; q->up = r; x->up = r; y->left = p; p->rank = 1; p->up = y; p->flag = 0; p->bal = (short int)(s == NULL ? 0 : +1); p->left = NULL; p->right = s; if (s != NULL) s->up = p; } skip: /* now the specified node [p] has at least one empty subtree; go upstairs to the root and adjust the rank field of all nodes affected by deletion */ q = p; f = q->up; while (f != NULL) { if (q->flag == 0) f->rank--; q = f; f = q->up; } /* delete the specified node from the tree */ f = p->up; flag = p->flag; q = p->left != NULL ? p->left : p->right; if (f == NULL) tree->root = q; else if (flag == 0) f->left = q; else f->right = q; if (q != NULL) q->up = f, q->flag = flag; tree->size--; /* go upstairs to the root and correct all subtrees affected by deletion */ while (f != NULL) { if (flag == 0) { /* the height of the left subtree of [f] is decreased */ if (f->bal == 0) { f->bal = +1; break; } if (f->bal < 0) f->bal = 0; else { f = rotate_subtree(tree, f); if (f->bal < 0) break; } flag = f->flag; f = f->up; } else { /* the height of the right subtree of [f] is decreased */ if (f->bal == 0) { f->bal = -1; break; } if (f->bal > 0) f->bal = 0; else { f = rotate_subtree(tree, f); if (f->bal > 0) break; } flag = f->flag; f = f->up; } } /* if the root has been reached, the height of the entire tree is decreased */ if (f == NULL) tree->height--; /* returns the deleted node to the memory pool */ dmp_free_atom(tree->pool, p, sizeof(AVLNODE)); return; } static AVLNODE *rotate_subtree(AVL *tree, AVLNODE *node) { /* restore balance of AVL subtree */ AVLNODE *f, *p, *q, *r, *x, *y; xassert(node != NULL); p = node; if (p->bal < 0) { /* perform negative (left) rotation */ f = p->up; q = p->left; r = q->right; if (q->bal <= 0) { /* perform single negative rotation */ if (f == NULL) tree->root = q; else if (p->flag == 0) f->left = q; else f->right = q; p->rank -= q->rank; q->up = f; q->flag = p->flag; q->bal++; q->right = p; p->up = q; p->flag = 1; p->bal = (short int)(-q->bal); p->left = r; if (r != NULL) r->up = p, r->flag = 0; node = q; } else { /* perform double negative rotation */ x = r->left; y = r->right; if (f == NULL) tree->root = r; else if (p->flag == 0) f->left = r; else f->right = r; p->rank -= (q->rank + r->rank); r->rank += q->rank; p->bal = (short int)(r->bal >= 0 ? 0 : +1); q->bal = (short int)(r->bal <= 0 ? 0 : -1); r->up = f; r->flag = p->flag; r->bal = 0; r->left = q; r->right = p; p->up = r; p->flag = 1; p->left = y; q->up = r; q->flag = 0; q->right = x; if (x != NULL) x->up = q, x->flag = 1; if (y != NULL) y->up = p, y->flag = 0; node = r; } } else { /* perform positive (right) rotation */ f = p->up; q = p->right; r = q->left; if (q->bal >= 0) { /* perform single positive rotation */ if (f == NULL) tree->root = q; else if (p->flag == 0) f->left = q; else f->right = q; q->rank += p->rank; q->up = f; q->flag = p->flag; q->bal--; q->left = p; p->up = q; p->flag = 0; p->bal = (short int)(-q->bal); p->right = r; if (r != NULL) r->up = p, r->flag = 1; node = q; } else { /* perform double positive rotation */ x = r->left; y = r->right; if (f == NULL) tree->root = r; else if (p->flag == 0) f->left = r; else f->right = r; q->rank -= r->rank; r->rank += p->rank; p->bal = (short int)(r->bal <= 0 ? 0 : -1); q->bal = (short int)(r->bal >= 0 ? 0 : +1); r->up = f; r->flag = p->flag; r->bal = 0; r->left = p; r->right = q; p->up = r; p->flag = 0; p->right = x; q->up = r; q->flag = 1; q->left = y; if (x != NULL) x->up = p, x->flag = 1; if (y != NULL) y->up = q, y->flag = 0; node = r; } } return node; } void avl_delete_tree(AVL *tree) { /* delete AVL tree */ dmp_delete_pool(tree->pool); xfree(tree); return; } /* eof */ Rglpk/src/GLPK/glpnpp04.c0000644000176000001440000014254512245352174014535 0ustar ripleyusers/* glpnpp04.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpnpp.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 */ Rglpk/src/GLPK/glpios09.c0000644000176000001440000006324212245352174014533 0ustar ripleyusers/* glpios09.c (branching heuristics) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpios.h" /*********************************************************************** * NAME * * ios_choose_var - select variable to branch on * * SYNOPSIS * * #include "glpios.h" * int ios_choose_var(glp_tree *T, int *next); * * The routine ios_choose_var chooses a variable from the candidate * list to branch on. Additionally the routine provides a flag stored * in the location next to suggests which of the child subproblems * should be solved next. * * RETURNS * * The routine ios_choose_var returns the ordinal number of the column * choosen. */ static int branch_first(glp_tree *T, int *next); static int branch_last(glp_tree *T, int *next); static int branch_mostf(glp_tree *T, int *next); static int branch_drtom(glp_tree *T, int *next); int ios_choose_var(glp_tree *T, int *next) { int j; if (T->parm->br_tech == GLP_BR_FFV) { /* branch on first fractional variable */ j = branch_first(T, next); } else if (T->parm->br_tech == GLP_BR_LFV) { /* branch on last fractional variable */ j = branch_last(T, next); } else if (T->parm->br_tech == GLP_BR_MFV) { /* branch on most fractional variable */ j = branch_mostf(T, next); } else if (T->parm->br_tech == GLP_BR_DTH) { /* branch using the heuristic by Dreebeck and Tomlin */ j = branch_drtom(T, next); } else if (T->parm->br_tech == GLP_BR_PCH) { /* hybrid pseudocost heuristic */ j = ios_pcost_branch(T, next); } else xassert(T != T); return j; } /*********************************************************************** * branch_first - choose first branching variable * * This routine looks up the list of structural variables and chooses * the first one, which is of integer kind and has fractional value in * optimal solution to the current LP relaxation. * * This routine also selects the branch to be solved next where integer * infeasibility of the chosen variable is less than in other one. */ static int branch_first(glp_tree *T, int *_next) { int j, next; double beta; /* choose the column to branch on */ for (j = 1; j <= T->n; j++) if (T->non_int[j]) break; xassert(1 <= j && j <= T->n); /* select the branch to be solved next */ beta = glp_get_col_prim(T->mip, j); if (beta - floor(beta) < ceil(beta) - beta) next = GLP_DN_BRNCH; else next = GLP_UP_BRNCH; *_next = next; return j; } /*********************************************************************** * branch_last - choose last branching variable * * This routine looks up the list of structural variables and chooses * the last one, which is of integer kind and has fractional value in * optimal solution to the current LP relaxation. * * This routine also selects the branch to be solved next where integer * infeasibility of the chosen variable is less than in other one. */ static int branch_last(glp_tree *T, int *_next) { int j, next; double beta; /* choose the column to branch on */ for (j = T->n; j >= 1; j--) if (T->non_int[j]) break; xassert(1 <= j && j <= T->n); /* select the branch to be solved next */ beta = glp_get_col_prim(T->mip, j); if (beta - floor(beta) < ceil(beta) - beta) next = GLP_DN_BRNCH; else next = GLP_UP_BRNCH; *_next = next; return j; } /*********************************************************************** * branch_mostf - choose most fractional branching variable * * This routine looks up the list of structural variables and chooses * that one, which is of integer kind and has most fractional value in * optimal solution to the current LP relaxation. * * This routine also selects the branch to be solved next where integer * infeasibility of the chosen variable is less than in other one. * * (Alexander Martin notices that "...most infeasible is as good as * random...".) */ static int branch_mostf(glp_tree *T, int *_next) { int j, jj, next; double beta, most, temp; /* choose the column to branch on */ jj = 0, most = DBL_MAX; for (j = 1; j <= T->n; j++) { if (T->non_int[j]) { beta = glp_get_col_prim(T->mip, j); temp = floor(beta) + 0.5; if (most > fabs(beta - temp)) { jj = j, most = fabs(beta - temp); if (beta < temp) next = GLP_DN_BRNCH; else next = GLP_UP_BRNCH; } } } *_next = next; return jj; } /*********************************************************************** * branch_drtom - choose branching var using Driebeck-Tomlin heuristic * * This routine chooses a structural variable, which is required to be * integral and has fractional value in optimal solution of the current * LP relaxation, using a heuristic proposed by Driebeck and Tomlin. * * The routine also selects the branch to be solved next, again due to * Driebeck and Tomlin. * * This routine is based on the heuristic proposed in: * * Driebeck N.J. An algorithm for the solution of mixed-integer * programming problems, Management Science, 12: 576-87 (1966); * * and improved in: * * Tomlin J.A. Branch and bound methods for integer and non-convex * programming, in J.Abadie (ed.), Integer and Nonlinear Programming, * North-Holland, Amsterdam, pp. 437-50 (1970). * * Must note that this heuristic is time-expensive, because computing * one-step degradation (see the routine below) requires one BTRAN for * each fractional-valued structural variable. */ static int branch_drtom(glp_tree *T, int *_next) { glp_prob *mip = T->mip; int m = mip->m; int n = mip->n; unsigned char *non_int = T->non_int; int j, jj, k, t, next, kase, len, stat, *ind; double x, dk, alfa, delta_j, delta_k, delta_z, dz_dn, dz_up, dd_dn, dd_up, degrad, *val; /* basic solution of LP relaxation must be optimal */ xassert(glp_get_status(mip) == GLP_OPT); /* allocate working arrays */ ind = xcalloc(1+n, sizeof(int)); val = xcalloc(1+n, sizeof(double)); /* nothing has been chosen so far */ jj = 0, degrad = -1.0; /* walk through the list of columns (structural variables) */ for (j = 1; j <= n; j++) { /* if j-th column is not marked as fractional, skip it */ if (!non_int[j]) continue; /* obtain (fractional) value of j-th column in basic solution of LP relaxation */ x = glp_get_col_prim(mip, j); /* since the value of j-th column is fractional, the column is basic; compute corresponding row of the simplex table */ len = glp_eval_tab_row(mip, m+j, ind, val); /* the following fragment computes a change in the objective function: delta Z = new Z - old Z, where old Z is the objective value in the current optimal basis, and new Z is the objective value in the adjacent basis, for two cases: 1) if new upper bound ub' = floor(x[j]) is introduced for j-th column (down branch); 2) if new lower bound lb' = ceil(x[j]) is introduced for j-th column (up branch); since in both cases the solution remaining dual feasible becomes primal infeasible, one implicit simplex iteration is performed to determine the change delta Z; it is obvious that new Z, which is never better than old Z, is a lower (minimization) or upper (maximization) bound of the objective function for down- and up-branches. */ for (kase = -1; kase <= +1; kase += 2) { /* if kase < 0, the new upper bound of x[j] is introduced; in this case x[j] should decrease in order to leave the basis and go to its new upper bound */ /* if kase > 0, the new lower bound of x[j] is introduced; in this case x[j] should increase in order to leave the basis and go to its new lower bound */ /* apply the dual ratio test in order to determine which auxiliary or structural variable should enter the basis to keep dual feasibility */ k = glp_dual_rtest(mip, len, ind, val, kase, 1e-9); if (k != 0) k = ind[k]; /* if no non-basic variable has been chosen, LP relaxation of corresponding branch being primal infeasible and dual unbounded has no primal feasible solution; in this case the change delta Z is formally set to infinity */ if (k == 0) { delta_z = (T->mip->dir == GLP_MIN ? +DBL_MAX : -DBL_MAX); goto skip; } /* row of the simplex table that corresponds to non-basic variable x[k] choosen by the dual ratio test is: x[j] = ... + alfa * x[k] + ... where alfa is the influence coefficient (an element of the simplex table row) */ /* determine the coefficient alfa */ for (t = 1; t <= len; t++) if (ind[t] == k) break; xassert(1 <= t && t <= len); alfa = val[t]; /* since in the adjacent basis the variable x[j] becomes non-basic, knowing its value in the current basis we can determine its change delta x[j] = new x[j] - old x[j] */ delta_j = (kase < 0 ? floor(x) : ceil(x)) - x; /* and knowing the coefficient alfa we can determine the corresponding change delta x[k] = new x[k] - old x[k], where old x[k] is a value of x[k] in the current basis, and new x[k] is a value of x[k] in the adjacent basis */ delta_k = delta_j / alfa; /* Tomlin noticed that if the variable x[k] is of integer kind, its change cannot be less (eventually) than one in the magnitude */ if (k > m && glp_get_col_kind(mip, k-m) != GLP_CV) { /* x[k] is structural integer variable */ if (fabs(delta_k - floor(delta_k + 0.5)) > 1e-3) { if (delta_k > 0.0) delta_k = ceil(delta_k); /* +3.14 -> +4 */ else delta_k = floor(delta_k); /* -3.14 -> -4 */ } } /* now determine the status and reduced cost of x[k] in the current basis */ if (k <= m) { stat = glp_get_row_stat(mip, k); dk = glp_get_row_dual(mip, k); } else { stat = glp_get_col_stat(mip, k-m); dk = glp_get_col_dual(mip, k-m); } /* if the current basis is dual degenerate, some reduced costs which are close to zero may have wrong sign due to round-off errors, so correct the sign of d[k] */ switch (T->mip->dir) { case GLP_MIN: if (stat == GLP_NL && dk < 0.0 || stat == GLP_NU && dk > 0.0 || stat == GLP_NF) dk = 0.0; break; case GLP_MAX: if (stat == GLP_NL && dk > 0.0 || stat == GLP_NU && dk < 0.0 || stat == GLP_NF) dk = 0.0; break; default: xassert(T != T); } /* now knowing the change of x[k] and its reduced cost d[k] we can compute the corresponding change in the objective function delta Z = new Z - old Z = d[k] * delta x[k]; note that due to Tomlin's modification new Z can be even worse than in the adjacent basis */ delta_z = dk * delta_k; skip: /* new Z is never better than old Z, therefore the change delta Z is always non-negative (in case of minimization) or non-positive (in case of maximization) */ switch (T->mip->dir) { case GLP_MIN: xassert(delta_z >= 0.0); break; case GLP_MAX: xassert(delta_z <= 0.0); break; default: xassert(T != T); } /* save the change in the objective fnction for down- and up-branches, respectively */ if (kase < 0) dz_dn = delta_z; else dz_up = delta_z; } /* thus, in down-branch no integer feasible solution can be better than Z + dz_dn, and in up-branch no integer feasible solution can be better than Z + dz_up, where Z is value of the objective function in the current basis */ /* following the heuristic by Driebeck and Tomlin we choose a column (i.e. structural variable) which provides largest degradation of the objective function in some of branches; besides, we select the branch with smaller degradation to be solved next and keep other branch with larger degradation in the active list hoping to minimize the number of further backtrackings */ if (degrad < fabs(dz_dn) || degrad < fabs(dz_up)) { jj = j; if (fabs(dz_dn) < fabs(dz_up)) { /* select down branch to be solved next */ next = GLP_DN_BRNCH; degrad = fabs(dz_up); } else { /* select up branch to be solved next */ next = GLP_UP_BRNCH; degrad = fabs(dz_dn); } /* save the objective changes for printing */ dd_dn = dz_dn, dd_up = dz_up; /* if down- or up-branch has no feasible solution, we does not need to consider other candidates (in principle, the corresponding branch could be pruned right now) */ if (degrad == DBL_MAX) break; } } /* free working arrays */ xfree(ind); xfree(val); /* something must be chosen */ xassert(1 <= jj && jj <= n); #if 1 /* 02/XI-2009 */ if (degrad < 1e-6 * (1.0 + 0.001 * fabs(mip->obj_val))) { jj = branch_mostf(T, &next); goto done; } #endif if (T->parm->msg_lev >= GLP_MSG_DBG) { xprintf("branch_drtom: column %d chosen to branch on\n", jj); if (fabs(dd_dn) == DBL_MAX) xprintf("branch_drtom: down-branch is infeasible\n"); else xprintf("branch_drtom: down-branch bound is %.9e\n", lpx_get_obj_val(mip) + dd_dn); if (fabs(dd_up) == DBL_MAX) xprintf("branch_drtom: up-branch is infeasible\n"); else xprintf("branch_drtom: up-branch bound is %.9e\n", lpx_get_obj_val(mip) + dd_up); } done: *_next = next; return jj; } /**********************************************************************/ struct csa { /* common storage area */ int *dn_cnt; /* int dn_cnt[1+n]; */ /* dn_cnt[j] is the number of subproblems, whose LP relaxations have been solved and which are down-branches for variable x[j]; dn_cnt[j] = 0 means the down pseudocost is uninitialized */ double *dn_sum; /* double dn_sum[1+n]; */ /* dn_sum[j] is the sum of per unit degradations of the objective over all dn_cnt[j] subproblems */ int *up_cnt; /* int up_cnt[1+n]; */ /* up_cnt[j] is the number of subproblems, whose LP relaxations have been solved and which are up-branches for variable x[j]; up_cnt[j] = 0 means the up pseudocost is uninitialized */ double *up_sum; /* double up_sum[1+n]; */ /* up_sum[j] is the sum of per unit degradations of the objective over all up_cnt[j] subproblems */ }; void *ios_pcost_init(glp_tree *tree) { /* initialize working data used on pseudocost branching */ struct csa *csa; int n = tree->n, j; csa = xmalloc(sizeof(struct csa)); csa->dn_cnt = xcalloc(1+n, sizeof(int)); csa->dn_sum = xcalloc(1+n, sizeof(double)); csa->up_cnt = xcalloc(1+n, sizeof(int)); csa->up_sum = xcalloc(1+n, sizeof(double)); for (j = 1; j <= n; j++) { csa->dn_cnt[j] = csa->up_cnt[j] = 0; csa->dn_sum[j] = csa->up_sum[j] = 0.0; } return csa; } static double eval_degrad(glp_prob *P, int j, double bnd) { /* compute degradation of the objective on fixing x[j] at given value with a limited number of dual simplex iterations */ /* this routine fixes column x[j] at specified value bnd, solves resulting LP, and returns a lower bound to degradation of the objective, degrad >= 0 */ glp_prob *lp; glp_smcp parm; int ret; double degrad; /* the current basis must be optimal */ xassert(glp_get_status(P) == GLP_OPT); /* create a copy of P */ lp = glp_create_prob(); glp_copy_prob(lp, P, 0); /* fix column x[j] at specified value */ glp_set_col_bnds(lp, j, GLP_FX, bnd, bnd); /* try to solve resulting LP */ glp_init_smcp(&parm); parm.msg_lev = GLP_MSG_OFF; parm.meth = GLP_DUAL; parm.it_lim = 30; parm.out_dly = 1000; parm.meth = GLP_DUAL; ret = glp_simplex(lp, &parm); if (ret == 0 || ret == GLP_EITLIM) { if (glp_get_prim_stat(lp) == GLP_NOFEAS) { /* resulting LP has no primal feasible solution */ degrad = DBL_MAX; } else if (glp_get_dual_stat(lp) == GLP_FEAS) { /* resulting basis is optimal or at least dual feasible, so we have the correct lower bound to degradation */ if (P->dir == GLP_MIN) degrad = lp->obj_val - P->obj_val; else if (P->dir == GLP_MAX) degrad = P->obj_val - lp->obj_val; else xassert(P != P); /* degradation cannot be negative by definition */ /* note that the lower bound to degradation may be close to zero even if its exact value is zero due to round-off errors on computing the objective value */ if (degrad < 1e-6 * (1.0 + 0.001 * fabs(P->obj_val))) degrad = 0.0; } else { /* the final basis reported by the simplex solver is dual infeasible, so we cannot determine a non-trivial lower bound to degradation */ degrad = 0.0; } } else { /* the simplex solver failed */ degrad = 0.0; } /* delete the copy of P */ glp_delete_prob(lp); return degrad; } void ios_pcost_update(glp_tree *tree) { /* update history information for pseudocost branching */ /* this routine is called every time when LP relaxation of the current subproblem has been solved to optimality with all lazy and cutting plane constraints included */ int j; double dx, dz, psi; struct csa *csa = tree->pcost; xassert(csa != NULL); xassert(tree->curr != NULL); /* if the current subproblem is the root, skip updating */ if (tree->curr->up == NULL) goto skip; /* determine branching variable x[j], which was used in the parent subproblem to create the current subproblem */ j = tree->curr->up->br_var; xassert(1 <= j && j <= tree->n); /* determine the change dx[j] = new x[j] - old x[j], where new x[j] is a value of x[j] in optimal solution to LP relaxation of the current subproblem, old x[j] is a value of x[j] in optimal solution to LP relaxation of the parent subproblem */ dx = tree->mip->col[j]->prim - tree->curr->up->br_val; xassert(dx != 0.0); /* determine corresponding change dz = new dz - old dz in the objective function value */ dz = tree->mip->obj_val - tree->curr->up->lp_obj; /* determine per unit degradation of the objective function */ psi = fabs(dz / dx); /* update history information */ if (dx < 0.0) { /* the current subproblem is down-branch */ csa->dn_cnt[j]++; csa->dn_sum[j] += psi; } else /* dx > 0.0 */ { /* the current subproblem is up-branch */ csa->up_cnt[j]++; csa->up_sum[j] += psi; } skip: return; } void ios_pcost_free(glp_tree *tree) { /* free working area used on pseudocost branching */ struct csa *csa = tree->pcost; xassert(csa != NULL); xfree(csa->dn_cnt); xfree(csa->dn_sum); xfree(csa->up_cnt); xfree(csa->up_sum); xfree(csa); tree->pcost = NULL; return; } static double eval_psi(glp_tree *T, int j, int brnch) { /* compute estimation of pseudocost of variable x[j] for down- or up-branch */ struct csa *csa = T->pcost; double beta, degrad, psi; xassert(csa != NULL); xassert(1 <= j && j <= T->n); if (brnch == GLP_DN_BRNCH) { /* down-branch */ if (csa->dn_cnt[j] == 0) { /* initialize down pseudocost */ beta = T->mip->col[j]->prim; degrad = eval_degrad(T->mip, j, floor(beta)); if (degrad == DBL_MAX) { psi = DBL_MAX; goto done; } csa->dn_cnt[j] = 1; csa->dn_sum[j] = degrad / (beta - floor(beta)); } psi = csa->dn_sum[j] / (double)csa->dn_cnt[j]; } else if (brnch == GLP_UP_BRNCH) { /* up-branch */ if (csa->up_cnt[j] == 0) { /* initialize up pseudocost */ beta = T->mip->col[j]->prim; degrad = eval_degrad(T->mip, j, ceil(beta)); if (degrad == DBL_MAX) { psi = DBL_MAX; goto done; } csa->up_cnt[j] = 1; csa->up_sum[j] = degrad / (ceil(beta) - beta); } psi = csa->up_sum[j] / (double)csa->up_cnt[j]; } else xassert(brnch != brnch); done: return psi; } static void progress(glp_tree *T) { /* display progress of pseudocost initialization */ struct csa *csa = T->pcost; int j, nv = 0, ni = 0; for (j = 1; j <= T->n; j++) { if (glp_ios_can_branch(T, j)) { nv++; if (csa->dn_cnt[j] > 0 && csa->up_cnt[j] > 0) ni++; } } xprintf("Pseudocosts initialized for %d of %d variables\n", ni, nv); return; } int ios_pcost_branch(glp_tree *T, int *_next) { /* choose branching variable with pseudocost branching */ #if 0 /* 10/VI-2013 */ glp_long t = xtime(); #else double t = xtime(); #endif int j, jjj, sel; double beta, psi, d1, d2, d, dmax; /* initialize the working arrays */ if (T->pcost == NULL) T->pcost = ios_pcost_init(T); /* nothing has been chosen so far */ jjj = 0, dmax = -1.0; /* go through the list of branching candidates */ for (j = 1; j <= T->n; j++) { if (!glp_ios_can_branch(T, j)) continue; /* determine primal value of x[j] in optimal solution to LP relaxation of the current subproblem */ beta = T->mip->col[j]->prim; /* estimate pseudocost of x[j] for down-branch */ psi = eval_psi(T, j, GLP_DN_BRNCH); if (psi == DBL_MAX) { /* down-branch has no primal feasible solution */ jjj = j, sel = GLP_DN_BRNCH; goto done; } /* estimate degradation of the objective for down-branch */ d1 = psi * (beta - floor(beta)); /* estimate pseudocost of x[j] for up-branch */ psi = eval_psi(T, j, GLP_UP_BRNCH); if (psi == DBL_MAX) { /* up-branch has no primal feasible solution */ jjj = j, sel = GLP_UP_BRNCH; goto done; } /* estimate degradation of the objective for up-branch */ d2 = psi * (ceil(beta) - beta); /* determine d = max(d1, d2) */ d = (d1 > d2 ? d1 : d2); /* choose x[j] which provides maximal estimated degradation of the objective either in down- or up-branch */ if (dmax < d) { dmax = d; jjj = j; /* continue the search from a subproblem, where degradation is less than in other one */ sel = (d1 <= d2 ? GLP_DN_BRNCH : GLP_UP_BRNCH); } /* display progress of pseudocost initialization */ if (T->parm->msg_lev >= GLP_ON) { if (xdifftime(xtime(), t) >= 10.0) { progress(T); t = xtime(); } } } if (dmax == 0.0) { /* no degradation is indicated; choose a variable having most fractional value */ jjj = branch_mostf(T, &sel); } done: *_next = sel; return jjj; } /* eof */ Rglpk/src/GLPK/qmd.c0000644000176000001440000004353712245352174013653 0ustar ripleyusers/* qmd.c (quotient minimum degree algorithm) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * THIS CODE IS THE RESULT OF TRANSLATION OF THE FORTRAN SUBROUTINES * GENQMD, QMDRCH, QMDQT, QMDUPD, AND QMDMRG FROM THE BOOK: * * ALAN GEORGE, JOSEPH W-H LIU. COMPUTER SOLUTION OF LARGE SPARSE * POSITIVE DEFINITE SYSTEMS. PRENTICE-HALL, 1981. * * THE TRANSLATION HAS BEEN DONE WITH THE PERMISSION OF THE AUTHORS * OF THE ORIGINAL FORTRAN SUBROUTINES: ALAN GEORGE AND JOSEPH LIU, * UNIVERSITY OF WATERLOO, WATERLOO, ONTARIO, CANADA. * * The translation was made by Andrew Makhorin . * * 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 . ***********************************************************************/ #include "qmd.h" /*********************************************************************** * NAME * * genqmd - GENeral Quotient Minimum Degree algorithm * * SYNOPSIS * * #include "qmd.h" * void genqmd(int *neqns, int xadj[], int adjncy[], int perm[], * int invp[], int deg[], int marker[], int rchset[], int nbrhd[], * int qsize[], int qlink[], int *nofsub); * * PURPOSE * * This routine implements the minimum degree algorithm. It makes use * of the implicit representation of the elimination graph by quotient * graphs, and the notion of indistinguishable nodes. * * CAUTION * * The adjancy vector adjncy will be destroyed. * * INPUT PARAMETERS * * neqns - number of equations; * (xadj, adjncy) - * the adjancy structure. * * OUTPUT PARAMETERS * * perm - the minimum degree ordering; * invp - the inverse of perm. * * WORKING PARAMETERS * * deg - the degree vector. deg[i] is negative means node i has been * numbered; * marker - a marker vector, where marker[i] is negative means node i * has been merged with another nodeand thus can be ignored; * rchset - vector used for the reachable set; * nbrhd - vector used for neighborhood set; * qsize - vector used to store the size of indistinguishable * supernodes; * qlink - vector used to store indistinguishable nodes, i, qlink[i], * qlink[qlink[i]], ... are the members of the supernode * represented by i. * * PROGRAM SUBROUTINES * * qmdrch, qmdqt, qmdupd. ***********************************************************************/ void genqmd(int *_neqns, int xadj[], int adjncy[], int perm[], int invp[], int deg[], int marker[], int rchset[], int nbrhd[], int qsize[], int qlink[], int *_nofsub) { int inode, ip, irch, j, mindeg, ndeg, nhdsze, node, np, num, nump1, nxnode, rchsze, search, thresh; # define neqns (*_neqns) # define nofsub (*_nofsub) /* Initialize degree vector and other working variables. */ mindeg = neqns; nofsub = 0; for (node = 1; node <= neqns; node++) { perm[node] = node; invp[node] = node; marker[node] = 0; qsize[node] = 1; qlink[node] = 0; ndeg = xadj[node+1] - xadj[node]; deg[node] = ndeg; if (ndeg < mindeg) mindeg = ndeg; } num = 0; /* Perform threshold search to get a node of min degree. * Variable search point to where search should start. */ s200: search = 1; thresh = mindeg; mindeg = neqns; s300: nump1 = num + 1; if (nump1 > search) search = nump1; for (j = search; j <= neqns; j++) { node = perm[j]; if (marker[node] >= 0) { ndeg = deg[node]; if (ndeg <= thresh) goto s500; if (ndeg < mindeg) mindeg = ndeg; } } goto s200; /* Node has minimum degree. Find its reachable sets by calling * qmdrch. */ s500: search = j; nofsub += deg[node]; marker[node] = 1; qmdrch(&node, xadj, adjncy, deg, marker, &rchsze, rchset, &nhdsze, nbrhd); /* Eliminate all nodes indistinguishable from node. They are given * by node, qlink[node], ... . */ nxnode = node; s600: num++; np = invp[nxnode]; ip = perm[num]; perm[np] = ip; invp[ip] = np; perm[num] = nxnode; invp[nxnode] = num; deg[nxnode] = -1; nxnode = qlink[nxnode]; if (nxnode > 0) goto s600; if (rchsze > 0) { /* Update the degrees of the nodes in the reachable set and * identify indistinguishable nodes. */ qmdupd(xadj, adjncy, &rchsze, rchset, deg, qsize, qlink, marker, &rchset[rchsze+1], &nbrhd[nhdsze+1]); /* Reset marker value of nodes in reach set. Update threshold * value for cyclic search. Also call qmdqt to form new * quotient graph. */ marker[node] = 0; for (irch = 1; irch <= rchsze; irch++) { inode = rchset[irch]; if (marker[inode] >= 0) { marker[inode] = 0; ndeg = deg[inode]; if (ndeg < mindeg) mindeg = ndeg; if (ndeg <= thresh) { mindeg = thresh; thresh = ndeg; search = invp[inode]; } } } if (nhdsze > 0) qmdqt(&node, xadj, adjncy, marker, &rchsze, rchset, nbrhd); } if (num < neqns) goto s300; return; # undef neqns # undef nofsub } /*********************************************************************** * NAME * * qmdrch - Quotient MD ReaCHable set * * SYNOPSIS * * #include "qmd.h" * void qmdrch(int *root, int xadj[], int adjncy[], int deg[], * int marker[], int *rchsze, int rchset[], int *nhdsze, * int nbrhd[]); * * PURPOSE * * This subroutine determines the reachable set of a node through a * given subset. The adjancy structure is assumed to be stored in a * quotient graph format. * * INPUT PARAMETERS * * root - the given node not in the subset; * (xadj, adjncy) - * the adjancy structure pair; * deg - the degree vector. deg[i] < 0 means the node belongs to the * given subset. * * OUTPUT PARAMETERS * * (rchsze, rchset) - * the reachable set; * (nhdsze, nbrhd) - * the neighborhood set. * * UPDATED PARAMETERS * * marker - the marker vector for reach and nbrhd sets. > 0 means the * node is in reach set. < 0 means the node has been merged * with others in the quotient or it is in nbrhd set. ***********************************************************************/ void qmdrch(int *_root, int xadj[], int adjncy[], int deg[], int marker[], int *_rchsze, int rchset[], int *_nhdsze, int nbrhd[]) { int i, istop, istrt, j, jstop, jstrt, nabor, node; # define root (*_root) # define rchsze (*_rchsze) # define nhdsze (*_nhdsze) /* Loop through the neighbors of root in the quotient graph. */ nhdsze = 0; rchsze = 0; istrt = xadj[root]; istop = xadj[root+1] - 1; if (istop < istrt) return; for (i = istrt; i <= istop; i++) { nabor = adjncy[i]; if (nabor == 0) return; if (marker[nabor] == 0) { if (deg[nabor] >= 0) { /* Include nabor into the reachable set. */ rchsze++; rchset[rchsze] = nabor; marker[nabor] = 1; goto s600; } /* nabor has been eliminated. Find nodes reachable from * it. */ marker[nabor] = -1; nhdsze++; nbrhd[nhdsze] = nabor; s300: jstrt = xadj[nabor]; jstop = xadj[nabor+1] - 1; for (j = jstrt; j <= jstop; j++) { node = adjncy[j]; nabor = - node; if (node < 0) goto s300; if (node == 0) goto s600; if (marker[node] == 0) { rchsze++; rchset[rchsze] = node; marker[node] = 1; } } } s600: ; } return; # undef root # undef rchsze # undef nhdsze } /*********************************************************************** * NAME * * qmdqt - Quotient MD Quotient graph Transformation * * SYNOPSIS * * #include "qmd.h" * void qmdqt(int *root, int xadj[], int adjncy[], int marker[], * int *rchsze, int rchset[], int nbrhd[]); * * PURPOSE * * This subroutine performs the quotient graph transformation after a * node has been eliminated. * * INPUT PARAMETERS * * root - the node just eliminated. It becomes the representative of * the new supernode; * (xadj, adjncy) - * the adjancy structure; * (rchsze, rchset) - * the reachable set of root in the old quotient graph; * nbrhd - the neighborhood set which will be merged with root to form * the new supernode; * marker - the marker vector. * * UPDATED PARAMETERS * * adjncy - becomes the adjncy of the quotient graph. ***********************************************************************/ void qmdqt(int *_root, int xadj[], int adjncy[], int marker[], int *_rchsze, int rchset[], int nbrhd[]) { int inhd, irch, j, jstop, jstrt, link, nabor, node; # define root (*_root) # define rchsze (*_rchsze) irch = 0; inhd = 0; node = root; s100: jstrt = xadj[node]; jstop = xadj[node+1] - 2; if (jstop >= jstrt) { /* Place reach nodes into the adjacent list of node. */ for (j = jstrt; j <= jstop; j++) { irch++; adjncy[j] = rchset[irch]; if (irch >= rchsze) goto s400; } } /* Link to other space provided by the nbrhd set. */ link = adjncy[jstop+1]; node = - link; if (link >= 0) { inhd++; node = nbrhd[inhd]; adjncy[jstop+1] = - node; } goto s100; /* All reachable nodes have been saved. End the adjacent list. * Add root to the neighborhood list of each node in the reach * set. */ s400: adjncy[j+1] = 0; for (irch = 1; irch <= rchsze; irch++) { node = rchset[irch]; if (marker[node] >= 0) { jstrt = xadj[node]; jstop = xadj[node+1] - 1; for (j = jstrt; j <= jstop; j++) { nabor = adjncy[j]; if (marker[nabor] < 0) { adjncy[j] = root; goto s600; } } } s600: ; } return; # undef root # undef rchsze } /*********************************************************************** * NAME * * qmdupd - Quotient MD UPDate * * SYNOPSIS * * #include "qmd.h" * void qmdupd(int xadj[], int adjncy[], int *nlist, int list[], * int deg[], int qsize[], int qlink[], int marker[], int rchset[], * int nbrhd[]); * * PURPOSE * * This routine performs degree update for a set of nodes in the minimum * degree algorithm. * * INPUT PARAMETERS * * (xadj, adjncy) - * the adjancy structure; * (nlist, list) - * the list of nodes whose degree has to be updated. * * UPDATED PARAMETERS * * deg - the degree vector; * qsize - size of indistinguishable supernodes; * qlink - linked list for indistinguishable nodes; * marker - used to mark those nodes in reach/nbrhd sets. * * WORKING PARAMETERS * * rchset - the reachable set; * nbrhd - the neighborhood set. * * PROGRAM SUBROUTINES * * qmdmrg. ***********************************************************************/ void qmdupd(int xadj[], int adjncy[], int *_nlist, int list[], int deg[], int qsize[], int qlink[], int marker[], int rchset[], int nbrhd[]) { int deg0, deg1, il, inhd, inode, irch, j, jstop, jstrt, mark, nabor, nhdsze, node, rchsze; # define nlist (*_nlist) /* Find all eliminated supernodes that are adjacent to some nodes * in the given list. Put them into (nhdsze, nbrhd). deg0 contains * the number of nodes in the list. */ if (nlist <= 0) return; deg0 = 0; nhdsze = 0; for (il = 1; il <= nlist; il++) { node = list[il]; deg0 += qsize[node]; jstrt = xadj[node]; jstop = xadj[node+1] - 1; for (j = jstrt; j <= jstop; j++) { nabor = adjncy[j]; if (marker[nabor] == 0 && deg[nabor] < 0) { marker[nabor] = -1; nhdsze++; nbrhd[nhdsze] = nabor; } } } /* Merge indistinguishable nodes in the list by calling the * subroutine qmdmrg. */ if (nhdsze > 0) qmdmrg(xadj, adjncy, deg, qsize, qlink, marker, °0, &nhdsze, nbrhd, rchset, &nbrhd[nhdsze+1]); /* Find the new degrees of the nodes that have not been merged. */ for (il = 1; il <= nlist; il++) { node = list[il]; mark = marker[node]; if (mark == 0 || mark == 1) { marker[node] = 2; qmdrch(&node, xadj, adjncy, deg, marker, &rchsze, rchset, &nhdsze, nbrhd); deg1 = deg0; if (rchsze > 0) { for (irch = 1; irch <= rchsze; irch++) { inode = rchset[irch]; deg1 += qsize[inode]; marker[inode] = 0; } } deg[node] = deg1 - 1; if (nhdsze > 0) { for (inhd = 1; inhd <= nhdsze; inhd++) { inode = nbrhd[inhd]; marker[inode] = 0; } } } } return; # undef nlist } /*********************************************************************** * NAME * * qmdmrg - Quotient MD MeRGe * * SYNOPSIS * * #include "qmd.h" * void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[], * int qlink[], int marker[], int *deg0, int *nhdsze, int nbrhd[], * int rchset[], int ovrlp[]); * * PURPOSE * * This routine merges indistinguishable nodes in the minimum degree * ordering algorithm. It also computes the new degrees of these new * supernodes. * * INPUT PARAMETERS * * (xadj, adjncy) - * the adjancy structure; * deg0 - the number of nodes in the given set; * (nhdsze, nbrhd) - * the set of eliminated supernodes adjacent to some nodes in * the set. * * UPDATED PARAMETERS * * deg - the degree vector; * qsize - size of indistinguishable nodes; * qlink - linked list for indistinguishable nodes; * marker - the given set is given by those nodes with marker value set * to 1. Those nodes with degree updated will have marker value * set to 2. * * WORKING PARAMETERS * * rchset - the reachable set; * ovrlp - temp vector to store the intersection of two reachable sets. ***********************************************************************/ void qmdmrg(int xadj[], int adjncy[], int deg[], int qsize[], int qlink[], int marker[], int *_deg0, int *_nhdsze, int nbrhd[], int rchset[], int ovrlp[]) { int deg1, head, inhd, iov, irch, j, jstop, jstrt, link, lnode, mark, mrgsze, nabor, node, novrlp, rchsze, root; # define deg0 (*_deg0) # define nhdsze (*_nhdsze) /* Initialization. */ if (nhdsze <= 0) return; for (inhd = 1; inhd <= nhdsze; inhd++) { root = nbrhd[inhd]; marker[root] = 0; } /* Loop through each eliminated supernode in the set * (nhdsze, nbrhd). */ for (inhd = 1; inhd <= nhdsze; inhd++) { root = nbrhd[inhd]; marker[root] = -1; rchsze = 0; novrlp = 0; deg1 = 0; s200: jstrt = xadj[root]; jstop = xadj[root+1] - 1; /* Determine the reachable set and its intersection with the * input reachable set. */ for (j = jstrt; j <= jstop; j++) { nabor = adjncy[j]; root = - nabor; if (nabor < 0) goto s200; if (nabor == 0) break; mark = marker[nabor]; if (mark == 0) { rchsze++; rchset[rchsze] = nabor; deg1 += qsize[nabor]; marker[nabor] = 1; } else if (mark == 1) { novrlp++; ovrlp[novrlp] = nabor; marker[nabor] = 2; } } /* From the overlapped set, determine the nodes that can be * merged together. */ head = 0; mrgsze = 0; for (iov = 1; iov <= novrlp; iov++) { node = ovrlp[iov]; jstrt = xadj[node]; jstop = xadj[node+1] - 1; for (j = jstrt; j <= jstop; j++) { nabor = adjncy[j]; if (marker[nabor] == 0) { marker[node] = 1; goto s1100; } } /* Node belongs to the new merged supernode. Update the * vectors qlink and qsize. */ mrgsze += qsize[node]; marker[node] = -1; lnode = node; s900: link = qlink[lnode]; if (link > 0) { lnode = link; goto s900; } qlink[lnode] = head; head = node; s1100: ; } if (head > 0) { qsize[head] = mrgsze; deg[head] = deg0 + deg1 - 1; marker[head] = 2; } /* Reset marker values. */ root = nbrhd[inhd]; marker[root] = 0; if (rchsze > 0) { for (irch = 1; irch <= rchsze; irch++) { node = rchset[irch]; marker[node] = 0; } } } return; # undef deg0 # undef nhdsze } /* eof */ Rglpk/src/GLPK/glplpf.h0000644000176000001440000001732012245352174014352 0ustar ripleyusers/* glplpf.h (LP basis factorization, Schur complement version) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPLPF_H #define GLPLPF_H #include "glpscf.h" #if 0 /* 06/VI-2013 */ #include "glpluf.h" #else #include "lufint.h" #endif /*********************************************************************** * The structure LPF defines the factorization of the basis mxm matrix * B, where m is the number of rows in corresponding problem instance. * * This factorization is the following septet: * * [B] = (L0, U0, R, S, C, P, Q), (1) * * and is based on the following main equality: * * ( B F^) ( B0 F ) ( L0 0 ) ( U0 R ) * ( ) = P ( ) Q = P ( ) ( ) Q, (2) * ( G^ H^) ( G H ) ( S I ) ( 0 C ) * * where: * * B is the current basis matrix (not stored); * * F^, G^, H^ are some additional matrices (not stored); * * B0 is some initial basis matrix (not stored); * * F, G, H are some additional matrices (not stored); * * P, Q are permutation matrices (stored in both row- and column-like * formats); * * L0, U0 are some matrices that defines a factorization of the initial * basis matrix B0 = L0 * U0 (stored in an invertable form); * * R is a matrix defined from L0 * R = F, so R = inv(L0) * F (stored in * a column-wise sparse format); * * S is a matrix defined from S * U0 = G, so S = G * inv(U0) (stored in * a row-wise sparse format); * * C is the Schur complement for matrix (B0 F G H). It is defined from * S * R + C = H, so C = H - S * R = H - G * inv(U0) * inv(L0) * F = * = H - G * inv(B0) * F. Matrix C is stored in an invertable form. * * REFERENCES * * 1. M.A.Saunders, "LUSOL: A basis package for constrained optimiza- * tion," SCCM, Stanford University, 2006. * * 2. M.A.Saunders, "Notes 5: Basis Updates," CME 318, Stanford Univer- * sity, Spring 2006. * * 3. M.A.Saunders, "Notes 6: LUSOL---a Basis Factorization Package," * ibid. */ typedef struct LPF LPF; struct LPF { /* LP basis factorization */ int valid; /* the factorization is valid only if this flag is set */ /*--------------------------------------------------------------*/ /* initial basis matrix B0 */ int m0_max; /* maximal value of m0 (increased automatically, if necessary) */ int m0; /* the order of B0 */ #if 0 /* 06/VI-2013 */ LUF *luf; #else LUFINT *lufint; #endif /* LU-factorization of B0 */ /*--------------------------------------------------------------*/ /* current basis matrix B */ int m; /* the order of B */ double *B; /* double B[1+m*m]; */ /* B in dense format stored by rows and used only for debugging; normally this array is not allocated */ /*--------------------------------------------------------------*/ /* augmented matrix (B0 F G H) of the order m0+n */ int n_max; /* maximal number of additional rows and columns */ int n; /* current number of additional rows and columns */ /*--------------------------------------------------------------*/ /* m0xn matrix R in column-wise format */ int *R_ptr; /* int R_ptr[1+n_max]; */ /* R_ptr[j], 1 <= j <= n, is a pointer to j-th column */ int *R_len; /* int R_len[1+n_max]; */ /* R_len[j], 1 <= j <= n, is the length of j-th column */ /*--------------------------------------------------------------*/ /* nxm0 matrix S in row-wise format */ int *S_ptr; /* int S_ptr[1+n_max]; */ /* S_ptr[i], 1 <= i <= n, is a pointer to i-th row */ int *S_len; /* int S_len[1+n_max]; */ /* S_len[i], 1 <= i <= n, is the length of i-th row */ /*--------------------------------------------------------------*/ /* Schur complement C of the order n */ SCF *scf; /* SCF scf[1:n_max]; */ /* factorization of the Schur complement */ /*--------------------------------------------------------------*/ /* matrix P of the order m0+n */ int *P_row; /* int P_row[1+m0_max+n_max]; */ /* P_row[i] = j means that P[i,j] = 1 */ int *P_col; /* int P_col[1+m0_max+n_max]; */ /* P_col[j] = i means that P[i,j] = 1 */ /*--------------------------------------------------------------*/ /* matrix Q of the order m0+n */ int *Q_row; /* int Q_row[1+m0_max+n_max]; */ /* Q_row[i] = j means that Q[i,j] = 1 */ int *Q_col; /* int Q_col[1+m0_max+n_max]; */ /* Q_col[j] = i means that Q[i,j] = 1 */ /*--------------------------------------------------------------*/ /* Sparse Vector Area (SVA) is a set of locations intended to store sparse vectors which represent columns of matrix R and rows of matrix S; each location is a doublet (ind, val), where ind is an index, val is a numerical value of a sparse vector element; in the whole each sparse vector is a set of adjacent locations defined by a pointer to its first element and its length, i.e. the number of its elements */ int v_size; /* the SVA size, in locations; locations are numbered by integers 1, 2, ..., v_size, and location 0 is not used */ int v_ptr; /* pointer to the first available location */ int *v_ind; /* int v_ind[1+v_size]; */ /* v_ind[k], 1 <= k <= v_size, is the index field of location k */ double *v_val; /* double v_val[1+v_size]; */ /* v_val[k], 1 <= k <= v_size, is the value field of location k */ /*--------------------------------------------------------------*/ double *work1; /* double work1[1+m0+n_max]; */ /* working array */ double *work2; /* double work2[1+m0+n_max]; */ /* working array */ }; /* return codes: */ #define LPF_ESING 1 /* singular matrix */ #define LPF_ECOND 2 /* ill-conditioned matrix */ #define LPF_ELIMIT 3 /* update limit reached */ #define lpf_create_it _glp_lpf_create_it LPF *lpf_create_it(void); /* create LP basis factorization */ #define lpf_factorize _glp_lpf_factorize int lpf_factorize(LPF *lpf, int m, const int bh[], int (*col) (void *info, int j, int ind[], double val[]), void *info); /* compute LP basis factorization */ #define lpf_ftran _glp_lpf_ftran void lpf_ftran(LPF *lpf, double x[]); /* perform forward transformation (solve system B*x = b) */ #define lpf_btran _glp_lpf_btran void lpf_btran(LPF *lpf, double x[]); /* perform backward transformation (solve system B'*x = b) */ #define lpf_update_it _glp_lpf_update_it int lpf_update_it(LPF *lpf, int j, int bh, int len, const int ind[], const double val[]); /* update LP basis factorization */ #define lpf_delete_it _glp_lpf_delete_it void lpf_delete_it(LPF *lpf); /* delete LP basis factorization */ #endif /* eof */ Rglpk/src/GLPK/glpmat.h0000644000176000001440000001643412245352174014357 0ustar ripleyusers/* glpmat.h (linear algebra routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPMAT_H #define GLPMAT_H /*********************************************************************** * FULL-VECTOR STORAGE * * For a sparse vector x having n elements, ne of which are non-zero, * the full-vector storage format uses two arrays x_ind and x_vec, which * are set up as follows: * * x_ind is an integer array of length [1+ne]. Location x_ind[0] is * not used, and locations x_ind[1], ..., x_ind[ne] contain indices of * non-zero elements in vector x. * * x_vec is a floating-point array of length [1+n]. Location x_vec[0] * is not used, and locations x_vec[1], ..., x_vec[n] contain numeric * values of ALL elements in vector x, including its zero elements. * * Let, for example, the following sparse vector x be given: * * (0, 1, 0, 0, 2, 3, 0, 4) * * Then the arrays are: * * x_ind = { X; 2, 5, 6, 8 } * * x_vec = { X; 0, 1, 0, 0, 2, 3, 0, 4 } * * COMPRESSED-VECTOR STORAGE * * For a sparse vector x having n elements, ne of which are non-zero, * the compressed-vector storage format uses two arrays x_ind and x_vec, * which are set up as follows: * * x_ind is an integer array of length [1+ne]. Location x_ind[0] is * not used, and locations x_ind[1], ..., x_ind[ne] contain indices of * non-zero elements in vector x. * * x_vec is a floating-point array of length [1+ne]. Location x_vec[0] * is not used, and locations x_vec[1], ..., x_vec[ne] contain numeric * values of corresponding non-zero elements in vector x. * * Let, for example, the following sparse vector x be given: * * (0, 1, 0, 0, 2, 3, 0, 4) * * Then the arrays are: * * x_ind = { X; 2, 5, 6, 8 } * * x_vec = { X; 1, 2, 3, 4 } * * STORAGE-BY-ROWS * * For a sparse matrix A, which has m rows, n columns, and ne non-zero * elements the storage-by-rows format uses three arrays A_ptr, A_ind, * and A_val, which are set up as follows: * * A_ptr is an integer array of length [1+m+1] also called "row pointer * array". It contains the relative starting positions of each row of A * in the arrays A_ind and A_val, i.e. element A_ptr[i], 1 <= i <= m, * indicates where row i begins in the arrays A_ind and A_val. If all * elements in row i are zero, then A_ptr[i] = A_ptr[i+1]. Location * A_ptr[0] is not used, location A_ptr[1] must contain 1, and location * A_ptr[m+1] must contain ne+1 that indicates the position after the * last element in the arrays A_ind and A_val. * * A_ind is an integer array of length [1+ne]. Location A_ind[0] is not * used, and locations A_ind[1], ..., A_ind[ne] contain column indices * of (non-zero) elements in matrix A. * * A_val is a floating-point array of length [1+ne]. Location A_val[0] * is not used, and locations A_val[1], ..., A_val[ne] contain numeric * values of non-zero elements in matrix A. * * Non-zero elements of matrix A are stored contiguously, and the rows * of matrix A are stored consecutively from 1 to m in the arrays A_ind * and A_val. The elements in each row of A may be stored in any order * in A_ind and A_val. Note that elements with duplicate column indices * are not allowed. * * Let, for example, the following sparse matrix A be given: * * | 11 . 13 . . . | * | 21 22 . 24 . . | * | . 32 33 . . . | * | . . 43 44 . 46 | * | . . . . . . | * | 61 62 . . . 66 | * * Then the arrays are: * * A_ptr = { X; 1, 3, 6, 8, 11, 11; 14 } * * A_ind = { X; 1, 3; 4, 2, 1; 2, 3; 4, 3, 6; 1, 2, 6 } * * A_val = { X; 11, 13; 24, 22, 21; 32, 33; 44, 43, 46; 61, 62, 66 } * * PERMUTATION MATRICES * * Let P be a permutation matrix of the order n. It is represented as * an integer array P_per of length [1+n+n] as follows: if p[i,j] = 1, * then P_per[i] = j and P_per[n+j] = i. Location P_per[0] is not used. * * Let A' = P*A. If i-th row of A corresponds to i'-th row of A', then * P_per[i'] = i and P_per[n+i] = i'. * * References: * * 1. Gustavson F.G. Some basic techniques for solving sparse systems of * linear equations. In Rose and Willoughby (1972), pp. 41-52. * * 2. Basic Linear Algebra Subprograms Technical (BLAST) Forum Standard. * University of Tennessee (2001). */ #define check_fvs _glp_mat_check_fvs int check_fvs(int n, int nnz, int ind[], double vec[]); /* check sparse vector in full-vector storage format */ #define check_pattern _glp_mat_check_pattern int check_pattern(int m, int n, int A_ptr[], int A_ind[]); /* check pattern of sparse matrix */ #define transpose _glp_mat_transpose void transpose(int m, int n, int A_ptr[], int A_ind[], double A_val[], int AT_ptr[], int AT_ind[], double AT_val[]); /* transpose sparse matrix */ #define adat_symbolic _glp_mat_adat_symbolic int *adat_symbolic(int m, int n, int P_per[], int A_ptr[], int A_ind[], int S_ptr[]); /* compute S = P*A*D*A'*P' (symbolic phase) */ #define adat_numeric _glp_mat_adat_numeric void adat_numeric(int m, int n, int P_per[], int A_ptr[], int A_ind[], double A_val[], double D_diag[], int S_ptr[], int S_ind[], double S_val[], double S_diag[]); /* compute S = P*A*D*A'*P' (numeric phase) */ #define min_degree _glp_mat_min_degree void min_degree(int n, int A_ptr[], int A_ind[], int P_per[]); /* minimum degree ordering */ #define amd_order1 _glp_mat_amd_order1 void amd_order1(int n, int A_ptr[], int A_ind[], int P_per[]); /* approximate minimum degree ordering (AMD) */ #define symamd_ord _glp_mat_symamd_ord void symamd_ord(int n, int A_ptr[], int A_ind[], int P_per[]); /* approximate minimum degree ordering (SYMAMD) */ #define chol_symbolic _glp_mat_chol_symbolic int *chol_symbolic(int n, int A_ptr[], int A_ind[], int U_ptr[]); /* compute Cholesky factorization (symbolic phase) */ #define chol_numeric _glp_mat_chol_numeric int chol_numeric(int n, int A_ptr[], int A_ind[], double A_val[], double A_diag[], int U_ptr[], int U_ind[], double U_val[], double U_diag[]); /* compute Cholesky factorization (numeric phase) */ #define u_solve _glp_mat_u_solve void u_solve(int n, int U_ptr[], int U_ind[], double U_val[], double U_diag[], double x[]); /* solve upper triangular system U*x = b */ #define ut_solve _glp_mat_ut_solve void ut_solve(int n, int U_ptr[], int U_ind[], double U_val[], double U_diag[], double x[]); /* solve lower triangular system U'*x = b */ #endif /* eof */ Rglpk/src/GLPK/glpapi08.c0000644000176000001440000003031512245352174014504 0ustar ripleyusers/* glpapi08.c (interior-point method routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpapi.h" #include "glpipm.h" #include "glpnpp.h" /*********************************************************************** * NAME * * glp_interior - solve LP problem with the interior-point method * * SYNOPSIS * * int glp_interior(glp_prob *P, const glp_iptcp *parm); * * The routine glp_interior is a driver to the LP solver based on the * interior-point method. * * The interior-point solver has a set of control parameters. Values of * the control parameters can be passed in a structure glp_iptcp, which * the parameter parm points to. * * Currently this routine implements an easy variant of the primal-dual * interior-point method based on Mehrotra's technique. * * This routine transforms the original LP problem to an equivalent LP * problem in the standard formulation (all constraints are equalities, * all variables are non-negative), calls the routine ipm_main to solve * the transformed problem, and then transforms an obtained solution to * the solution of the original problem. * * RETURNS * * 0 The LP problem instance has been successfully solved. This code * does not necessarily mean that the solver has found optimal * solution. It only means that the solution process was successful. * * GLP_EFAIL * The problem has no rows/columns. * * GLP_ENOCVG * Very slow convergence or divergence. * * GLP_EITLIM * Iteration limit exceeded. * * GLP_EINSTAB * Numerical instability on solving Newtonian system. */ static void transform(NPP *npp) { /* transform LP to the standard formulation */ NPPROW *row, *prev_row; NPPCOL *col, *prev_col; for (row = npp->r_tail; row != NULL; row = prev_row) { prev_row = row->prev; if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) npp_free_row(npp, row); else if (row->lb == -DBL_MAX) npp_leq_row(npp, row); else if (row->ub == +DBL_MAX) npp_geq_row(npp, row); else if (row->lb != row->ub) { if (fabs(row->lb) < fabs(row->ub)) npp_geq_row(npp, row); else npp_leq_row(npp, row); } } for (col = npp->c_tail; col != NULL; col = prev_col) { prev_col = col->prev; if (col->lb == -DBL_MAX && col->ub == +DBL_MAX) npp_free_col(npp, col); else if (col->lb == -DBL_MAX) npp_ubnd_col(npp, col); else if (col->ub == +DBL_MAX) { if (col->lb != 0.0) npp_lbnd_col(npp, col); } else if (col->lb != col->ub) { if (fabs(col->lb) < fabs(col->ub)) { if (col->lb != 0.0) npp_lbnd_col(npp, col); } else npp_ubnd_col(npp, col); npp_dbnd_col(npp, col); } else npp_fixed_col(npp, col); } for (row = npp->r_head; row != NULL; row = row->next) xassert(row->lb == row->ub); for (col = npp->c_head; col != NULL; col = col->next) xassert(col->lb == 0.0 && col->ub == +DBL_MAX); return; } int glp_interior(glp_prob *P, const glp_iptcp *parm) { glp_iptcp _parm; GLPROW *row; GLPCOL *col; NPP *npp = NULL; glp_prob *prob = NULL; int i, j, ret; /* check control parameters */ if (parm == NULL) glp_init_iptcp(&_parm), parm = &_parm; if (!(parm->msg_lev == GLP_MSG_OFF || parm->msg_lev == GLP_MSG_ERR || parm->msg_lev == GLP_MSG_ON || parm->msg_lev == GLP_MSG_ALL)) xerror("glp_interior: msg_lev = %d; invalid parameter\n", parm->msg_lev); if (!(parm->ord_alg == GLP_ORD_NONE || parm->ord_alg == GLP_ORD_QMD || parm->ord_alg == GLP_ORD_AMD || parm->ord_alg == GLP_ORD_SYMAMD)) xerror("glp_interior: ord_alg = %d; invalid parameter\n", parm->ord_alg); /* interior-point solution is currently undefined */ P->ipt_stat = GLP_UNDEF; P->ipt_obj = 0.0; /* check bounds of double-bounded variables */ for (i = 1; i <= P->m; i++) { row = P->row[i]; if (row->type == GLP_DB && row->lb >= row->ub) { if (parm->msg_lev >= GLP_MSG_ERR) xprintf("glp_interior: row %d: lb = %g, ub = %g; incorre" "ct bounds\n", i, row->lb, row->ub); ret = GLP_EBOUND; goto done; } } for (j = 1; j <= P->n; j++) { col = P->col[j]; if (col->type == GLP_DB && col->lb >= col->ub) { if (parm->msg_lev >= GLP_MSG_ERR) xprintf("glp_interior: column %d: lb = %g, ub = %g; inco" "rrect bounds\n", j, col->lb, col->ub); ret = GLP_EBOUND; goto done; } } /* transform LP to the standard formulation */ if (parm->msg_lev >= GLP_MSG_ALL) xprintf("Original LP has %d row(s), %d column(s), and %d non-z" "ero(s)\n", P->m, P->n, P->nnz); npp = npp_create_wksp(); npp_load_prob(npp, P, GLP_OFF, GLP_IPT, GLP_ON); transform(npp); prob = glp_create_prob(); npp_build_prob(npp, prob); if (parm->msg_lev >= GLP_MSG_ALL) xprintf("Working LP has %d row(s), %d column(s), and %d non-ze" "ro(s)\n", prob->m, prob->n, prob->nnz); #if 1 /* currently empty problem cannot be solved */ if (!(prob->m > 0 && prob->n > 0)) { if (parm->msg_lev >= GLP_MSG_ERR) xprintf("glp_interior: unable to solve empty problem\n"); ret = GLP_EFAIL; goto done; } #endif /* scale the resultant LP */ { ENV *env = get_env_ptr(); int term_out = env->term_out; env->term_out = GLP_OFF; glp_scale_prob(prob, GLP_SF_EQ); env->term_out = term_out; } /* warn about dense columns */ if (parm->msg_lev >= GLP_MSG_ON && prob->m >= 200) { int len, cnt = 0; for (j = 1; j <= prob->n; j++) { len = glp_get_mat_col(prob, j, NULL, NULL); if ((double)len >= 0.20 * (double)prob->m) cnt++; } if (cnt == 1) xprintf("WARNING: PROBLEM HAS ONE DENSE COLUMN\n"); else if (cnt > 0) xprintf("WARNING: PROBLEM HAS %d DENSE COLUMNS\n", cnt); } /* solve the transformed LP */ ret = ipm_solve(prob, parm); /* postprocess solution from the transformed LP */ npp_postprocess(npp, prob); /* and store solution to the original LP */ npp_unload_sol(npp, P); done: /* free working program objects */ if (npp != NULL) npp_delete_wksp(npp); if (prob != NULL) glp_delete_prob(prob); /* return to the application program */ return ret; } /*********************************************************************** * NAME * * glp_init_iptcp - initialize interior-point solver control parameters * * SYNOPSIS * * void glp_init_iptcp(glp_iptcp *parm); * * DESCRIPTION * * The routine glp_init_iptcp initializes control parameters, which are * used by the interior-point solver, with default values. * * Default values of the control parameters are stored in the glp_iptcp * structure, which the parameter parm points to. */ void glp_init_iptcp(glp_iptcp *parm) { parm->msg_lev = GLP_MSG_ALL; parm->ord_alg = GLP_ORD_AMD; return; } /*********************************************************************** * NAME * * glp_ipt_status - retrieve status of interior-point solution * * SYNOPSIS * * int glp_ipt_status(glp_prob *lp); * * RETURNS * * The routine glp_ipt_status reports the status of solution found by * the interior-point solver as follows: * * GLP_UNDEF - interior-point solution is undefined; * GLP_OPT - interior-point solution is optimal; * GLP_INFEAS - interior-point solution is infeasible; * GLP_NOFEAS - no feasible solution exists. */ int glp_ipt_status(glp_prob *lp) { int ipt_stat = lp->ipt_stat; return ipt_stat; } /*********************************************************************** * NAME * * glp_ipt_obj_val - retrieve objective value (interior point) * * SYNOPSIS * * double glp_ipt_obj_val(glp_prob *lp); * * RETURNS * * The routine glp_ipt_obj_val returns value of the objective function * for interior-point solution. */ double glp_ipt_obj_val(glp_prob *lp) { /*struct LPXCPS *cps = lp->cps;*/ double z; z = lp->ipt_obj; /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/ return z; } /*********************************************************************** * NAME * * glp_ipt_row_prim - retrieve row primal value (interior point) * * SYNOPSIS * * double glp_ipt_row_prim(glp_prob *lp, int i); * * RETURNS * * The routine glp_ipt_row_prim returns primal value of the auxiliary * variable associated with i-th row. */ double glp_ipt_row_prim(glp_prob *lp, int i) { /*struct LPXCPS *cps = lp->cps;*/ double pval; if (!(1 <= i && i <= lp->m)) xerror("glp_ipt_row_prim: i = %d; row number out of range\n", i); pval = lp->row[i]->pval; /*if (cps->round && fabs(pval) < 1e-9) pval = 0.0;*/ return pval; } /*********************************************************************** * NAME * * glp_ipt_row_dual - retrieve row dual value (interior point) * * SYNOPSIS * * double glp_ipt_row_dual(glp_prob *lp, int i); * * RETURNS * * The routine glp_ipt_row_dual returns dual value (i.e. reduced cost) * of the auxiliary variable associated with i-th row. */ double glp_ipt_row_dual(glp_prob *lp, int i) { /*struct LPXCPS *cps = lp->cps;*/ double dval; if (!(1 <= i && i <= lp->m)) xerror("glp_ipt_row_dual: i = %d; row number out of range\n", i); dval = lp->row[i]->dval; /*if (cps->round && fabs(dval) < 1e-9) dval = 0.0;*/ return dval; } /*********************************************************************** * NAME * * glp_ipt_col_prim - retrieve column primal value (interior point) * * SYNOPSIS * * double glp_ipt_col_prim(glp_prob *lp, int j); * * RETURNS * * The routine glp_ipt_col_prim returns primal value of the structural * variable associated with j-th column. */ double glp_ipt_col_prim(glp_prob *lp, int j) { /*struct LPXCPS *cps = lp->cps;*/ double pval; if (!(1 <= j && j <= lp->n)) xerror("glp_ipt_col_prim: j = %d; column number out of range\n" , j); pval = lp->col[j]->pval; /*if (cps->round && fabs(pval) < 1e-9) pval = 0.0;*/ return pval; } /*********************************************************************** * NAME * * glp_ipt_col_dual - retrieve column dual value (interior point) * * SYNOPSIS * * #include "glplpx.h" * double glp_ipt_col_dual(glp_prob *lp, int j); * * RETURNS * * The routine glp_ipt_col_dual returns dual value (i.e. reduced cost) * of the structural variable associated with j-th column. */ double glp_ipt_col_dual(glp_prob *lp, int j) { /*struct LPXCPS *cps = lp->cps;*/ double dval; if (!(1 <= j && j <= lp->n)) xerror("glp_ipt_col_dual: j = %d; column number out of range\n" , j); dval = lp->col[j]->dval; /*if (cps->round && fabs(dval) < 1e-9) dval = 0.0;*/ return dval; } /* eof */ Rglpk/src/GLPK/glpnpp.h0000644000176000001440000005331712245352174014374 0ustar ripleyusers/* glpnpp.h (LP/MIP preprocessor) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPNPP_H #define GLPNPP_H #include "glpapi.h" typedef struct NPP NPP; typedef struct NPPROW NPPROW; typedef struct NPPCOL NPPCOL; typedef struct NPPAIJ NPPAIJ; typedef struct NPPTSE NPPTSE; typedef struct NPPLFE NPPLFE; struct NPP { /* 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 */ Rglpk/src/GLPK/rng.h0000644000176000001440000000424412245352174013655 0ustar ripleyusers/* rng.h (pseudo-random number generator) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2003, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef RNG_H #define RNG_H typedef struct RNG RNG; struct RNG { /* Knuth's portable pseudo-random number generator */ int A[56]; /* pseudo-random values */ int *fptr; /* the next A value to be exported */ }; #define rng_create_rand _glp_rng_create_rand RNG *rng_create_rand(void); /* create pseudo-random number generator */ #define rng_init_rand _glp_rng_init_rand void rng_init_rand(RNG *rand, int seed); /* initialize pseudo-random number generator */ #define rng_next_rand _glp_rng_next_rand int rng_next_rand(RNG *rand); /* obtain pseudo-random integer in the range [0, 2^31-1] */ #define rng_unif_rand _glp_rng_unif_rand int rng_unif_rand(RNG *rand, int m); /* obtain pseudo-random integer in the range [0, m-1] */ #define rng_delete_rand _glp_rng_delete_rand void rng_delete_rand(RNG *rand); /* delete pseudo-random number generator */ #define rng_unif_01 _glp_rng_unif_01 double rng_unif_01(RNG *rand); /* obtain pseudo-random number in the range [0, 1] */ #define rng_uniform _glp_rng_uniform double rng_uniform(RNG *rand, double a, double b); /* obtain pseudo-random number in the range [a, b] */ #endif /* eof */ Rglpk/src/GLPK/glpapi18.c0000644000176000001440000001023612245352174014505 0ustar ripleyusers/* glpapi18.c (maximum clique problem) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpapi.h" #include "wclique.h" static void set_edge(int nv, unsigned char a[], int i, int j) { int k; xassert(1 <= j && j < i && i <= nv); k = ((i - 1) * (i - 2)) / 2 + (j - 1); a[k / CHAR_BIT] |= (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT)); return; } int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol, int v_set) { /* find maximum weight clique with exact algorithm */ glp_arc *e; int i, j, k, len, x, *w, *ind, ret = 0; unsigned char *a; double s, t; if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double)) xerror("glp_wclique_exact: v_wgt = %d; invalid parameter\n", v_wgt); if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) xerror("glp_wclique_exact: v_set = %d; invalid parameter\n", v_set); if (G->nv == 0) { /* empty graph has only empty clique */ if (sol != NULL) *sol = 0.0; return 0; } /* allocate working arrays */ w = xcalloc(1+G->nv, sizeof(int)); ind = xcalloc(1+G->nv, sizeof(int)); len = G->nv; /* # vertices */ len = len * (len - 1) / 2; /* # entries in lower triangle */ len = (len + (CHAR_BIT - 1)) / CHAR_BIT; /* # bytes needed */ a = xcalloc(len, sizeof(char)); memset(a, 0, len * sizeof(char)); /* determine vertex weights */ s = 0.0; for (i = 1; i <= G->nv; i++) { if (v_wgt >= 0) { memcpy(&t, (char *)G->v[i]->data + v_wgt, sizeof(double)); if (!(0.0 <= t && t <= (double)INT_MAX && t == floor(t))) { ret = GLP_EDATA; goto done; } w[i] = (int)t; } else w[i] = 1; s += (double)w[i]; } if (s > (double)INT_MAX) { ret = GLP_EDATA; goto done; } /* build the adjacency matrix */ for (i = 1; i <= G->nv; i++) { for (e = G->v[i]->in; e != NULL; e = e->h_next) { j = e->tail->i; /* there exists edge (j,i) in the graph */ if (i > j) set_edge(G->nv, a, i, j); } for (e = G->v[i]->out; e != NULL; e = e->t_next) { j = e->head->i; /* there exists edge (i,j) in the graph */ if (i > j) set_edge(G->nv, a, i, j); } } /* find maximum weight clique in the graph */ len = wclique(G->nv, w, a, ind); /* compute the clique weight */ s = 0.0; for (k = 1; k <= len; k++) { i = ind[k]; xassert(1 <= i && i <= G->nv); s += (double)w[i]; } if (sol != NULL) *sol = s; /* mark vertices included in the clique */ if (v_set >= 0) { x = 0; for (i = 1; i <= G->nv; i++) memcpy((char *)G->v[i]->data + v_set, &x, sizeof(int)); x = 1; for (k = 1; k <= len; k++) { i = ind[k]; memcpy((char *)G->v[i]->data + v_set, &x, sizeof(int)); } } done: /* free working arrays */ xfree(w); xfree(ind); xfree(a); return ret; } /* eof */ Rglpk/src/GLPK/stdout.c0000644000176000001440000001653712245352174014414 0ustar ripleyusers/* stdout.c (terminal output) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #undef NDEBUG #include #include "env.h" /*********************************************************************** * NAME * * glp_puts - write string on terminal * * SYNOPSIS * * void glp_puts(const char *s); * * The routine glp_puts writes the string s on the terminal. */ void glp_puts(const char *s) { ENV *env = get_env_ptr(); /* if terminal output is disabled, do nothing */ if (!env->term_out) goto skip; /* pass the string to the hook routine, if defined */ if (env->term_hook != NULL) { if (env->term_hook(env->term_info, s) != 0) goto skip; } /* write the string on the terminal */ fputs(s, stdout); fflush(stdout); /* write the string on the tee file, if required */ if (env->tee_file != NULL) { fputs(s, env->tee_file); fflush(env->tee_file); } skip: return; } /*********************************************************************** * NAME * * glp_printf - write formatted output on terminal * * SYNOPSIS * * void glp_printf(const char *fmt, ...); * * DESCRIPTION * * The routine glp_printf uses the format control string fmt to format * its parameters and writes the formatted output on the terminal. */ void glp_printf(const char *fmt, ...) { ENV *env = get_env_ptr(); va_list arg; /* if terminal output is disabled, do nothing */ if (!env->term_out) goto skip; /* format the output */ va_start(arg, fmt); vsprintf(env->term_buf, fmt, arg); /* (do not use xassert) */ assert(strlen(env->term_buf) < TBUF_SIZE); va_end(arg); /* write the formatted output on the terminal */ glp_puts(env->term_buf); skip: return; } /*********************************************************************** * NAME * * glp_vprintf - write formatted output on terminal * * SYNOPSIS * * void glp_vprintf(const char *fmt, va_list arg); * * DESCRIPTION * * The routine glp_vprintf uses the format control string fmt to format * its parameters specified by the list arg and writes the formatted * output on the terminal. */ void glp_vprintf(const char *fmt, va_list arg) { ENV *env = get_env_ptr(); /* if terminal output is disabled, do nothing */ if (!env->term_out) goto skip; /* format the output */ vsprintf(env->term_buf, fmt, arg); /* (do not use xassert) */ assert(strlen(env->term_buf) < TBUF_SIZE); /* write the formatted output on the terminal */ glp_puts(env->term_buf); skip: return; } /*********************************************************************** * NAME * * glp_term_out - enable/disable terminal output * * SYNOPSIS * * int glp_term_out(int flag); * * DESCRIPTION * * Depending on the parameter flag the routine glp_term_out enables or * disables terminal output performed by glpk routines: * * GLP_ON - enable terminal output; * GLP_OFF - disable terminal output. * * RETURNS * * The routine glp_term_out returns the previous value of the terminal * output flag. */ int glp_term_out(int flag) { ENV *env = get_env_ptr(); int old = env->term_out; if (!(flag == GLP_ON || flag == GLP_OFF)) xerror("glp_term_out: flag = %d; invalid parameter\n", flag); env->term_out = flag; return old; } /*********************************************************************** * NAME * * glp_term_hook - install hook to intercept terminal output * * SYNOPSIS * * void glp_term_hook(int (*func)(void *info, const char *s), * void *info); * * DESCRIPTION * * The routine glp_term_hook installs a user-defined hook routine to * intercept all terminal output performed by glpk routines. * * This feature can be used to redirect the terminal output to other * destination, for example to a file or a text window. * * The parameter func specifies the user-defined hook routine. It is * called from an internal printing routine, which passes to it two * parameters: info and s. The parameter info is a transit pointer, * specified in the corresponding call to the routine glp_term_hook; * it may be used to pass some information to the hook routine. The * parameter s is a pointer to the null terminated character string, * which is intended to be written to the terminal. If the hook routine * returns zero, the printing routine writes the string s to the * terminal in a usual way; otherwise, if the hook routine returns * non-zero, no terminal output is performed. * * To uninstall the hook routine the parameters func and info should be * specified as NULL. */ void glp_term_hook(int (*func)(void *info, const char *s), void *info) { ENV *env = get_env_ptr(); if (func == NULL) { env->term_hook = NULL; env->term_info = NULL; } else { env->term_hook = func; env->term_info = info; } return; } /*********************************************************************** * NAME * * glp_open_tee - start copying terminal output to text file * * SYNOPSIS * * int glp_open_tee(const char *name); * * DESCRIPTION * * The routine glp_open_tee starts copying all the terminal output to * an output text file, whose name is specified by the character string * name. * * RETURNS * * 0 - operation successful * 1 - copying terminal output is already active * 2 - unable to create output file */ int glp_open_tee(const char *name) { ENV *env = get_env_ptr(); if (env->tee_file != NULL) { /* copying terminal output is already active */ return 1; } env->tee_file = fopen(name, "w"); if (env->tee_file == NULL) { /* unable to create output file */ return 2; } return 0; } /*********************************************************************** * NAME * * glp_close_tee - stop copying terminal output to text file * * SYNOPSIS * * int glp_close_tee(void); * * DESCRIPTION * * The routine glp_close_tee stops copying the terminal output to the * output text file previously open by the routine glp_open_tee closing * that file. * * RETURNS * * 0 - operation successful * 1 - copying terminal output was not started */ int glp_close_tee(void) { ENV *env = get_env_ptr(); if (env->tee_file == NULL) { /* copying terminal output was not started */ return 1; } fclose(env->tee_file); env->tee_file = NULL; return 0; } /* eof */ Rglpk/src/GLPK/glpsdf.c0000644000176000001440000001601112245352174014334 0ustar ripleyusers/* glpsdf.c (plain data file reading routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #if 1 /* 11/VI-2013 */ #include "env2.h" #endif #include "glpapi.h" #include "glpsdf.h" #include "glplib.h" struct glp_data { /* plain data file */ char *fname; /* name of data file */ XFILE *fp; /* stream assigned to data file */ void *jump; /* jmp_buf jump; */ /* label for go to in case of error */ int count; /* line count */ int c; /* current character of XEOF */ char item[255+1]; /* current data item */ }; static void next_char(glp_data *data); glp_data *glp_sdf_open_file(const char *fname) { /* open plain data file */ glp_data *data = NULL; XFILE *fp; jmp_buf jump; fp = xfopen(fname, "r"); if (fp == NULL) { xprintf("Unable to open `%s' - %s\n", fname, xerrmsg()); goto done; } data = xmalloc(sizeof(glp_data)); data->fname = xmalloc(strlen(fname)+1); strcpy(data->fname, fname); data->fp = fp; data->jump = NULL; data->count = 0; data->c = '\n'; data->item[0] = '\0'; /* read the very first character */ if (setjmp(jump)) { glp_sdf_close_file(data); data = NULL; goto done; } data->jump = jump; next_char(data); data->jump = NULL; done: return data; } void glp_sdf_set_jump(glp_data *data, void *jump) { /* set up error handling */ data->jump = jump; return; } void glp_sdf_error(glp_data *data, const char *fmt, ...) { /* print error message */ va_list arg; xprintf("%s:%d: ", data->fname, data->count); va_start(arg, fmt); xvprintf(fmt, arg); va_end(arg); if (data->jump == NULL) xerror(""); else longjmp(data->jump, 1); /* no return */ } void glp_sdf_warning(glp_data *data, const char *fmt, ...) { /* print warning message */ va_list arg; xprintf("%s:%d: warning: ", data->fname, data->count); va_start(arg, fmt); xvprintf(fmt, arg); va_end(arg); return; } static void next_char(glp_data *data) { /* read next character */ int c; if (data->c == XEOF) glp_sdf_error(data, "unexpected end of file\n"); else if (data->c == '\n') data->count++; c = xfgetc(data->fp); if (c < 0) { if (xferror(data->fp)) glp_sdf_error(data, "read error - %s\n", xerrmsg()); else if (data->c == '\n') c = XEOF; else { glp_sdf_warning(data, "missing final end of line\n"); c = '\n'; } } else if (c == '\n') ; else if (isspace(c)) c = ' '; else if (iscntrl(c)) glp_sdf_error(data, "invalid control character 0x%02X\n", c); data->c = c; return; } static void skip_pad(glp_data *data) { /* skip uninteresting characters and comments */ loop: while (data->c == ' ' || data->c == '\n') next_char(data); if (data->c == '/') { next_char(data); if (data->c != '*') glp_sdf_error(data, "invalid use of slash\n"); next_char(data); for (;;) { if (data->c == '*') { next_char(data); if (data->c == '/') { next_char(data); break; } } next_char(data); } goto loop; } return; } static void next_item(glp_data *data) { /* read next item */ int len; skip_pad(data); len = 0; while (!(data->c == ' ' || data->c == '\n')) { data->item[len++] = (char)data->c; if (len == sizeof(data->item)) glp_sdf_error(data, "data item `%.31s...' too long\n", data->item); next_char(data); } data->item[len] = '\0'; return; } int glp_sdf_read_int(glp_data *data) { /* read integer number */ int x; next_item(data); switch (str2int(data->item, &x)) { case 0: break; case 1: glp_sdf_error(data, "integer `%s' out of range\n", data->item); case 2: glp_sdf_error(data, "cannot convert `%s' to integer\n", data->item); default: xassert(data != data); } return x; } double glp_sdf_read_num(glp_data *data) { /* read floating-point number */ double x; next_item(data); switch (str2num(data->item, &x)) { case 0: break; case 1: glp_sdf_error(data, "number `%s' out of range\n", data->item); case 2: glp_sdf_error(data, "cannot convert `%s' to number\n", data->item); default: xassert(data != data); } return x; } const char *glp_sdf_read_item(glp_data *data) { /* read data item */ next_item(data); return data->item; } const char *glp_sdf_read_text(glp_data *data) { /* read text until end of line */ int c, len = 0; for (;;) { c = data->c; next_char(data); if (c == ' ') { /* ignore initial spaces */ if (len == 0) continue; /* and multiple ones */ if (data->item[len-1] == ' ') continue; } else if (c == '\n') { /* remove trailing space */ if (len > 0 && data->item[len-1] == ' ') len--; /* and stop reading */ break; } /* add current character to the buffer */ data->item[len++] = (char)c; if (len == sizeof(data->item)) glp_sdf_error(data, "line too long\n", data->item); } data->item[len] = '\0'; return data->item; } int glp_sdf_line(glp_data *data) { /* determine current line number */ return data->count; } void glp_sdf_close_file(glp_data *data) { /* close plain data file */ xfclose(data->fp); xfree(data->fname); xfree(data); return; } /* eof */ Rglpk/src/GLPK/okalg.h0000644000176000001440000000242012245352174014156 0ustar ripleyusers/* okalg.h (out-of-kilter algorithm) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2009, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef OKALG_H #define OKALG_H #define okalg _glp_okalg int okalg(int nv, int na, const int tail[], const int head[], const int low[], const int cap[], const int cost[], int x[], int pi[]); /* out-of-kilter algorithm */ #endif /* eof */ Rglpk/src/GLPK/cfg.c0000644000176000001440000003261212245352174013621 0ustar ripleyusers/* cfg.c (conflict graph) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "cfg.h" #include "env.h" /*********************************************************************** * cfg_create_graph - create conflict graph * * This routine creates the conflict graph, which initially is empty, * and returns a pointer to the graph descriptor. * * The parameter n specifies the number of *all* variables in MIP, for * which the conflict graph will be built. * * The parameter nv_max specifies maximal number of vertices in the * conflict graph. It should be the double number of binary variables * in corresponding MIP. */ CFG *cfg_create_graph(int n, int nv_max) { CFG *G; xassert(n >= 0); xassert(0 <= nv_max && nv_max <= n + n); G = talloc(1, CFG); G->n = n; G->pos = talloc(1+n, int); memset(&G->pos[1], 0, n * sizeof(int)); G->neg = talloc(1+n, int); memset(&G->neg[1], 0, n * sizeof(int)); G->pool = dmp_create_pool(); G->nv_max = nv_max; G->nv = 0; G->ref = talloc(1+nv_max, int); G->vptr = talloc(1+nv_max, CFGVLE *); G->cptr = talloc(1+nv_max, CFGCLE *); return G; } /*********************************************************************** * cfg_add_clique - add clique to conflict graph * * This routine adds a clique to the conflict graph. * * The parameter size specifies the clique size, size >= 2. Note that * any edge can be considered as a clique of size 2. * * The array ind specifies vertices constituting the clique in elements * ind[k], 1 <= k <= size: * * ind[k] = +j means a vertex of the conflict graph that corresponds to * original binary variable x[j], 1 <= j <= n. * * ind[k] = -j means a vertex of the conflict graph that corresponds to * complement of original binary variable x[j], 1 <= j <= n. * * Note that if both vertices for x[j] and (1 - x[j]) have appeared in * the conflict graph, the routine automatically adds an edge incident * to these vertices. */ static void add_edge(CFG *G, int v, int w) { /* add clique of size 2 */ DMP *pool = G->pool; int nv = G->nv; CFGVLE **vptr = G->vptr; CFGVLE *vle; xassert(1 <= v && v <= nv); xassert(1 <= w && w <= nv); xassert(v != w); vle = dmp_talloc(pool, CFGVLE); vle->v = w; vle->next = vptr[v]; vptr[v] = vle; vle = dmp_talloc(pool, CFGVLE); vle->v = v; vle->next = vptr[w]; vptr[w] = vle; return; } void cfg_add_clique(CFG *G, int size, const int ind[]) { int n = G->n; int *pos = G->pos; int *neg = G->neg; DMP *pool = G->pool; int nv_max = G->nv_max; int *ref = G->ref; CFGVLE **vptr = G->vptr; CFGCLE **cptr = G->cptr; int j, k, v; xassert(2 <= size && size <= nv_max); /* add new vertices to the conflict graph */ for (k = 1; k <= size; k++) { j = ind[k]; if (j > 0) { /* vertex corresponds to x[j] */ xassert(1 <= j && j <= n); if (pos[j] == 0) { /* no such vertex exists; add it */ v = pos[j] = ++(G->nv); xassert(v <= nv_max); ref[v] = j; vptr[v] = NULL; cptr[v] = NULL; if (neg[j] != 0) { /* now both vertices for x[j] and (1 - x[j]) exist */ add_edge(G, v, neg[j]); } } } else { /* vertex corresponds to (1 - x[j]) */ j = -j; xassert(1 <= j && j <= n); if (neg[j] == 0) { /* no such vertex exists; add it */ v = neg[j] = ++(G->nv); xassert(v <= nv_max); ref[v] = j; vptr[v] = NULL; cptr[v] = NULL; if (pos[j] != 0) { /* now both vertices for x[j] and (1 - x[j]) exist */ add_edge(G, v, pos[j]); } } } } /* add specified clique to the conflict graph */ if (size == 2) add_edge(G, ind[1] > 0 ? pos[+ind[1]] : neg[-ind[1]], ind[2] > 0 ? pos[+ind[2]] : neg[-ind[2]]); else { CFGVLE *vp, *vle; CFGCLE *cle; /* build list of clique vertices */ vp = NULL; for (k = 1; k <= size; k++) { vle = dmp_talloc(pool, CFGVLE); vle->v = ind[k] > 0 ? pos[+ind[k]] : neg[-ind[k]]; vle->next = vp; vp = vle; } /* attach the clique to all its vertices */ for (k = 1; k <= size; k++) { cle = dmp_talloc(pool, CFGCLE); cle->vptr = vp; v = ind[k] > 0 ? pos[+ind[k]] : neg[-ind[k]]; cle->next = cptr[v]; cptr[v] = cle; } } return; } /*********************************************************************** * cfg_get_adjacent - get vertices adjacent to specified vertex * * This routine stores numbers of all vertices adjacent to specified * vertex v of the conflict graph in locations ind[1], ..., ind[len], * and returns len, 1 <= len <= nv-1, where nv is the total number of * vertices in the conflict graph. * * Note that the conflict graph defined by this routine has neither * self-loops nor multiple edges. */ int cfg_get_adjacent(CFG *G, int v, int ind[]) { int nv = G->nv; int *ref = G->ref; CFGVLE **vptr = G->vptr; CFGCLE **cptr = G->cptr; CFGVLE *vle; CFGCLE *cle; int k, w, len; xassert(1 <= v && v <= nv); len = 0; /* walk thru the list of adjacent vertices */ for (vle = vptr[v]; vle != NULL; vle = vle->next) { w = vle->v; xassert(1 <= w && w <= nv); xassert(w != v); if (ref[w] > 0) { ind[++len] = w; ref[w] = -ref[w]; } } /* walk thru the list of incident cliques */ for (cle = cptr[v]; cle != NULL; cle = cle->next) { /* walk thru the list of clique vertices */ for (vle = cle->vptr; vle != NULL; vle = vle->next) { w = vle->v; xassert(1 <= w && w <= nv); if (w != v && ref[w] > 0) { ind[++len] = w; ref[w] = -ref[w]; } } } xassert(1 <= len && len < nv); /* unmark vertices included in the resultant adjacency list */ for (k = 1; k <= len; k++) { w = ind[k]; ref[w] = -ref[w]; } return len; } /*********************************************************************** * cfg_expand_clique - expand specified clique to maximal clique * * Given some clique in the conflict graph this routine expands it to * a maximal clique by including in it new vertices. * * On entry vertex indices constituting the initial clique should be * stored in locations c_ind[1], ..., c_ind[c_len], where c_len is the * initial clique size. On exit the routine stores new vertex indices * to locations c_ind[c_len+1], ..., c_ind[c_len'], where c_len' is the * size of the maximal clique found, and returns c_len'. * * ALGORITHM * * Let G = (V, E) be a graph, C within V be a current clique to be * expanded, and D within V \ C be a subset of vertices adjacent to all * vertices from C. On every iteration the routine chooses some vertex * v in D, includes it into C, and removes from D the vertex v as well * as all vertices not adjacent to v. Initially C is empty and D = V. * Iterations repeat until D becomes an empty set. Obviously, the final * set C is a maximal clique in G. * * Now let C0 be an initial clique, and we want C0 to be a subset of * the final maximal clique C. To provide this condition the routine * starts constructing C by choosing only such vertices v in D, which * are in C0, until all vertices from C0 have been included in C. May * note that if on some iteration C0 \ C is non-empty (i.e. if not all * vertices from C0 have been included in C), C0 \ C is a subset of D, * because C0 is a clique. */ static int intersection(int d_len, int d_ind[], int d_pos[], int len, const int ind[]) { /* compute intersection D := D inter W, where W is some specified * set of vertices */ int k, t, v, new_len; /* walk thru vertices in W and mark vertices in D */ for (t = 1; t <= len; t++) { /* v in W */ v = ind[t]; /* determine position of v in D */ k = d_pos[v]; if (k != 0) { /* v in D */ xassert(d_ind[k] == v); /* mark v to keep it in D */ d_ind[k] = -v; } } /* remove all unmarked vertices from D */ new_len = 0; for (k = 1; k <= d_len; k++) { /* v in D */ v = d_ind[k]; if (v < 0) { /* v is marked; keep it */ v = -v; new_len++; d_ind[new_len] = v; d_pos[v] = new_len; } else { /* v is not marked; remove it */ d_pos[v] = 0; } } return new_len; } int cfg_expand_clique(CFG *G, int c_len, int c_ind[]) { int nv = G->nv; int d_len, *d_ind, *d_pos, len, *ind; int k, v; xassert(0 <= c_len && c_len <= nv); /* allocate working arrays */ d_ind = talloc(1+nv, int); d_pos = talloc(1+nv, int); ind = talloc(1+nv, int); /* initialize C := 0, D := V */ d_len = nv; for (k = 1; k <= nv; k++) d_ind[k] = d_pos[k] = k; /* expand C by vertices of specified initial clique C0 */ for (k = 1; k <= c_len; k++) { /* v in C0 */ v = c_ind[k]; xassert(1 <= v && v <= nv); /* since C0 is clique, v should be in D */ xassert(d_pos[v] != 0); /* W := set of vertices adjacent to v */ len = cfg_get_adjacent(G, v, ind); /* D := D inter W */ d_len = intersection(d_len, d_ind, d_pos, len, ind); /* since v not in W, now v should be not in D */ xassert(d_pos[v] == 0); } /* expand C by some other vertices until D is empty */ while (d_len > 0) { /* v in D */ v = d_ind[1]; xassert(1 <= v && v <= nv); /* note that v is adjacent to all vertices in C (by design), * so add v to C */ c_ind[++c_len] = v; /* W := set of vertices adjacent to v */ len = cfg_get_adjacent(G, v, ind); /* D := D inter W */ d_len = intersection(d_len, d_ind, d_pos, len, ind); /* since v not in W, now v should be not in D */ xassert(d_pos[v] == 0); } /* free working arrays */ tfree(d_ind); tfree(d_pos); tfree(ind); /* bring maximal clique to calling routine */ return c_len; } /*********************************************************************** * cfg_check_clique - check clique in conflict graph * * This routine checks that vertices of the conflict graph specified * in locations c_ind[1], ..., c_ind[c_len] constitute a clique. * * NOTE: for testing/debugging only. */ void cfg_check_clique(CFG *G, int c_len, const int c_ind[]) { int nv = G->nv; int k, kk, v, w, len, *ind; char *flag; ind = talloc(1+nv, int); flag = talloc(1+nv, char); memset(&flag[1], 0, nv); /* walk thru clique vertices */ xassert(c_len >= 0); for (k = 1; k <= c_len; k++) { /* get clique vertex v */ v = c_ind[k]; xassert(1 <= v && v <= nv); /* get vertices adjacent to vertex v */ len = cfg_get_adjacent(G, v, ind); for (kk = 1; kk <= len; kk++) { w = ind[kk]; xassert(1 <= w && w <= nv); xassert(w != v); flag[w] = 1; } /* check that all clique vertices other than v are adjacent to v */ for (kk = 1; kk <= c_len; kk++) { w = c_ind[kk]; xassert(1 <= w && w <= nv); if (w != v) xassert(flag[w]); } /* reset vertex flags */ for (kk = 1; kk <= len; kk++) flag[ind[kk]] = 0; } tfree(ind); tfree(flag); return; } /*********************************************************************** * cfg_delete_graph - delete conflict graph * * This routine deletes the conflict graph by freeing all the memory * allocated to this program object. */ void cfg_delete_graph(CFG *G) { tfree(G->pos); tfree(G->neg); dmp_delete_pool(G->pool); tfree(G->ref); tfree(G->vptr); tfree(G->cptr); tfree(G); return; } /* eof */ Rglpk/src/GLPK/glpssx01.c0000644000176000001440000006616512245352174014555 0ustar ripleyusers/* glpssx01.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #include "glpssx.h" #define xfault xerror /*---------------------------------------------------------------------- // ssx_create - create simplex solver workspace. // // This routine creates the workspace used by simplex solver routines, // and returns a pointer to it. // // Parameters m, n, and nnz specify, respectively, the number of rows, // columns, and non-zero constraint coefficients. // // This routine only allocates the memory for the workspace components, // so the workspace needs to be saturated by data. */ SSX *ssx_create(int m, int n, int nnz) { SSX *ssx; int i, j, k; if (m < 1) xfault("ssx_create: m = %d; invalid number of rows\n", m); if (n < 1) xfault("ssx_create: n = %d; invalid number of columns\n", n); if (nnz < 0) xfault("ssx_create: nnz = %d; invalid number of non-zero const" "raint coefficients\n", nnz); ssx = xmalloc(sizeof(SSX)); ssx->m = m; ssx->n = n; ssx->type = xcalloc(1+m+n, sizeof(int)); ssx->lb = xcalloc(1+m+n, sizeof(mpq_t)); for (k = 1; k <= m+n; k++) mpq_init(ssx->lb[k]); ssx->ub = xcalloc(1+m+n, sizeof(mpq_t)); for (k = 1; k <= m+n; k++) mpq_init(ssx->ub[k]); ssx->coef = xcalloc(1+m+n, sizeof(mpq_t)); for (k = 0; k <= m+n; k++) mpq_init(ssx->coef[k]); ssx->A_ptr = xcalloc(1+n+1, sizeof(int)); ssx->A_ptr[n+1] = nnz+1; ssx->A_ind = xcalloc(1+nnz, sizeof(int)); ssx->A_val = xcalloc(1+nnz, sizeof(mpq_t)); for (k = 1; k <= nnz; k++) mpq_init(ssx->A_val[k]); ssx->stat = xcalloc(1+m+n, sizeof(int)); ssx->Q_row = xcalloc(1+m+n, sizeof(int)); ssx->Q_col = xcalloc(1+m+n, sizeof(int)); ssx->binv = bfx_create_binv(); ssx->bbar = xcalloc(1+m, sizeof(mpq_t)); for (i = 0; i <= m; i++) mpq_init(ssx->bbar[i]); ssx->pi = xcalloc(1+m, sizeof(mpq_t)); for (i = 1; i <= m; i++) mpq_init(ssx->pi[i]); ssx->cbar = xcalloc(1+n, sizeof(mpq_t)); for (j = 1; j <= n; j++) mpq_init(ssx->cbar[j]); ssx->rho = xcalloc(1+m, sizeof(mpq_t)); for (i = 1; i <= m; i++) mpq_init(ssx->rho[i]); ssx->ap = xcalloc(1+n, sizeof(mpq_t)); for (j = 1; j <= n; j++) mpq_init(ssx->ap[j]); ssx->aq = xcalloc(1+m, sizeof(mpq_t)); for (i = 1; i <= m; i++) mpq_init(ssx->aq[i]); mpq_init(ssx->delta); return ssx; } /*---------------------------------------------------------------------- // ssx_factorize - factorize the current basis matrix. // // This routine computes factorization of the current basis matrix B // and returns the singularity flag. If the matrix B is non-singular, // the flag is zero, otherwise non-zero. */ static int basis_col(void *info, int j, int ind[], mpq_t val[]) { /* this auxiliary routine provides row indices and numeric values of non-zero elements in j-th column of the matrix B */ SSX *ssx = info; int m = ssx->m; int n = ssx->n; int *A_ptr = ssx->A_ptr; int *A_ind = ssx->A_ind; mpq_t *A_val = ssx->A_val; int *Q_col = ssx->Q_col; int k, len, ptr; xassert(1 <= j && j <= m); k = Q_col[j]; /* x[k] = xB[j] */ xassert(1 <= k && k <= m+n); /* j-th column of the matrix B is k-th column of the augmented constraint matrix (I | -A) */ if (k <= m) { /* it is a column of the unity matrix I */ len = 1, ind[1] = k, mpq_set_si(val[1], 1, 1); } else { /* it is a column of the original constraint matrix -A */ len = 0; for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++) { len++; ind[len] = A_ind[ptr]; mpq_neg(val[len], A_val[ptr]); } } return len; } int ssx_factorize(SSX *ssx) { int ret; ret = bfx_factorize(ssx->binv, ssx->m, basis_col, ssx); return ret; } /*---------------------------------------------------------------------- // ssx_get_xNj - determine value of non-basic variable. // // This routine determines the value of non-basic variable xN[j] in the // current basic solution defined as follows: // // 0, if xN[j] is free variable // lN[j], if xN[j] is on its lower bound // uN[j], if xN[j] is on its upper bound // lN[j] = uN[j], if xN[j] is fixed variable // // where lN[j] and uN[j] are lower and upper bounds of xN[j]. */ void ssx_get_xNj(SSX *ssx, int j, mpq_t x) { int m = ssx->m; int n = ssx->n; mpq_t *lb = ssx->lb; mpq_t *ub = ssx->ub; int *stat = ssx->stat; int *Q_col = ssx->Q_col; int k; xassert(1 <= j && j <= n); k = Q_col[m+j]; /* x[k] = xN[j] */ xassert(1 <= k && k <= m+n); switch (stat[k]) { case SSX_NL: /* xN[j] is on its lower bound */ mpq_set(x, lb[k]); break; case SSX_NU: /* xN[j] is on its upper bound */ mpq_set(x, ub[k]); break; case SSX_NF: /* xN[j] is free variable */ mpq_set_si(x, 0, 1); break; case SSX_NS: /* xN[j] is fixed variable */ mpq_set(x, lb[k]); break; default: xassert(stat != stat); } return; } /*---------------------------------------------------------------------- // ssx_eval_bbar - compute values of basic variables. // // This routine computes values of basic variables xB in the current // basic solution as follows: // // beta = - inv(B) * N * xN, // // where B is the basis matrix, N is the matrix of non-basic columns, // xN is a vector of current values of non-basic variables. */ void ssx_eval_bbar(SSX *ssx) { int m = ssx->m; int n = ssx->n; mpq_t *coef = ssx->coef; int *A_ptr = ssx->A_ptr; int *A_ind = ssx->A_ind; mpq_t *A_val = ssx->A_val; int *Q_col = ssx->Q_col; mpq_t *bbar = ssx->bbar; int i, j, k, ptr; mpq_t x, temp; mpq_init(x); mpq_init(temp); /* bbar := 0 */ for (i = 1; i <= m; i++) mpq_set_si(bbar[i], 0, 1); /* bbar := - N * xN = - N[1] * xN[1] - ... - N[n] * xN[n] */ for (j = 1; j <= n; j++) { ssx_get_xNj(ssx, j, x); if (mpq_sgn(x) == 0) continue; k = Q_col[m+j]; /* x[k] = xN[j] */ if (k <= m) { /* N[j] is a column of the unity matrix I */ mpq_sub(bbar[k], bbar[k], x); } else { /* N[j] is a column of the original constraint matrix -A */ for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++) { mpq_mul(temp, A_val[ptr], x); mpq_add(bbar[A_ind[ptr]], bbar[A_ind[ptr]], temp); } } } /* bbar := inv(B) * bbar */ bfx_ftran(ssx->binv, bbar, 0); #if 1 /* compute value of the objective function */ /* bbar[0] := c[0] */ mpq_set(bbar[0], coef[0]); /* bbar[0] := bbar[0] + sum{i in B} cB[i] * xB[i] */ for (i = 1; i <= m; i++) { k = Q_col[i]; /* x[k] = xB[i] */ if (mpq_sgn(coef[k]) == 0) continue; mpq_mul(temp, coef[k], bbar[i]); mpq_add(bbar[0], bbar[0], temp); } /* bbar[0] := bbar[0] + sum{j in N} cN[j] * xN[j] */ for (j = 1; j <= n; j++) { k = Q_col[m+j]; /* x[k] = xN[j] */ if (mpq_sgn(coef[k]) == 0) continue; ssx_get_xNj(ssx, j, x); mpq_mul(temp, coef[k], x); mpq_add(bbar[0], bbar[0], temp); } #endif mpq_clear(x); mpq_clear(temp); return; } /*---------------------------------------------------------------------- // ssx_eval_pi - compute values of simplex multipliers. // // This routine computes values of simplex multipliers (shadow prices) // pi in the current basic solution as follows: // // pi = inv(B') * cB, // // where B' is a matrix transposed to the basis matrix B, cB is a vector // of objective coefficients at basic variables xB. */ void ssx_eval_pi(SSX *ssx) { int m = ssx->m; mpq_t *coef = ssx->coef; int *Q_col = ssx->Q_col; mpq_t *pi = ssx->pi; int i; /* pi := cB */ for (i = 1; i <= m; i++) mpq_set(pi[i], coef[Q_col[i]]); /* pi := inv(B') * cB */ bfx_btran(ssx->binv, pi); return; } /*---------------------------------------------------------------------- // ssx_eval_dj - compute reduced cost of non-basic variable. // // This routine computes reduced cost d[j] of non-basic variable xN[j] // in the current basic solution as follows: // // d[j] = cN[j] - N[j] * pi, // // where cN[j] is an objective coefficient at xN[j], N[j] is a column // of the augmented constraint matrix (I | -A) corresponding to xN[j], // pi is the vector of simplex multipliers (shadow prices). */ void ssx_eval_dj(SSX *ssx, int j, mpq_t dj) { int m = ssx->m; int n = ssx->n; mpq_t *coef = ssx->coef; int *A_ptr = ssx->A_ptr; int *A_ind = ssx->A_ind; mpq_t *A_val = ssx->A_val; int *Q_col = ssx->Q_col; mpq_t *pi = ssx->pi; int k, ptr, end; mpq_t temp; mpq_init(temp); xassert(1 <= j && j <= n); k = Q_col[m+j]; /* x[k] = xN[j] */ xassert(1 <= k && k <= m+n); /* j-th column of the matrix N is k-th column of the augmented constraint matrix (I | -A) */ if (k <= m) { /* it is a column of the unity matrix I */ mpq_sub(dj, coef[k], pi[k]); } else { /* it is a column of the original constraint matrix -A */ mpq_set(dj, coef[k]); for (ptr = A_ptr[k-m], end = A_ptr[k-m+1]; ptr < end; ptr++) { mpq_mul(temp, A_val[ptr], pi[A_ind[ptr]]); mpq_add(dj, dj, temp); } } mpq_clear(temp); return; } /*---------------------------------------------------------------------- // ssx_eval_cbar - compute reduced costs of all non-basic variables. // // This routine computes the vector of reduced costs pi in the current // basic solution for all non-basic variables, including fixed ones. */ void ssx_eval_cbar(SSX *ssx) { int n = ssx->n; mpq_t *cbar = ssx->cbar; int j; for (j = 1; j <= n; j++) ssx_eval_dj(ssx, j, cbar[j]); return; } /*---------------------------------------------------------------------- // ssx_eval_rho - compute p-th row of the inverse. // // This routine computes p-th row of the matrix inv(B), where B is the // current basis matrix. // // p-th row of the inverse is computed using the following formula: // // rho = inv(B') * e[p], // // where B' is a matrix transposed to B, e[p] is a unity vector, which // contains one in p-th position. */ void ssx_eval_rho(SSX *ssx) { int m = ssx->m; int p = ssx->p; mpq_t *rho = ssx->rho; int i; xassert(1 <= p && p <= m); /* rho := 0 */ for (i = 1; i <= m; i++) mpq_set_si(rho[i], 0, 1); /* rho := e[p] */ mpq_set_si(rho[p], 1, 1); /* rho := inv(B') * rho */ bfx_btran(ssx->binv, rho); return; } /*---------------------------------------------------------------------- // ssx_eval_row - compute pivot row of the simplex table. // // This routine computes p-th (pivot) row of the current simplex table // A~ = - inv(B) * N using the following formula: // // A~[p] = - N' * inv(B') * e[p] = - N' * rho[p], // // where N' is a matrix transposed to the matrix N, rho[p] is p-th row // of the inverse inv(B). */ void ssx_eval_row(SSX *ssx) { int m = ssx->m; int n = ssx->n; int *A_ptr = ssx->A_ptr; int *A_ind = ssx->A_ind; mpq_t *A_val = ssx->A_val; int *Q_col = ssx->Q_col; mpq_t *rho = ssx->rho; mpq_t *ap = ssx->ap; int j, k, ptr; mpq_t temp; mpq_init(temp); for (j = 1; j <= n; j++) { /* ap[j] := - N'[j] * rho (inner product) */ k = Q_col[m+j]; /* x[k] = xN[j] */ if (k <= m) mpq_neg(ap[j], rho[k]); else { mpq_set_si(ap[j], 0, 1); for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++) { mpq_mul(temp, A_val[ptr], rho[A_ind[ptr]]); mpq_add(ap[j], ap[j], temp); } } } mpq_clear(temp); return; } /*---------------------------------------------------------------------- // ssx_eval_col - compute pivot column of the simplex table. // // This routine computes q-th (pivot) column of the current simplex // table A~ = - inv(B) * N using the following formula: // // A~[q] = - inv(B) * N[q], // // where N[q] is q-th column of the matrix N corresponding to chosen // non-basic variable xN[q]. */ void ssx_eval_col(SSX *ssx) { int m = ssx->m; int n = ssx->n; int *A_ptr = ssx->A_ptr; int *A_ind = ssx->A_ind; mpq_t *A_val = ssx->A_val; int *Q_col = ssx->Q_col; int q = ssx->q; mpq_t *aq = ssx->aq; int i, k, ptr; xassert(1 <= q && q <= n); /* aq := 0 */ for (i = 1; i <= m; i++) mpq_set_si(aq[i], 0, 1); /* aq := N[q] */ k = Q_col[m+q]; /* x[k] = xN[q] */ if (k <= m) { /* N[q] is a column of the unity matrix I */ mpq_set_si(aq[k], 1, 1); } else { /* N[q] is a column of the original constraint matrix -A */ for (ptr = A_ptr[k-m]; ptr < A_ptr[k-m+1]; ptr++) mpq_neg(aq[A_ind[ptr]], A_val[ptr]); } /* aq := inv(B) * aq */ bfx_ftran(ssx->binv, aq, 1); /* aq := - aq */ for (i = 1; i <= m; i++) mpq_neg(aq[i], aq[i]); return; } /*---------------------------------------------------------------------- // ssx_chuzc - choose pivot column. // // This routine chooses non-basic variable xN[q] whose reduced cost // indicates possible improving of the objective function to enter it // in the basis. // // Currently the standard (textbook) pricing is used, i.e. that // non-basic variable is preferred which has greatest reduced cost (in // magnitude). // // If xN[q] has been chosen, the routine stores its number q and also // sets the flag q_dir that indicates direction in which xN[q] has to // change (+1 means increasing, -1 means decreasing). // // If the choice cannot be made, because the current basic solution is // dual feasible, the routine sets the number q to 0. */ void ssx_chuzc(SSX *ssx) { int m = ssx->m; int n = ssx->n; int dir = (ssx->dir == SSX_MIN ? +1 : -1); int *Q_col = ssx->Q_col; int *stat = ssx->stat; mpq_t *cbar = ssx->cbar; int j, k, s, q, q_dir; double best, temp; /* nothing is chosen so far */ q = 0, q_dir = 0, best = 0.0; /* look through the list of non-basic variables */ for (j = 1; j <= n; j++) { k = Q_col[m+j]; /* x[k] = xN[j] */ s = dir * mpq_sgn(cbar[j]); if ((stat[k] == SSX_NF || stat[k] == SSX_NL) && s < 0 || (stat[k] == SSX_NF || stat[k] == SSX_NU) && s > 0) { /* reduced cost of xN[j] indicates possible improving of the objective function */ temp = fabs(mpq_get_d(cbar[j])); xassert(temp != 0.0); if (q == 0 || best < temp) q = j, q_dir = - s, best = temp; } } ssx->q = q, ssx->q_dir = q_dir; return; } /*---------------------------------------------------------------------- // ssx_chuzr - choose pivot row. // // This routine looks through elements of q-th column of the simplex // table and chooses basic variable xB[p] which should leave the basis. // // The choice is based on the standard (textbook) ratio test. // // If xB[p] has been chosen, the routine stores its number p and also // sets its non-basic status p_stat which should be assigned to xB[p] // when it has left the basis and become xN[q]. // // Special case p < 0 means that xN[q] is double-bounded variable and // it reaches its opposite bound before any basic variable does that, // so the current basis remains unchanged. // // If the choice cannot be made, because xN[q] can infinitely change in // the feasible direction, the routine sets the number p to 0. */ void ssx_chuzr(SSX *ssx) { int m = ssx->m; int n = ssx->n; int *type = ssx->type; mpq_t *lb = ssx->lb; mpq_t *ub = ssx->ub; int *Q_col = ssx->Q_col; mpq_t *bbar = ssx->bbar; int q = ssx->q; mpq_t *aq = ssx->aq; int q_dir = ssx->q_dir; int i, k, s, t, p, p_stat; mpq_t teta, temp; mpq_init(teta); mpq_init(temp); xassert(1 <= q && q <= n); xassert(q_dir == +1 || q_dir == -1); /* nothing is chosen so far */ p = 0, p_stat = 0; /* look through the list of basic variables */ for (i = 1; i <= m; i++) { s = q_dir * mpq_sgn(aq[i]); if (s < 0) { /* xB[i] decreases */ k = Q_col[i]; /* x[k] = xB[i] */ t = type[k]; if (t == SSX_LO || t == SSX_DB || t == SSX_FX) { /* xB[i] has finite lower bound */ mpq_sub(temp, bbar[i], lb[k]); mpq_div(temp, temp, aq[i]); mpq_abs(temp, temp); if (p == 0 || mpq_cmp(teta, temp) > 0) { p = i; p_stat = (t == SSX_FX ? SSX_NS : SSX_NL); mpq_set(teta, temp); } } } else if (s > 0) { /* xB[i] increases */ k = Q_col[i]; /* x[k] = xB[i] */ t = type[k]; if (t == SSX_UP || t == SSX_DB || t == SSX_FX) { /* xB[i] has finite upper bound */ mpq_sub(temp, bbar[i], ub[k]); mpq_div(temp, temp, aq[i]); mpq_abs(temp, temp); if (p == 0 || mpq_cmp(teta, temp) > 0) { p = i; p_stat = (t == SSX_FX ? SSX_NS : SSX_NU); mpq_set(teta, temp); } } } /* if something has been chosen and the ratio test indicates exact degeneracy, the search can be finished */ if (p != 0 && mpq_sgn(teta) == 0) break; } /* if xN[q] is double-bounded, check if it can reach its opposite bound before any basic variable */ k = Q_col[m+q]; /* x[k] = xN[q] */ if (type[k] == SSX_DB) { mpq_sub(temp, ub[k], lb[k]); if (p == 0 || mpq_cmp(teta, temp) > 0) { p = -1; p_stat = -1; mpq_set(teta, temp); } } ssx->p = p; ssx->p_stat = p_stat; /* if xB[p] has been chosen, determine its actual change in the adjacent basis (it has the same sign as q_dir) */ if (p != 0) { xassert(mpq_sgn(teta) >= 0); if (q_dir > 0) mpq_set(ssx->delta, teta); else mpq_neg(ssx->delta, teta); } mpq_clear(teta); mpq_clear(temp); return; } /*---------------------------------------------------------------------- // ssx_update_bbar - update values of basic variables. // // This routine recomputes the current values of basic variables for // the adjacent basis. // // The simplex table for the current basis is the following: // // xB[i] = sum{j in 1..n} alfa[i,j] * xN[q], i = 1,...,m // // therefore // // delta xB[i] = alfa[i,q] * delta xN[q], i = 1,...,m // // where delta xN[q] = xN.new[q] - xN[q] is the change of xN[q] in the // adjacent basis, and delta xB[i] = xB.new[i] - xB[i] is the change of // xB[i]. This gives formulae for recomputing values of xB[i]: // // xB.new[p] = xN[q] + delta xN[q] // // (because xN[q] becomes xB[p] in the adjacent basis), and // // xB.new[i] = xB[i] + alfa[i,q] * delta xN[q], i != p // // for other basic variables. */ void ssx_update_bbar(SSX *ssx) { int m = ssx->m; int n = ssx->n; mpq_t *bbar = ssx->bbar; mpq_t *cbar = ssx->cbar; int p = ssx->p; int q = ssx->q; mpq_t *aq = ssx->aq; int i; mpq_t temp; mpq_init(temp); xassert(1 <= q && q <= n); if (p < 0) { /* xN[q] is double-bounded and goes to its opposite bound */ /* nop */; } else { /* xN[q] becomes xB[p] in the adjacent basis */ /* xB.new[p] = xN[q] + delta xN[q] */ xassert(1 <= p && p <= m); ssx_get_xNj(ssx, q, temp); mpq_add(bbar[p], temp, ssx->delta); } /* update values of other basic variables depending on xN[q] */ for (i = 1; i <= m; i++) { if (i == p) continue; /* xB.new[i] = xB[i] + alfa[i,q] * delta xN[q] */ if (mpq_sgn(aq[i]) == 0) continue; mpq_mul(temp, aq[i], ssx->delta); mpq_add(bbar[i], bbar[i], temp); } #if 1 /* update value of the objective function */ /* z.new = z + d[q] * delta xN[q] */ mpq_mul(temp, cbar[q], ssx->delta); mpq_add(bbar[0], bbar[0], temp); #endif mpq_clear(temp); return; } /*---------------------------------------------------------------------- -- ssx_update_pi - update simplex multipliers. -- -- This routine recomputes the vector of simplex multipliers for the -- adjacent basis. */ void ssx_update_pi(SSX *ssx) { int m = ssx->m; int n = ssx->n; mpq_t *pi = ssx->pi; mpq_t *cbar = ssx->cbar; int p = ssx->p; int q = ssx->q; mpq_t *aq = ssx->aq; mpq_t *rho = ssx->rho; int i; mpq_t new_dq, temp; mpq_init(new_dq); mpq_init(temp); xassert(1 <= p && p <= m); xassert(1 <= q && q <= n); /* compute d[q] in the adjacent basis */ mpq_div(new_dq, cbar[q], aq[p]); /* update the vector of simplex multipliers */ for (i = 1; i <= m; i++) { if (mpq_sgn(rho[i]) == 0) continue; mpq_mul(temp, new_dq, rho[i]); mpq_sub(pi[i], pi[i], temp); } mpq_clear(new_dq); mpq_clear(temp); return; } /*---------------------------------------------------------------------- // ssx_update_cbar - update reduced costs of non-basic variables. // // This routine recomputes the vector of reduced costs of non-basic // variables for the adjacent basis. */ void ssx_update_cbar(SSX *ssx) { int m = ssx->m; int n = ssx->n; mpq_t *cbar = ssx->cbar; int p = ssx->p; int q = ssx->q; mpq_t *ap = ssx->ap; int j; mpq_t temp; mpq_init(temp); xassert(1 <= p && p <= m); xassert(1 <= q && q <= n); /* compute d[q] in the adjacent basis */ /* d.new[q] = d[q] / alfa[p,q] */ mpq_div(cbar[q], cbar[q], ap[q]); /* update reduced costs of other non-basic variables */ for (j = 1; j <= n; j++) { if (j == q) continue; /* d.new[j] = d[j] - (alfa[p,j] / alfa[p,q]) * d[q] */ if (mpq_sgn(ap[j]) == 0) continue; mpq_mul(temp, ap[j], cbar[q]); mpq_sub(cbar[j], cbar[j], temp); } mpq_clear(temp); return; } /*---------------------------------------------------------------------- // ssx_change_basis - change current basis to adjacent one. // // This routine changes the current basis to the adjacent one swapping // basic variable xB[p] and non-basic variable xN[q]. */ void ssx_change_basis(SSX *ssx) { int m = ssx->m; int n = ssx->n; int *type = ssx->type; int *stat = ssx->stat; int *Q_row = ssx->Q_row; int *Q_col = ssx->Q_col; int p = ssx->p; int q = ssx->q; int p_stat = ssx->p_stat; int k, kp, kq; if (p < 0) { /* special case: xN[q] goes to its opposite bound */ xassert(1 <= q && q <= n); k = Q_col[m+q]; /* x[k] = xN[q] */ xassert(type[k] == SSX_DB); switch (stat[k]) { case SSX_NL: stat[k] = SSX_NU; break; case SSX_NU: stat[k] = SSX_NL; break; default: xassert(stat != stat); } } else { /* xB[p] leaves the basis, xN[q] enters the basis */ xassert(1 <= p && p <= m); xassert(1 <= q && q <= n); kp = Q_col[p]; /* x[kp] = xB[p] */ kq = Q_col[m+q]; /* x[kq] = xN[q] */ /* check non-basic status of xB[p] which becomes xN[q] */ switch (type[kp]) { case SSX_FR: xassert(p_stat == SSX_NF); break; case SSX_LO: xassert(p_stat == SSX_NL); break; case SSX_UP: xassert(p_stat == SSX_NU); break; case SSX_DB: xassert(p_stat == SSX_NL || p_stat == SSX_NU); break; case SSX_FX: xassert(p_stat == SSX_NS); break; default: xassert(type != type); } /* swap xB[p] and xN[q] */ stat[kp] = (char)p_stat, stat[kq] = SSX_BS; Q_row[kp] = m+q, Q_row[kq] = p; Q_col[p] = kq, Q_col[m+q] = kp; /* update factorization of the basis matrix */ if (bfx_update(ssx->binv, p)) { if (ssx_factorize(ssx)) xassert(("Internal error: basis matrix is singular", 0)); } } return; } /*---------------------------------------------------------------------- // ssx_delete - delete simplex solver workspace. // // This routine deletes the simplex solver workspace freeing all the // memory allocated to this object. */ void ssx_delete(SSX *ssx) { int m = ssx->m; int n = ssx->n; int nnz = ssx->A_ptr[n+1]-1; int i, j, k; xfree(ssx->type); for (k = 1; k <= m+n; k++) mpq_clear(ssx->lb[k]); xfree(ssx->lb); for (k = 1; k <= m+n; k++) mpq_clear(ssx->ub[k]); xfree(ssx->ub); for (k = 0; k <= m+n; k++) mpq_clear(ssx->coef[k]); xfree(ssx->coef); xfree(ssx->A_ptr); xfree(ssx->A_ind); for (k = 1; k <= nnz; k++) mpq_clear(ssx->A_val[k]); xfree(ssx->A_val); xfree(ssx->stat); xfree(ssx->Q_row); xfree(ssx->Q_col); bfx_delete_binv(ssx->binv); for (i = 0; i <= m; i++) mpq_clear(ssx->bbar[i]); xfree(ssx->bbar); for (i = 1; i <= m; i++) mpq_clear(ssx->pi[i]); xfree(ssx->pi); for (j = 1; j <= n; j++) mpq_clear(ssx->cbar[j]); xfree(ssx->cbar); for (i = 1; i <= m; i++) mpq_clear(ssx->rho[i]); xfree(ssx->rho); for (j = 1; j <= n; j++) mpq_clear(ssx->ap[j]); xfree(ssx->ap); for (i = 1; i <= m; i++) mpq_clear(ssx->aq[i]); xfree(ssx->aq); mpq_clear(ssx->delta); xfree(ssx); return; } /* eof */ Rglpk/src/GLPK/glpios07.c0000644000176000001440000004524512245352174014534 0ustar ripleyusers/* glpios07.c (mixed cover cut generator) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpios.h" /*---------------------------------------------------------------------- -- COVER INEQUALITIES -- -- Consider the set of feasible solutions to 0-1 knapsack problem: -- -- sum a[j]*x[j] <= b, (1) -- j in J -- -- x[j] is binary, (2) -- -- where, wlog, we assume that a[j] > 0 (since 0-1 variables can be -- complemented) and a[j] <= b (since a[j] > b implies x[j] = 0). -- -- A set C within J is called a cover if -- -- sum a[j] > b. (3) -- j in C -- -- For any cover C the inequality -- -- sum x[j] <= |C| - 1 (4) -- j in C -- -- is called a cover inequality and is valid for (1)-(2). -- -- MIXED COVER INEQUALITIES -- -- Consider the set of feasible solutions to mixed knapsack problem: -- -- sum a[j]*x[j] + y <= b, (5) -- j in J -- -- x[j] is binary, (6) -- -- 0 <= y <= u is continuous, (7) -- -- where again we assume that a[j] > 0. -- -- Let C within J be some set. From (1)-(4) it follows that -- -- sum a[j] > b - y (8) -- j in C -- -- implies -- -- sum x[j] <= |C| - 1. (9) -- j in C -- -- Thus, we need to modify the inequality (9) in such a way that it be -- a constraint only if the condition (8) is satisfied. -- -- Consider the following inequality: -- -- sum x[j] <= |C| - t. (10) -- j in C -- -- If 0 < t <= 1, then (10) is equivalent to (9), because all x[j] are -- binary variables. On the other hand, if t <= 0, (10) being satisfied -- for any values of x[j] is not a constraint. -- -- Let -- -- t' = sum a[j] + y - b. (11) -- j in C -- -- It is understood that the condition t' > 0 is equivalent to (8). -- Besides, from (6)-(7) it follows that t' has an implied upper bound: -- -- t'max = sum a[j] + u - b. (12) -- j in C -- -- This allows to express the parameter t having desired properties: -- -- t = t' / t'max. (13) -- -- In fact, t <= 1 by definition, and t > 0 being equivalent to t' > 0 -- is equivalent to (8). -- -- Thus, the inequality (10), where t is given by formula (13) is valid -- for (5)-(7). -- -- Note that if u = 0, then y = 0, so t = 1, and the conditions (8) and -- (10) is transformed to the conditions (3) and (4). -- -- GENERATING MIXED COVER CUTS -- -- To generate a mixed cover cut in the form (10) we need to find such -- set C which satisfies to the inequality (8) and for which, in turn, -- the inequality (10) is violated in the current point. -- -- Substituting t from (13) to (10) gives: -- -- 1 -- sum x[j] <= |C| - ----- (sum a[j] + y - b), (14) -- j in C t'max j in C -- -- and finally we have the cut inequality in the standard form: -- -- sum x[j] + alfa * y <= beta, (15) -- j in C -- -- where: -- -- alfa = 1 / t'max, (16) -- -- beta = |C| - alfa * (sum a[j] - b). (17) -- j in C */ #if 1 #define MAXTRY 1000 #else #define MAXTRY 10000 #endif static int cover2(int n, double a[], double b, double u, double x[], double y, int cov[], double *_alfa, double *_beta) { /* try to generate mixed cover cut using two-element cover */ int i, j, try = 0, ret = 0; double eps, alfa, beta, temp, rmax = 0.001; eps = 0.001 * (1.0 + fabs(b)); for (i = 0+1; i <= n; i++) for (j = i+1; j <= n; j++) { /* C = {i, j} */ try++; if (try > MAXTRY) goto done; /* check if condition (8) is satisfied */ if (a[i] + a[j] + y > b + eps) { /* compute parameters for inequality (15) */ temp = a[i] + a[j] - b; alfa = 1.0 / (temp + u); beta = 2.0 - alfa * temp; /* compute violation of inequality (15) */ temp = x[i] + x[j] + alfa * y - beta; /* choose C providing maximum violation */ if (rmax < temp) { rmax = temp; cov[1] = i; cov[2] = j; *_alfa = alfa; *_beta = beta; ret = 1; } } } done: return ret; } static int cover3(int n, double a[], double b, double u, double x[], double y, int cov[], double *_alfa, double *_beta) { /* try to generate mixed cover cut using three-element cover */ int i, j, k, try = 0, ret = 0; double eps, alfa, beta, temp, rmax = 0.001; eps = 0.001 * (1.0 + fabs(b)); for (i = 0+1; i <= n; i++) for (j = i+1; j <= n; j++) for (k = j+1; k <= n; k++) { /* C = {i, j, k} */ try++; if (try > MAXTRY) goto done; /* check if condition (8) is satisfied */ if (a[i] + a[j] + a[k] + y > b + eps) { /* compute parameters for inequality (15) */ temp = a[i] + a[j] + a[k] - b; alfa = 1.0 / (temp + u); beta = 3.0 - alfa * temp; /* compute violation of inequality (15) */ temp = x[i] + x[j] + x[k] + alfa * y - beta; /* choose C providing maximum violation */ if (rmax < temp) { rmax = temp; cov[1] = i; cov[2] = j; cov[3] = k; *_alfa = alfa; *_beta = beta; ret = 1; } } } done: return ret; } static int cover4(int n, double a[], double b, double u, double x[], double y, int cov[], double *_alfa, double *_beta) { /* try to generate mixed cover cut using four-element cover */ int i, j, k, l, try = 0, ret = 0; double eps, alfa, beta, temp, rmax = 0.001; eps = 0.001 * (1.0 + fabs(b)); for (i = 0+1; i <= n; i++) for (j = i+1; j <= n; j++) for (k = j+1; k <= n; k++) for (l = k+1; l <= n; l++) { /* C = {i, j, k, l} */ try++; if (try > MAXTRY) goto done; /* check if condition (8) is satisfied */ if (a[i] + a[j] + a[k] + a[l] + y > b + eps) { /* compute parameters for inequality (15) */ temp = a[i] + a[j] + a[k] + a[l] - b; alfa = 1.0 / (temp + u); beta = 4.0 - alfa * temp; /* compute violation of inequality (15) */ temp = x[i] + x[j] + x[k] + x[l] + alfa * y - beta; /* choose C providing maximum violation */ if (rmax < temp) { rmax = temp; cov[1] = i; cov[2] = j; cov[3] = k; cov[4] = l; *_alfa = alfa; *_beta = beta; ret = 1; } } } done: return ret; } static int cover(int n, double a[], double b, double u, double x[], double y, int cov[], double *alfa, double *beta) { /* try to generate mixed cover cut; input (see (5)): n is the number of binary variables; a[1:n] are coefficients at binary variables; b is the right-hand side; u is upper bound of continuous variable; x[1:n] are values of binary variables at current point; y is value of continuous variable at current point; output (see (15), (16), (17)): cov[1:r] are indices of binary variables included in cover C, where r is the set cardinality returned on exit; alfa coefficient at continuous variable; beta is the right-hand side; */ int j; /* perform some sanity checks */ xassert(n >= 2); for (j = 1; j <= n; j++) xassert(a[j] > 0.0); #if 1 /* ??? */ xassert(b > -1e-5); #else xassert(b > 0.0); #endif xassert(u >= 0.0); for (j = 1; j <= n; j++) xassert(0.0 <= x[j] && x[j] <= 1.0); xassert(0.0 <= y && y <= u); /* try to generate mixed cover cut */ if (cover2(n, a, b, u, x, y, cov, alfa, beta)) return 2; if (cover3(n, a, b, u, x, y, cov, alfa, beta)) return 3; if (cover4(n, a, b, u, x, y, cov, alfa, beta)) return 4; return 0; } /*---------------------------------------------------------------------- -- lpx_cover_cut - generate mixed cover cut. -- -- SYNOPSIS -- -- #include "glplpx.h" -- int lpx_cover_cut(LPX *lp, int len, int ind[], double val[], -- double work[]); -- -- DESCRIPTION -- -- The routine lpx_cover_cut generates a mixed cover cut for a given -- row of the MIP problem. -- -- The given row of the MIP problem should be explicitly specified in -- the form: -- -- sum{j in J} a[j]*x[j] <= b. (1) -- -- On entry indices (ordinal numbers) of structural variables, which -- have non-zero constraint coefficients, should be placed in locations -- ind[1], ..., ind[len], and corresponding constraint coefficients -- should be placed in locations val[1], ..., val[len]. The right-hand -- side b should be stored in location val[0]. -- -- The working array work should have at least nb locations, where nb -- is the number of binary variables in (1). -- -- The routine generates a mixed cover cut in the same form as (1) and -- stores the cut coefficients and right-hand side in the same way as -- just described above. -- -- RETURNS -- -- If the cutting plane has been successfully generated, the routine -- returns 1 <= len' <= n, which is the number of non-zero coefficients -- in the inequality constraint. Otherwise, the routine returns zero. */ static int lpx_cover_cut(LPX *lp, int len, int ind[], double val[], double work[]) { int cov[1+4], j, k, nb, newlen, r; double f_min, f_max, alfa, beta, u, *x = work, y; /* substitute and remove fixed variables */ newlen = 0; for (k = 1; k <= len; k++) { j = ind[k]; if (lpx_get_col_type(lp, j) == LPX_FX) val[0] -= val[k] * lpx_get_col_lb(lp, j); else { newlen++; ind[newlen] = ind[k]; val[newlen] = val[k]; } } len = newlen; /* move binary variables to the beginning of the list so that elements 1, 2, ..., nb correspond to binary variables, and elements nb+1, nb+2, ..., len correspond to rest variables */ nb = 0; for (k = 1; k <= len; k++) { j = ind[k]; if (lpx_get_col_kind(lp, j) == LPX_IV && lpx_get_col_type(lp, j) == LPX_DB && lpx_get_col_lb(lp, j) == 0.0 && lpx_get_col_ub(lp, j) == 1.0) { /* binary variable */ int ind_k; double val_k; nb++; ind_k = ind[nb], val_k = val[nb]; ind[nb] = ind[k], val[nb] = val[k]; ind[k] = ind_k, val[k] = val_k; } } /* now the specified row has the form: sum a[j]*x[j] + sum a[j]*y[j] <= b, where x[j] are binary variables, y[j] are rest variables */ /* at least two binary variables are needed */ if (nb < 2) return 0; /* compute implied lower and upper bounds for sum a[j]*y[j] */ f_min = f_max = 0.0; for (k = nb+1; k <= len; k++) { j = ind[k]; /* both bounds must be finite */ if (lpx_get_col_type(lp, j) != LPX_DB) return 0; if (val[k] > 0.0) { f_min += val[k] * lpx_get_col_lb(lp, j); f_max += val[k] * lpx_get_col_ub(lp, j); } else { f_min += val[k] * lpx_get_col_ub(lp, j); f_max += val[k] * lpx_get_col_lb(lp, j); } } /* sum a[j]*x[j] + sum a[j]*y[j] <= b ===> sum a[j]*x[j] + (sum a[j]*y[j] - f_min) <= b - f_min ===> sum a[j]*x[j] + y <= b - f_min, where y = sum a[j]*y[j] - f_min; note that 0 <= y <= u, u = f_max - f_min */ /* determine upper bound of y */ u = f_max - f_min; /* determine value of y at the current point */ y = 0.0; for (k = nb+1; k <= len; k++) { j = ind[k]; y += val[k] * lpx_get_col_prim(lp, j); } y -= f_min; if (y < 0.0) y = 0.0; if (y > u) y = u; /* modify the right-hand side b */ val[0] -= f_min; /* now the transformed row has the form: sum a[j]*x[j] + y <= b, where 0 <= y <= u */ /* determine values of x[j] at the current point */ for (k = 1; k <= nb; k++) { j = ind[k]; x[k] = lpx_get_col_prim(lp, j); if (x[k] < 0.0) x[k] = 0.0; if (x[k] > 1.0) x[k] = 1.0; } /* if a[j] < 0, replace x[j] by its complement 1 - x'[j] */ for (k = 1; k <= nb; k++) { if (val[k] < 0.0) { ind[k] = - ind[k]; val[k] = - val[k]; val[0] += val[k]; x[k] = 1.0 - x[k]; } } /* try to generate a mixed cover cut for the transformed row */ r = cover(nb, val, val[0], u, x, y, cov, &alfa, &beta); if (r == 0) return 0; xassert(2 <= r && r <= 4); /* now the cut is in the form: sum{j in C} x[j] + alfa * y <= beta */ /* store the right-hand side beta */ ind[0] = 0, val[0] = beta; /* restore the original ordinal numbers of x[j] */ for (j = 1; j <= r; j++) cov[j] = ind[cov[j]]; /* store cut coefficients at binary variables complementing back the variables having negative row coefficients */ xassert(r <= nb); for (k = 1; k <= r; k++) { if (cov[k] > 0) { ind[k] = +cov[k]; val[k] = +1.0; } else { ind[k] = -cov[k]; val[k] = -1.0; val[0] -= 1.0; } } /* substitute y = sum a[j]*y[j] - f_min */ for (k = nb+1; k <= len; k++) { r++; ind[r] = ind[k]; val[r] = alfa * val[k]; } val[0] += alfa * f_min; xassert(r <= len); len = r; return len; } /*---------------------------------------------------------------------- -- lpx_eval_row - compute explictily specified row. -- -- SYNOPSIS -- -- #include "glplpx.h" -- double lpx_eval_row(LPX *lp, int len, int ind[], double val[]); -- -- DESCRIPTION -- -- The routine lpx_eval_row computes the primal value of an explicitly -- specified row using current values of structural variables. -- -- The explicitly specified row may be thought as a linear form: -- -- y = a[1]*x[m+1] + a[2]*x[m+2] + ... + a[n]*x[m+n], -- -- where y is an auxiliary variable for this row, a[j] are coefficients -- of the linear form, x[m+j] are structural variables. -- -- On entry column indices and numerical values of non-zero elements of -- the row should be stored in locations ind[1], ..., ind[len] and -- val[1], ..., val[len], where len is the number of non-zero elements. -- The array ind and val are not changed on exit. -- -- RETURNS -- -- The routine returns a computed value of y, the auxiliary variable of -- the specified row. */ static double lpx_eval_row(LPX *lp, int len, int ind[], double val[]) { int n = lpx_get_num_cols(lp); int j, k; double sum = 0.0; if (len < 0) xerror("lpx_eval_row: len = %d; invalid row length\n", len); for (k = 1; k <= len; k++) { j = ind[k]; if (!(1 <= j && j <= n)) xerror("lpx_eval_row: j = %d; column number out of range\n", j); sum += val[k] * lpx_get_col_prim(lp, j); } return sum; } /*********************************************************************** * NAME * * ios_cov_gen - generate mixed cover cuts * * SYNOPSIS * * #include "glpios.h" * void ios_cov_gen(glp_tree *tree); * * DESCRIPTION * * The routine ios_cov_gen generates mixed cover cuts for the current * point and adds them to the cut pool. */ void ios_cov_gen(glp_tree *tree) { glp_prob *prob = tree->mip; int m = lpx_get_num_rows(prob); int n = lpx_get_num_cols(prob); int i, k, type, kase, len, *ind; double r, *val, *work; xassert(lpx_get_status(prob) == LPX_OPT); /* allocate working arrays */ ind = xcalloc(1+n, sizeof(int)); val = xcalloc(1+n, sizeof(double)); work = xcalloc(1+n, sizeof(double)); /* look through all rows */ for (i = 1; i <= m; i++) for (kase = 1; kase <= 2; kase++) { type = lpx_get_row_type(prob, i); if (kase == 1) { /* consider rows of '<=' type */ if (!(type == LPX_UP || type == LPX_DB)) continue; len = lpx_get_mat_row(prob, i, ind, val); val[0] = lpx_get_row_ub(prob, i); } else { /* consider rows of '>=' type */ if (!(type == LPX_LO || type == LPX_DB)) continue; len = lpx_get_mat_row(prob, i, ind, val); for (k = 1; k <= len; k++) val[k] = - val[k]; val[0] = - lpx_get_row_lb(prob, i); } /* generate mixed cover cut: sum{j in J} a[j] * x[j] <= b */ len = lpx_cover_cut(prob, len, ind, val, work); if (len == 0) continue; /* at the current point the cut inequality is violated, i.e. sum{j in J} a[j] * x[j] - b > 0 */ r = lpx_eval_row(prob, len, ind, val) - val[0]; if (r < 1e-3) continue; /* add the cut to the cut pool */ glp_ios_add_row(tree, NULL, GLP_RF_COV, 0, len, ind, val, GLP_UP, val[0]); } /* free working arrays */ xfree(ind); xfree(val); xfree(work); return; } /* eof */ Rglpk/src/GLPK/glpmpl04.c0000644000176000001440000013407512245352174014527 0ustar ripleyusers/* glpmpl04.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #define _GLPSTD_ERRNO #define _GLPSTD_STDIO #include "glpmpl.h" #define xfault xerror #define dmp_create_poolx(size) dmp_create_pool() /**********************************************************************/ /* * * GENERATING AND POSTSOLVING MODEL * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- alloc_content - allocate content arrays for all model objects. -- -- This routine allocates content arrays for all existing model objects -- and thereby finalizes creating model. -- -- This routine must be called immediately after reading model section, -- i.e. before reading data section or generating model. */ void alloc_content(MPL *mpl) { STATEMENT *stmt; /* walk through all model statements */ for (stmt = mpl->model; stmt != NULL; stmt = stmt->next) { switch (stmt->type) { case A_SET: /* model set */ xassert(stmt->u.set->array == NULL); stmt->u.set->array = create_array(mpl, A_ELEMSET, stmt->u.set->dim); break; case A_PARAMETER: /* model parameter */ xassert(stmt->u.par->array == NULL); switch (stmt->u.par->type) { case A_NUMERIC: case A_INTEGER: case A_BINARY: stmt->u.par->array = create_array(mpl, A_NUMERIC, stmt->u.par->dim); break; case A_SYMBOLIC: stmt->u.par->array = create_array(mpl, A_SYMBOLIC, stmt->u.par->dim); break; default: xassert(stmt != stmt); } break; case A_VARIABLE: /* model variable */ xassert(stmt->u.var->array == NULL); stmt->u.var->array = create_array(mpl, A_ELEMVAR, stmt->u.var->dim); break; case A_CONSTRAINT: /* model constraint/objective */ xassert(stmt->u.con->array == NULL); stmt->u.con->array = create_array(mpl, A_ELEMCON, stmt->u.con->dim); break; #if 1 /* 11/II-2008 */ case A_TABLE: #endif case A_SOLVE: case A_CHECK: case A_DISPLAY: case A_PRINTF: case A_FOR: /* functional statements have no content array */ break; default: xassert(stmt != stmt); } } return; } /*---------------------------------------------------------------------- -- generate_model - generate model. -- -- This routine executes the model statements which precede the solve -- statement. */ void generate_model(MPL *mpl) { STATEMENT *stmt; xassert(!mpl->flag_p); for (stmt = mpl->model; stmt != NULL; stmt = stmt->next) { execute_statement(mpl, stmt); if (mpl->stmt->type == A_SOLVE) break; } mpl->stmt = stmt; return; } /*---------------------------------------------------------------------- -- build_problem - build problem instance. -- -- This routine builds lists of rows and columns for problem instance, -- which corresponds to the generated model. */ void build_problem(MPL *mpl) { STATEMENT *stmt; MEMBER *memb; VARIABLE *v; CONSTRAINT *c; FORMULA *t; int i, j; xassert(mpl->m == 0); xassert(mpl->n == 0); xassert(mpl->row == NULL); xassert(mpl->col == NULL); /* check that all elemental variables has zero column numbers */ for (stmt = mpl->model; stmt != NULL; stmt = stmt->next) { if (stmt->type == A_VARIABLE) { v = stmt->u.var; for (memb = v->array->head; memb != NULL; memb = memb->next) xassert(memb->value.var->j == 0); } } /* assign row numbers to elemental constraints and objectives */ for (stmt = mpl->model; stmt != NULL; stmt = stmt->next) { if (stmt->type == A_CONSTRAINT) { c = stmt->u.con; for (memb = c->array->head; memb != NULL; memb = memb->next) { xassert(memb->value.con->i == 0); memb->value.con->i = ++mpl->m; /* walk through linear form and mark elemental variables, which are referenced at least once */ for (t = memb->value.con->form; t != NULL; t = t->next) { xassert(t->var != NULL); t->var->memb->value.var->j = -1; } } } } /* assign column numbers to marked elemental variables */ for (stmt = mpl->model; stmt != NULL; stmt = stmt->next) { if (stmt->type == A_VARIABLE) { v = stmt->u.var; for (memb = v->array->head; memb != NULL; memb = memb->next) if (memb->value.var->j != 0) memb->value.var->j = ++mpl->n; } } /* build list of rows */ mpl->row = xcalloc(1+mpl->m, sizeof(ELEMCON *)); for (i = 1; i <= mpl->m; i++) mpl->row[i] = NULL; for (stmt = mpl->model; stmt != NULL; stmt = stmt->next) { if (stmt->type == A_CONSTRAINT) { c = stmt->u.con; for (memb = c->array->head; memb != NULL; memb = memb->next) { i = memb->value.con->i; xassert(1 <= i && i <= mpl->m); xassert(mpl->row[i] == NULL); mpl->row[i] = memb->value.con; } } } for (i = 1; i <= mpl->m; i++) xassert(mpl->row[i] != NULL); /* build list of columns */ mpl->col = xcalloc(1+mpl->n, sizeof(ELEMVAR *)); for (j = 1; j <= mpl->n; j++) mpl->col[j] = NULL; for (stmt = mpl->model; stmt != NULL; stmt = stmt->next) { if (stmt->type == A_VARIABLE) { v = stmt->u.var; for (memb = v->array->head; memb != NULL; memb = memb->next) { j = memb->value.var->j; if (j == 0) continue; xassert(1 <= j && j <= mpl->n); xassert(mpl->col[j] == NULL); mpl->col[j] = memb->value.var; } } } for (j = 1; j <= mpl->n; j++) xassert(mpl->col[j] != NULL); return; } /*---------------------------------------------------------------------- -- postsolve_model - postsolve model. -- -- This routine executes the model statements which follow the solve -- statement. */ void postsolve_model(MPL *mpl) { STATEMENT *stmt; xassert(!mpl->flag_p); mpl->flag_p = 1; for (stmt = mpl->stmt; stmt != NULL; stmt = stmt->next) execute_statement(mpl, stmt); mpl->stmt = NULL; return; } /*---------------------------------------------------------------------- -- clean_model - clean model content. -- -- This routine cleans the model content that assumes deleting all stuff -- dynamically allocated on generating/postsolving phase. -- -- Actually cleaning model content is not needed. This function is used -- mainly to be sure that there were no logical errors on using dynamic -- memory pools during the generation phase. -- -- NOTE: This routine must not be called if any errors were detected on -- the generation phase. */ void clean_model(MPL *mpl) { STATEMENT *stmt; for (stmt = mpl->model; stmt != NULL; stmt = stmt->next) clean_statement(mpl, stmt); /* check that all atoms have been returned to their pools */ if (dmp_in_use(mpl->strings) != 0) error(mpl, "internal logic error: %d string segment(s) were lo" "st", dmp_in_use(mpl->strings)); if (dmp_in_use(mpl->symbols) != 0) error(mpl, "internal logic error: %d symbol(s) were lost", dmp_in_use(mpl->symbols)); if (dmp_in_use(mpl->tuples) != 0) error(mpl, "internal logic error: %d n-tuple component(s) were" " lost", dmp_in_use(mpl->tuples)); if (dmp_in_use(mpl->arrays) != 0) error(mpl, "internal logic error: %d array(s) were lost", dmp_in_use(mpl->arrays)); if (dmp_in_use(mpl->members) != 0) error(mpl, "internal logic error: %d array member(s) were lost" , dmp_in_use(mpl->members)); if (dmp_in_use(mpl->elemvars) != 0) error(mpl, "internal logic error: %d elemental variable(s) wer" "e lost", dmp_in_use(mpl->elemvars)); if (dmp_in_use(mpl->formulae) != 0) error(mpl, "internal logic error: %d linear term(s) were lost", dmp_in_use(mpl->formulae)); if (dmp_in_use(mpl->elemcons) != 0) error(mpl, "internal logic error: %d elemental constraint(s) w" "ere lost", dmp_in_use(mpl->elemcons)); return; } /**********************************************************************/ /* * * INPUT/OUTPUT * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- open_input - open input text file. -- -- This routine opens the input text file for scanning. */ void open_input(MPL *mpl, char *file) { mpl->line = 0; mpl->c = '\n'; mpl->token = 0; mpl->imlen = 0; mpl->image[0] = '\0'; mpl->value = 0.0; mpl->b_token = T_EOF; mpl->b_imlen = 0; mpl->b_image[0] = '\0'; mpl->b_value = 0.0; mpl->f_dots = 0; mpl->f_scan = 0; mpl->f_token = 0; mpl->f_imlen = 0; mpl->f_image[0] = '\0'; mpl->f_value = 0.0; memset(mpl->context, ' ', CONTEXT_SIZE); mpl->c_ptr = 0; xassert(mpl->in_fp == NULL); mpl->in_fp = xfopen(file, "r"); if (mpl->in_fp == NULL) error(mpl, "unable to open %s - %s", file, xerrmsg()); mpl->in_file = file; /* scan the very first character */ get_char(mpl); /* scan the very first token */ get_token(mpl); return; } /*---------------------------------------------------------------------- -- read_char - read next character from input text file. -- -- This routine returns a next ASCII character read from the input text -- file. If the end of file has been reached, EOF is returned. */ int read_char(MPL *mpl) { int c; xassert(mpl->in_fp != NULL); c = xfgetc(mpl->in_fp); if (c < 0) { if (xferror(mpl->in_fp)) error(mpl, "read error on %s - %s", mpl->in_file, xerrmsg()); c = EOF; } return c; } /*---------------------------------------------------------------------- -- close_input - close input text file. -- -- This routine closes the input text file. */ void close_input(MPL *mpl) { xassert(mpl->in_fp != NULL); xfclose(mpl->in_fp); mpl->in_fp = NULL; mpl->in_file = NULL; return; } /*---------------------------------------------------------------------- -- open_output - open output text file. -- -- This routine opens the output text file for writing data produced by -- display and printf statements. */ void open_output(MPL *mpl, char *file) { xassert(mpl->out_fp == NULL); if (file == NULL) { file = ""; mpl->out_fp = (void *)stdout; } else { mpl->out_fp = xfopen(file, "w"); if (mpl->out_fp == NULL) error(mpl, "unable to create %s - %s", file, xerrmsg()); } mpl->out_file = xmalloc(strlen(file)+1); strcpy(mpl->out_file, file); return; } /*---------------------------------------------------------------------- -- write_char - write next character to output text file. -- -- This routine writes an ASCII character to the output text file. */ void write_char(MPL *mpl, int c) { xassert(mpl->out_fp != NULL); if (mpl->out_fp == (void *)stdout) xprintf("%c", c); else xfprintf(mpl->out_fp, "%c", c); return; } /*---------------------------------------------------------------------- -- write_text - format and write text to output text file. -- -- This routine formats a text using the format control string and then -- writes this text to the output text file. */ void write_text(MPL *mpl, char *fmt, ...) { va_list arg; char buf[OUTBUF_SIZE], *c; va_start(arg, fmt); vsprintf(buf, fmt, arg); xassert(strlen(buf) < sizeof(buf)); va_end(arg); for (c = buf; *c != '\0'; c++) write_char(mpl, *c); return; } /*---------------------------------------------------------------------- -- flush_output - finalize writing data to output text file. -- -- This routine finalizes writing data to the output text file. */ void flush_output(MPL *mpl) { xassert(mpl->out_fp != NULL); if (mpl->out_fp != (void *)stdout) { xfflush(mpl->out_fp); if (xferror(mpl->out_fp)) error(mpl, "write error on %s - %s", mpl->out_file, xerrmsg()); } return; } /**********************************************************************/ /* * * SOLVER INTERFACE * * */ /**********************************************************************/ /*---------------------------------------------------------------------- -- error - print error message and terminate model processing. -- -- This routine formats and prints an error message and then terminates -- model processing. */ void error(MPL *mpl, char *fmt, ...) { va_list arg; char msg[4095+1]; va_start(arg, fmt); vsprintf(msg, fmt, arg); xassert(strlen(msg) < sizeof(msg)); va_end(arg); switch (mpl->phase) { case 1: case 2: /* translation phase */ xprintf("%s:%d: %s\n", mpl->in_file == NULL ? "(unknown)" : mpl->in_file, mpl->line, msg); print_context(mpl); break; case 3: /* generation/postsolve phase */ xprintf("%s:%d: %s\n", mpl->mod_file == NULL ? "(unknown)" : mpl->mod_file, mpl->stmt == NULL ? 0 : mpl->stmt->line, msg); break; default: xassert(mpl != mpl); } mpl->phase = 4; longjmp(mpl->jump, 1); /* no return */ } /*---------------------------------------------------------------------- -- warning - print warning message and continue model processing. -- -- This routine formats and prints a warning message and returns to the -- calling program. */ void warning(MPL *mpl, char *fmt, ...) { va_list arg; char msg[4095+1]; va_start(arg, fmt); vsprintf(msg, fmt, arg); xassert(strlen(msg) < sizeof(msg)); va_end(arg); switch (mpl->phase) { case 1: case 2: /* translation phase */ xprintf("%s:%d: warning: %s\n", mpl->in_file == NULL ? "(unknown)" : mpl->in_file, mpl->line, msg); break; case 3: /* generation/postsolve phase */ xprintf("%s:%d: warning: %s\n", mpl->mod_file == NULL ? "(unknown)" : mpl->mod_file, mpl->stmt == NULL ? 0 : mpl->stmt->line, msg); break; default: xassert(mpl != mpl); } return; } /*---------------------------------------------------------------------- -- mpl_initialize - create and initialize translator database. -- -- *Synopsis* -- -- #include "glpmpl.h" -- MPL *mpl_initialize(void); -- -- *Description* -- -- The routine mpl_initialize creates and initializes the database used -- by the GNU MathProg translator. -- -- *Returns* -- -- The routine returns a pointer to the database created. */ MPL *mpl_initialize(void) { MPL *mpl; mpl = xmalloc(sizeof(MPL)); /* scanning segment */ mpl->line = 0; mpl->c = 0; mpl->token = 0; mpl->imlen = 0; mpl->image = xcalloc(MAX_LENGTH+1, sizeof(char)); mpl->image[0] = '\0'; mpl->value = 0.0; mpl->b_token = 0; mpl->b_imlen = 0; mpl->b_image = xcalloc(MAX_LENGTH+1, sizeof(char)); mpl->b_image[0] = '\0'; mpl->b_value = 0.0; mpl->f_dots = 0; mpl->f_scan = 0; mpl->f_token = 0; mpl->f_imlen = 0; mpl->f_image = xcalloc(MAX_LENGTH+1, sizeof(char)); mpl->f_image[0] = '\0'; mpl->f_value = 0.0; mpl->context = xcalloc(CONTEXT_SIZE, sizeof(char)); memset(mpl->context, ' ', CONTEXT_SIZE); mpl->c_ptr = 0; mpl->flag_d = 0; /* translating segment */ mpl->pool = dmp_create_poolx(0); mpl->tree = avl_create_tree(avl_strcmp, NULL); mpl->model = NULL; mpl->flag_x = 0; mpl->as_within = 0; mpl->as_in = 0; mpl->as_binary = 0; mpl->flag_s = 0; /* common segment */ mpl->strings = dmp_create_poolx(sizeof(STRING)); mpl->symbols = dmp_create_poolx(sizeof(SYMBOL)); mpl->tuples = dmp_create_poolx(sizeof(TUPLE)); mpl->arrays = dmp_create_poolx(sizeof(ARRAY)); mpl->members = dmp_create_poolx(sizeof(MEMBER)); mpl->elemvars = dmp_create_poolx(sizeof(ELEMVAR)); mpl->formulae = dmp_create_poolx(sizeof(FORMULA)); mpl->elemcons = dmp_create_poolx(sizeof(ELEMCON)); mpl->a_list = NULL; mpl->sym_buf = xcalloc(255+1, sizeof(char)); mpl->sym_buf[0] = '\0'; mpl->tup_buf = xcalloc(255+1, sizeof(char)); mpl->tup_buf[0] = '\0'; /* generating/postsolving segment */ mpl->rand = rng_create_rand(); mpl->flag_p = 0; mpl->stmt = NULL; #if 1 /* 11/II-2008 */ mpl->dca = NULL; #endif mpl->m = 0; mpl->n = 0; mpl->row = NULL; mpl->col = NULL; /* input/output segment */ mpl->in_fp = NULL; mpl->in_file = NULL; mpl->out_fp = NULL; mpl->out_file = NULL; mpl->prt_fp = NULL; mpl->prt_file = NULL; /* solver interface segment */ if (setjmp(mpl->jump)) xassert(mpl != mpl); mpl->phase = 0; mpl->mod_file = NULL; mpl->mpl_buf = xcalloc(255+1, sizeof(char)); mpl->mpl_buf[0] = '\0'; return mpl; } /*---------------------------------------------------------------------- -- mpl_read_model - read model section and optional data section. -- -- *Synopsis* -- -- #include "glpmpl.h" -- int mpl_read_model(MPL *mpl, char *file, int skip_data); -- -- *Description* -- -- The routine mpl_read_model reads model section and optionally data -- section, which may follow the model section, from the text file, -- whose name is the character string file, performs translating model -- statements and data blocks, and stores all the information in the -- translator database. -- -- The parameter skip_data is a flag. If the input file contains the -- data section and this flag is set, the data section is not read as -- if there were no data section and a warning message is issued. This -- allows reading the data section from another input file. -- -- This routine should be called once after the routine mpl_initialize -- and before other API routines. -- -- *Returns* -- -- The routine mpl_read_model returns one the following codes: -- -- 1 - translation successful. The input text file contains only model -- section. In this case the calling program may call the routine -- mpl_read_data to read data section from another file. -- 2 - translation successful. The input text file contains both model -- and data section. -- 4 - processing failed due to some errors. In this case the calling -- program should call the routine mpl_terminate to terminate model -- processing. */ int mpl_read_model(MPL *mpl, char *file, int skip_data) { if (mpl->phase != 0) xfault("mpl_read_model: invalid call sequence\n"); if (file == NULL) xfault("mpl_read_model: no input filename specified\n"); /* set up error handler */ if (setjmp(mpl->jump)) goto done; /* translate model section */ mpl->phase = 1; xprintf("Reading model section from %s...\n", file); open_input(mpl, file); model_section(mpl); if (mpl->model == NULL) error(mpl, "empty model section not allowed"); /* save name of the input text file containing model section for error diagnostics during the generation phase */ mpl->mod_file = xcalloc(strlen(file)+1, sizeof(char)); strcpy(mpl->mod_file, mpl->in_file); /* allocate content arrays for all model objects */ alloc_content(mpl); /* optional data section may begin with the keyword 'data' */ if (is_keyword(mpl, "data")) { if (skip_data) { warning(mpl, "data section ignored"); goto skip; } mpl->flag_d = 1; get_token(mpl /* data */); if (mpl->token != T_SEMICOLON) error(mpl, "semicolon missing where expected"); get_token(mpl /* ; */); /* translate data section */ mpl->phase = 2; xprintf("Reading data section from %s...\n", file); data_section(mpl); } /* process end statement */ end_statement(mpl); skip: xprintf("%d line%s were read\n", mpl->line, mpl->line == 1 ? "" : "s"); close_input(mpl); done: /* return to the calling program */ return mpl->phase; } /*---------------------------------------------------------------------- -- mpl_read_data - read data section. -- -- *Synopsis* -- -- #include "glpmpl.h" -- int mpl_read_data(MPL *mpl, char *file); -- -- *Description* -- -- The routine mpl_read_data reads data section from the text file, -- whose name is the character string file, performs translating data -- blocks, and stores the data read in the translator database. -- -- If this routine is used, it should be called once after the routine -- mpl_read_model and if the latter returned the code 1. -- -- *Returns* -- -- The routine mpl_read_data returns one of the following codes: -- -- 2 - data section has been successfully processed. -- 4 - processing failed due to some errors. In this case the calling -- program should call the routine mpl_terminate to terminate model -- processing. */ int mpl_read_data(MPL *mpl, char *file) #if 0 /* 02/X-2008 */ { if (mpl->phase != 1) #else { if (!(mpl->phase == 1 || mpl->phase == 2)) #endif xfault("mpl_read_data: invalid call sequence\n"); if (file == NULL) xfault("mpl_read_data: no input filename specified\n"); /* set up error handler */ if (setjmp(mpl->jump)) goto done; /* process data section */ mpl->phase = 2; xprintf("Reading data section from %s...\n", file); mpl->flag_d = 1; open_input(mpl, file); /* in this case the keyword 'data' is optional */ if (is_literal(mpl, "data")) { get_token(mpl /* data */); if (mpl->token != T_SEMICOLON) error(mpl, "semicolon missing where expected"); get_token(mpl /* ; */); } data_section(mpl); /* process end statement */ end_statement(mpl); xprintf("%d line%s were read\n", mpl->line, mpl->line == 1 ? "" : "s"); close_input(mpl); done: /* return to the calling program */ return mpl->phase; } /*---------------------------------------------------------------------- -- mpl_generate - generate model. -- -- *Synopsis* -- -- #include "glpmpl.h" -- int mpl_generate(MPL *mpl, char *file); -- -- *Description* -- -- The routine mpl_generate generates the model using its description -- stored in the translator database. This phase means generating all -- variables, constraints, and objectives, executing check and display -- statements, which precede the solve statement (if it is presented), -- and building the problem instance. -- -- The character string file specifies the name of output text file, to -- which output produced by display statements should be written. It is -- allowed to specify NULL, in which case the output goes to stdout via -- the routine print. -- -- This routine should be called once after the routine mpl_read_model -- or mpl_read_data and if one of the latters returned the code 2. -- -- *Returns* -- -- The routine mpl_generate returns one of the following codes: -- -- 3 - model has been successfully generated. In this case the calling -- program may call other api routines to obtain components of the -- problem instance from the translator database. -- 4 - processing failed due to some errors. In this case the calling -- program should call the routine mpl_terminate to terminate model -- processing. */ int mpl_generate(MPL *mpl, char *file) { if (!(mpl->phase == 1 || mpl->phase == 2)) xfault("mpl_generate: invalid call sequence\n"); /* set up error handler */ if (setjmp(mpl->jump)) goto done; /* generate model */ mpl->phase = 3; open_output(mpl, file); generate_model(mpl); flush_output(mpl); /* build problem instance */ build_problem(mpl); /* generation phase has been finished */ xprintf("Model has been successfully generated\n"); done: /* return to the calling program */ return mpl->phase; } /*---------------------------------------------------------------------- -- mpl_get_prob_name - obtain problem (model) name. -- -- *Synopsis* -- -- #include "glpmpl.h" -- char *mpl_get_prob_name(MPL *mpl); -- -- *Returns* -- -- The routine mpl_get_prob_name returns a pointer to internal buffer, -- which contains symbolic name of the problem (model). -- -- *Note* -- -- Currently MathProg has no feature to assign a symbolic name to the -- model. Therefore the routine mpl_get_prob_name tries to construct -- such name using the name of input text file containing model section, -- although this is not a good idea (due to portability problems). */ char *mpl_get_prob_name(MPL *mpl) { char *name = mpl->mpl_buf; char *file = mpl->mod_file; int k; if (mpl->phase != 3) xfault("mpl_get_prob_name: invalid call sequence\n"); for (;;) { if (strchr(file, '/') != NULL) file = strchr(file, '/') + 1; else if (strchr(file, '\\') != NULL) file = strchr(file, '\\') + 1; else if (strchr(file, ':') != NULL) file = strchr(file, ':') + 1; else break; } for (k = 0; ; k++) { if (k == 255) break; if (!(isalnum((unsigned char)*file) || *file == '_')) break; name[k] = *file++; } if (k == 0) strcpy(name, "Unknown"); else name[k] = '\0'; xassert(strlen(name) <= 255); return name; } /*---------------------------------------------------------------------- -- mpl_get_num_rows - determine number of rows. -- -- *Synopsis* -- -- #include "glpmpl.h" -- int mpl_get_num_rows(MPL *mpl); -- -- *Returns* -- -- The routine mpl_get_num_rows returns total number of rows in the -- problem, where each row is an individual constraint or objective. */ int mpl_get_num_rows(MPL *mpl) { if (mpl->phase != 3) xfault("mpl_get_num_rows: invalid call sequence\n"); return mpl->m; } /*---------------------------------------------------------------------- -- mpl_get_num_cols - determine number of columns. -- -- *Synopsis* -- -- #include "glpmpl.h" -- int mpl_get_num_cols(MPL *mpl); -- -- *Returns* -- -- The routine mpl_get_num_cols returns total number of columns in the -- problem, where each column is an individual variable. */ int mpl_get_num_cols(MPL *mpl) { if (mpl->phase != 3) xfault("mpl_get_num_cols: invalid call sequence\n"); return mpl->n; } /*---------------------------------------------------------------------- -- mpl_get_row_name - obtain row name. -- -- *Synopsis* -- -- #include "glpmpl.h" -- char *mpl_get_row_name(MPL *mpl, int i); -- -- *Returns* -- -- The routine mpl_get_row_name returns a pointer to internal buffer, -- which contains symbolic name of i-th row of the problem. */ char *mpl_get_row_name(MPL *mpl, int i) { char *name = mpl->mpl_buf, *t; int len; if (mpl->phase != 3) xfault("mpl_get_row_name: invalid call sequence\n"); if (!(1 <= i && i <= mpl->m)) xfault("mpl_get_row_name: i = %d; row number out of range\n", i); strcpy(name, mpl->row[i]->con->name); len = strlen(name); xassert(len <= 255); t = format_tuple(mpl, '[', mpl->row[i]->memb->tuple); while (*t) { if (len == 255) break; name[len++] = *t++; } name[len] = '\0'; if (len == 255) strcpy(name+252, "..."); xassert(strlen(name) <= 255); return name; } /*---------------------------------------------------------------------- -- mpl_get_row_kind - determine row kind. -- -- *Synopsis* -- -- #include "glpmpl.h" -- int mpl_get_row_kind(MPL *mpl, int i); -- -- *Returns* -- -- The routine mpl_get_row_kind returns the kind of i-th row, which can -- be one of the following: -- -- MPL_ST - non-free (constraint) row; -- MPL_MIN - free (objective) row to be minimized; -- MPL_MAX - free (objective) row to be maximized. */ int mpl_get_row_kind(MPL *mpl, int i) { int kind; if (mpl->phase != 3) xfault("mpl_get_row_kind: invalid call sequence\n"); if (!(1 <= i && i <= mpl->m)) xfault("mpl_get_row_kind: i = %d; row number out of range\n", i); switch (mpl->row[i]->con->type) { case A_CONSTRAINT: kind = MPL_ST; break; case A_MINIMIZE: kind = MPL_MIN; break; case A_MAXIMIZE: kind = MPL_MAX; break; default: xassert(mpl != mpl); } return kind; } /*---------------------------------------------------------------------- -- mpl_get_row_bnds - obtain row bounds. -- -- *Synopsis* -- -- #include "glpmpl.h" -- int mpl_get_row_bnds(MPL *mpl, int i, double *lb, double *ub); -- -- *Description* -- -- The routine mpl_get_row_bnds stores lower and upper bounds of i-th -- row of the problem to the locations, which the parameters lb and ub -- point to, respectively. Besides the routine returns the type of the -- i-th row. -- -- If some of the parameters lb and ub is NULL, the corresponding bound -- value is not stored. -- -- Types and bounds have the following meaning: -- -- Type Bounds Note -- ----------------------------------------------------------- -- MPL_FR -inf < f(x) < +inf Free linear form -- MPL_LO lb <= f(x) < +inf Inequality f(x) >= lb -- MPL_UP -inf < f(x) <= ub Inequality f(x) <= ub -- MPL_DB lb <= f(x) <= ub Inequality lb <= f(x) <= ub -- MPL_FX f(x) = lb Equality f(x) = lb -- -- where f(x) is the corresponding linear form of the i-th row. -- -- If the row has no lower bound, *lb is set to zero; if the row has -- no upper bound, *ub is set to zero; and if the row is of fixed type, -- both *lb and *ub are set to the same value. -- -- *Returns* -- -- The routine returns the type of the i-th row as it is stated in the -- table above. */ int mpl_get_row_bnds(MPL *mpl, int i, double *_lb, double *_ub) { ELEMCON *con; int type; double lb, ub; if (mpl->phase != 3) xfault("mpl_get_row_bnds: invalid call sequence\n"); if (!(1 <= i && i <= mpl->m)) xfault("mpl_get_row_bnds: i = %d; row number out of range\n", i); con = mpl->row[i]; #if 0 /* 21/VII-2006 */ if (con->con->lbnd == NULL && con->con->ubnd == NULL) type = MPL_FR, lb = ub = 0.0; else if (con->con->ubnd == NULL) type = MPL_LO, lb = con->lbnd, ub = 0.0; else if (con->con->lbnd == NULL) type = MPL_UP, lb = 0.0, ub = con->ubnd; else if (con->con->lbnd != con->con->ubnd) type = MPL_DB, lb = con->lbnd, ub = con->ubnd; else type = MPL_FX, lb = ub = con->lbnd; #else lb = (con->con->lbnd == NULL ? -DBL_MAX : con->lbnd); ub = (con->con->ubnd == NULL ? +DBL_MAX : con->ubnd); if (lb == -DBL_MAX && ub == +DBL_MAX) type = MPL_FR, lb = ub = 0.0; else if (ub == +DBL_MAX) type = MPL_LO, ub = 0.0; else if (lb == -DBL_MAX) type = MPL_UP, lb = 0.0; else if (con->con->lbnd != con->con->ubnd) type = MPL_DB; else type = MPL_FX; #endif if (_lb != NULL) *_lb = lb; if (_ub != NULL) *_ub = ub; return type; } /*---------------------------------------------------------------------- -- mpl_get_mat_row - obtain row of the constraint matrix. -- -- *Synopsis* -- -- #include "glpmpl.h" -- int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[]); -- -- *Description* -- -- The routine mpl_get_mat_row stores column indices and numeric values -- of constraint coefficients for the i-th row to locations ndx[1], ..., -- ndx[len] and val[1], ..., val[len], respectively, where 0 <= len <= n -- is number of (structural) non-zero constraint coefficients, and n is -- number of columns in the problem. -- -- If the parameter ndx is NULL, column indices are not stored. If the -- parameter val is NULL, numeric values are not stored. -- -- Note that free rows may have constant terms, which are not part of -- the constraint matrix and therefore not reported by this routine. The -- constant term of a particular row can be obtained, if necessary, via -- the routine mpl_get_row_c0. -- -- *Returns* -- -- The routine mpl_get_mat_row returns len, which is length of i-th row -- of the constraint matrix (i.e. number of non-zero coefficients). */ int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[]) { FORMULA *term; int len = 0; if (mpl->phase != 3) xfault("mpl_get_mat_row: invalid call sequence\n"); if (!(1 <= i && i <= mpl->m)) xfault("mpl_get_mat_row: i = %d; row number out of range\n", i); for (term = mpl->row[i]->form; term != NULL; term = term->next) { xassert(term->var != NULL); len++; xassert(len <= mpl->n); if (ndx != NULL) ndx[len] = term->var->j; if (val != NULL) val[len] = term->coef; } return len; } /*---------------------------------------------------------------------- -- mpl_get_row_c0 - obtain constant term of free row. -- -- *Synopsis* -- -- #include "glpmpl.h" -- double mpl_get_row_c0(MPL *mpl, int i); -- -- *Returns* -- -- The routine mpl_get_row_c0 returns numeric value of constant term of -- i-th row. -- -- Note that only free rows may have non-zero constant terms. Therefore -- if i-th row is not free, the routine returns zero. */ double mpl_get_row_c0(MPL *mpl, int i) { ELEMCON *con; double c0; if (mpl->phase != 3) xfault("mpl_get_row_c0: invalid call sequence\n"); if (!(1 <= i && i <= mpl->m)) xfault("mpl_get_row_c0: i = %d; row number out of range\n", i); con = mpl->row[i]; if (con->con->lbnd == NULL && con->con->ubnd == NULL) c0 = - con->lbnd; else c0 = 0.0; return c0; } /*---------------------------------------------------------------------- -- mpl_get_col_name - obtain column name. -- -- *Synopsis* -- -- #include "glpmpl.h" -- char *mpl_get_col_name(MPL *mpl, int j); -- -- *Returns* -- -- The routine mpl_get_col_name returns a pointer to internal buffer, -- which contains symbolic name of j-th column of the problem. */ char *mpl_get_col_name(MPL *mpl, int j) { char *name = mpl->mpl_buf, *t; int len; if (mpl->phase != 3) xfault("mpl_get_col_name: invalid call sequence\n"); if (!(1 <= j && j <= mpl->n)) xfault("mpl_get_col_name: j = %d; column number out of range\n" , j); strcpy(name, mpl->col[j]->var->name); len = strlen(name); xassert(len <= 255); t = format_tuple(mpl, '[', mpl->col[j]->memb->tuple); while (*t) { if (len == 255) break; name[len++] = *t++; } name[len] = '\0'; if (len == 255) strcpy(name+252, "..."); xassert(strlen(name) <= 255); return name; } /*---------------------------------------------------------------------- -- mpl_get_col_kind - determine column kind. -- -- *Synopsis* -- -- #include "glpmpl.h" -- int mpl_get_col_kind(MPL *mpl, int j); -- -- *Returns* -- -- The routine mpl_get_col_kind returns the kind of j-th column, which -- can be one of the following: -- -- MPL_NUM - continuous variable; -- MPL_INT - integer variable; -- MPL_BIN - binary variable. -- -- Note that column kinds are defined independently on type and bounds -- (reported by the routine mpl_get_col_bnds) of corresponding columns. -- This means, in particular, that bounds of an integer column may be -- fractional, or a binary column may have lower and upper bounds that -- are not 0 and 1 (or it may have no lower/upper bound at all). */ int mpl_get_col_kind(MPL *mpl, int j) { int kind; if (mpl->phase != 3) xfault("mpl_get_col_kind: invalid call sequence\n"); if (!(1 <= j && j <= mpl->n)) xfault("mpl_get_col_kind: j = %d; column number out of range\n" , j); switch (mpl->col[j]->var->type) { case A_NUMERIC: kind = MPL_NUM; break; case A_INTEGER: kind = MPL_INT; break; case A_BINARY: kind = MPL_BIN; break; default: xassert(mpl != mpl); } return kind; } /*---------------------------------------------------------------------- -- mpl_get_col_bnds - obtain column bounds. -- -- *Synopsis* -- -- #include "glpmpl.h" -- int mpl_get_col_bnds(MPL *mpl, int j, double *lb, double *ub); -- -- *Description* -- -- The routine mpl_get_col_bnds stores lower and upper bound of j-th -- column of the problem to the locations, which the parameters lb and -- ub point to, respectively. Besides the routine returns the type of -- the j-th column. -- -- If some of the parameters lb and ub is NULL, the corresponding bound -- value is not stored. -- -- Types and bounds have the following meaning: -- -- Type Bounds Note -- ------------------------------------------------------ -- MPL_FR -inf < x < +inf Free (unbounded) variable -- MPL_LO lb <= x < +inf Variable with lower bound -- MPL_UP -inf < x <= ub Variable with upper bound -- MPL_DB lb <= x <= ub Double-bounded variable -- MPL_FX x = lb Fixed variable -- -- where x is individual variable corresponding to the j-th column. -- -- If the column has no lower bound, *lb is set to zero; if the column -- has no upper bound, *ub is set to zero; and if the column is of fixed -- type, both *lb and *ub are set to the same value. -- -- *Returns* -- -- The routine returns the type of the j-th column as it is stated in -- the table above. */ int mpl_get_col_bnds(MPL *mpl, int j, double *_lb, double *_ub) { ELEMVAR *var; int type; double lb, ub; if (mpl->phase != 3) xfault("mpl_get_col_bnds: invalid call sequence\n"); if (!(1 <= j && j <= mpl->n)) xfault("mpl_get_col_bnds: j = %d; column number out of range\n" , j); var = mpl->col[j]; #if 0 /* 21/VII-2006 */ if (var->var->lbnd == NULL && var->var->ubnd == NULL) type = MPL_FR, lb = ub = 0.0; else if (var->var->ubnd == NULL) type = MPL_LO, lb = var->lbnd, ub = 0.0; else if (var->var->lbnd == NULL) type = MPL_UP, lb = 0.0, ub = var->ubnd; else if (var->var->lbnd != var->var->ubnd) type = MPL_DB, lb = var->lbnd, ub = var->ubnd; else type = MPL_FX, lb = ub = var->lbnd; #else lb = (var->var->lbnd == NULL ? -DBL_MAX : var->lbnd); ub = (var->var->ubnd == NULL ? +DBL_MAX : var->ubnd); if (lb == -DBL_MAX && ub == +DBL_MAX) type = MPL_FR, lb = ub = 0.0; else if (ub == +DBL_MAX) type = MPL_LO, ub = 0.0; else if (lb == -DBL_MAX) type = MPL_UP, lb = 0.0; else if (var->var->lbnd != var->var->ubnd) type = MPL_DB; else type = MPL_FX; #endif if (_lb != NULL) *_lb = lb; if (_ub != NULL) *_ub = ub; return type; } /*---------------------------------------------------------------------- -- mpl_has_solve_stmt - check if model has solve statement. -- -- *Synopsis* -- -- #include "glpmpl.h" -- int mpl_has_solve_stmt(MPL *mpl); -- -- *Returns* -- -- If the model has the solve statement, the routine returns non-zero, -- otherwise zero is returned. */ int mpl_has_solve_stmt(MPL *mpl) { if (mpl->phase != 3) xfault("mpl_has_solve_stmt: invalid call sequence\n"); return mpl->flag_s; } #if 1 /* 15/V-2010 */ void mpl_put_row_soln(MPL *mpl, int i, int stat, double prim, double dual) { /* store row (constraint/objective) solution components */ xassert(mpl->phase == 3); xassert(1 <= i && i <= mpl->m); mpl->row[i]->stat = stat; mpl->row[i]->prim = prim; mpl->row[i]->dual = dual; return; } #endif #if 1 /* 15/V-2010 */ void mpl_put_col_soln(MPL *mpl, int j, int stat, double prim, double dual) { /* store column (variable) solution components */ xassert(mpl->phase == 3); xassert(1 <= j && j <= mpl->n); mpl->col[j]->stat = stat; mpl->col[j]->prim = prim; mpl->col[j]->dual = dual; return; } #endif #if 0 /* 15/V-2010 */ /*---------------------------------------------------------------------- -- mpl_put_col_value - store column value. -- -- *Synopsis* -- -- #include "glpmpl.h" -- void mpl_put_col_value(MPL *mpl, int j, double val); -- -- *Description* -- -- The routine mpl_put_col_value stores numeric value of j-th column -- into the translator database. It is assumed that the column value is -- provided by the solver. */ void mpl_put_col_value(MPL *mpl, int j, double val) { if (mpl->phase != 3) xfault("mpl_put_col_value: invalid call sequence\n"); if (!(1 <= j && j <= mpl->n)) xfault( "mpl_put_col_value: j = %d; column number out of range\n", j); mpl->col[j]->prim = val; return; } #endif /*---------------------------------------------------------------------- -- mpl_postsolve - postsolve model. -- -- *Synopsis* -- -- #include "glpmpl.h" -- int mpl_postsolve(MPL *mpl); -- -- *Description* -- -- The routine mpl_postsolve performs postsolving of the model using -- its description stored in the translator database. This phase means -- executing statements, which follow the solve statement. -- -- If this routine is used, it should be called once after the routine -- mpl_generate and if the latter returned the code 3. -- -- *Returns* -- -- The routine mpl_postsolve returns one of the following codes: -- -- 3 - model has been successfully postsolved. -- 4 - processing failed due to some errors. In this case the calling -- program should call the routine mpl_terminate to terminate model -- processing. */ int mpl_postsolve(MPL *mpl) { if (!(mpl->phase == 3 && !mpl->flag_p)) xfault("mpl_postsolve: invalid call sequence\n"); /* set up error handler */ if (setjmp(mpl->jump)) goto done; /* perform postsolving */ postsolve_model(mpl); flush_output(mpl); /* postsolving phase has been finished */ xprintf("Model has been successfully processed\n"); done: /* return to the calling program */ return mpl->phase; } /*---------------------------------------------------------------------- -- mpl_terminate - free all resources used by translator. -- -- *Synopsis* -- -- #include "glpmpl.h" -- void mpl_terminate(MPL *mpl); -- -- *Description* -- -- The routine mpl_terminate frees all the resources used by the GNU -- MathProg translator. */ void mpl_terminate(MPL *mpl) { if (setjmp(mpl->jump)) xassert(mpl != mpl); switch (mpl->phase) { case 0: case 1: case 2: case 3: /* there were no errors; clean the model content */ clean_model(mpl); xassert(mpl->a_list == NULL); #if 1 /* 11/II-2008 */ xassert(mpl->dca == NULL); #endif break; case 4: /* model processing has been finished due to error; delete search trees, which may be created for some arrays */ { ARRAY *a; for (a = mpl->a_list; a != NULL; a = a->next) if (a->tree != NULL) avl_delete_tree(a->tree); } #if 1 /* 11/II-2008 */ free_dca(mpl); #endif break; default: xassert(mpl != mpl); } /* delete the translator database */ xfree(mpl->image); xfree(mpl->b_image); xfree(mpl->f_image); xfree(mpl->context); dmp_delete_pool(mpl->pool); avl_delete_tree(mpl->tree); dmp_delete_pool(mpl->strings); dmp_delete_pool(mpl->symbols); dmp_delete_pool(mpl->tuples); dmp_delete_pool(mpl->arrays); dmp_delete_pool(mpl->members); dmp_delete_pool(mpl->elemvars); dmp_delete_pool(mpl->formulae); dmp_delete_pool(mpl->elemcons); xfree(mpl->sym_buf); xfree(mpl->tup_buf); rng_delete_rand(mpl->rand); if (mpl->row != NULL) xfree(mpl->row); if (mpl->col != NULL) xfree(mpl->col); if (mpl->in_fp != NULL) xfclose(mpl->in_fp); if (mpl->out_fp != NULL && mpl->out_fp != (void *)stdout) xfclose(mpl->out_fp); if (mpl->out_file != NULL) xfree(mpl->out_file); if (mpl->prt_fp != NULL) xfclose(mpl->prt_fp); if (mpl->prt_file != NULL) xfree(mpl->prt_file); if (mpl->mod_file != NULL) xfree(mpl->mod_file); xfree(mpl->mpl_buf); xfree(mpl); return; } /* eof */ Rglpk/src/GLPK/glpapi01.c0000644000176000001440000014726112245352174014506 0ustar ripleyusers/* glpapi01.c (problem creating and modifying routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpios.h" /* CAUTION: DO NOT CHANGE THE LIMITS BELOW */ #define M_MAX 100000000 /* = 100*10^6 */ /* maximal number of rows in the problem object */ #define N_MAX 100000000 /* = 100*10^6 */ /* maximal number of columns in the problem object */ #define NNZ_MAX 500000000 /* = 500*10^6 */ /* maximal number of constraint coefficients in the problem object */ /*********************************************************************** * NAME * * glp_create_prob - create problem object * * SYNOPSIS * * glp_prob *glp_create_prob(void); * * DESCRIPTION * * The routine glp_create_prob creates a new problem object, which is * initially "empty", i.e. has no rows and columns. * * RETURNS * * The routine returns a pointer to the object created, which should be * used in any subsequent operations on this object. */ static void create_prob(glp_prob *lp) { lp->magic = GLP_PROB_MAGIC; lp->pool = dmp_create_pool(); #if 0 /* 17/XI-2009 */ lp->cps = xmalloc(sizeof(struct LPXCPS)); lpx_reset_parms(lp); #else lp->parms = NULL; #endif lp->tree = NULL; #if 0 lp->lwa = 0; lp->cwa = NULL; #endif /* LP/MIP data */ lp->name = NULL; lp->obj = NULL; lp->dir = GLP_MIN; lp->c0 = 0.0; lp->m_max = 100; lp->n_max = 200; lp->m = lp->n = 0; lp->nnz = 0; lp->row = xcalloc(1+lp->m_max, sizeof(GLPROW *)); lp->col = xcalloc(1+lp->n_max, sizeof(GLPCOL *)); lp->r_tree = lp->c_tree = NULL; /* basis factorization */ lp->valid = 0; lp->head = xcalloc(1+lp->m_max, sizeof(int)); lp->bfcp = NULL; lp->bfd = NULL; /* basic solution (LP) */ lp->pbs_stat = lp->dbs_stat = GLP_UNDEF; lp->obj_val = 0.0; lp->it_cnt = 0; lp->some = 0; /* interior-point solution (LP) */ lp->ipt_stat = GLP_UNDEF; lp->ipt_obj = 0.0; /* integer solution (MIP) */ lp->mip_stat = GLP_UNDEF; lp->mip_obj = 0.0; return; } glp_prob *glp_create_prob(void) { glp_prob *lp; lp = xmalloc(sizeof(glp_prob)); create_prob(lp); return lp; } /*********************************************************************** * NAME * * glp_set_prob_name - assign (change) problem name * * SYNOPSIS * * void glp_set_prob_name(glp_prob *lp, const char *name); * * DESCRIPTION * * The routine glp_set_prob_name assigns a given symbolic name (1 up to * 255 characters) to the specified problem object. * * If the parameter name is NULL or empty string, the routine erases an * existing symbolic name of the problem object. */ void glp_set_prob_name(glp_prob *lp, const char *name) { glp_tree *tree = lp->tree; if (tree != NULL && tree->reason != 0) xerror("glp_set_prob_name: operation not allowed\n"); if (lp->name != NULL) { dmp_free_atom(lp->pool, lp->name, strlen(lp->name)+1); lp->name = NULL; } if (!(name == NULL || name[0] == '\0')) { int k; for (k = 0; name[k] != '\0'; k++) { if (k == 256) xerror("glp_set_prob_name: problem name too long\n"); if (iscntrl((unsigned char)name[k])) xerror("glp_set_prob_name: problem name contains invalid" " character(s)\n"); } lp->name = dmp_get_atom(lp->pool, strlen(name)+1); strcpy(lp->name, name); } return; } /*********************************************************************** * NAME * * glp_set_obj_name - assign (change) objective function name * * SYNOPSIS * * void glp_set_obj_name(glp_prob *lp, const char *name); * * DESCRIPTION * * The routine glp_set_obj_name assigns a given symbolic name (1 up to * 255 characters) to the objective function of the specified problem * object. * * If the parameter name is NULL or empty string, the routine erases an * existing name of the objective function. */ void glp_set_obj_name(glp_prob *lp, const char *name) { glp_tree *tree = lp->tree; if (tree != NULL && tree->reason != 0) xerror("glp_set_obj_name: operation not allowed\n"); if (lp->obj != NULL) { dmp_free_atom(lp->pool, lp->obj, strlen(lp->obj)+1); lp->obj = NULL; } if (!(name == NULL || name[0] == '\0')) { int k; for (k = 0; name[k] != '\0'; k++) { if (k == 256) xerror("glp_set_obj_name: objective name too long\n"); if (iscntrl((unsigned char)name[k])) xerror("glp_set_obj_name: objective name contains invali" "d character(s)\n"); } lp->obj = dmp_get_atom(lp->pool, strlen(name)+1); strcpy(lp->obj, name); } return; } /*********************************************************************** * NAME * * glp_set_obj_dir - set (change) optimization direction flag * * SYNOPSIS * * void glp_set_obj_dir(glp_prob *lp, int dir); * * DESCRIPTION * * The routine glp_set_obj_dir sets (changes) optimization direction * flag (i.e. "sense" of the objective function) as specified by the * parameter dir: * * GLP_MIN - minimization; * GLP_MAX - maximization. */ void glp_set_obj_dir(glp_prob *lp, int dir) { glp_tree *tree = lp->tree; if (tree != NULL && tree->reason != 0) xerror("glp_set_obj_dir: operation not allowed\n"); if (!(dir == GLP_MIN || dir == GLP_MAX)) xerror("glp_set_obj_dir: dir = %d; invalid direction flag\n", dir); lp->dir = dir; return; } /*********************************************************************** * NAME * * glp_add_rows - add new rows to problem object * * SYNOPSIS * * int glp_add_rows(glp_prob *lp, int nrs); * * DESCRIPTION * * The routine glp_add_rows adds nrs rows (constraints) to the specified * problem object. New rows are always added to the end of the row list, * so the ordinal numbers of existing rows remain unchanged. * * Being added each new row is initially free (unbounded) and has empty * list of the constraint coefficients. * * RETURNS * * The routine glp_add_rows returns the ordinal number of the first new * row added to the problem object. */ int glp_add_rows(glp_prob *lp, int nrs) { glp_tree *tree = lp->tree; GLPROW *row; int m_new, i; /* determine new number of rows */ if (nrs < 1) xerror("glp_add_rows: nrs = %d; invalid number of rows\n", nrs); if (nrs > M_MAX - lp->m) xerror("glp_add_rows: nrs = %d; too many rows\n", nrs); m_new = lp->m + nrs; /* increase the room, if necessary */ if (lp->m_max < m_new) { GLPROW **save = lp->row; while (lp->m_max < m_new) { lp->m_max += lp->m_max; xassert(lp->m_max > 0); } lp->row = xcalloc(1+lp->m_max, sizeof(GLPROW *)); memcpy(&lp->row[1], &save[1], lp->m * sizeof(GLPROW *)); xfree(save); /* do not forget about the basis header */ xfree(lp->head); lp->head = xcalloc(1+lp->m_max, sizeof(int)); } /* add new rows to the end of the row list */ for (i = lp->m+1; i <= m_new; i++) { /* create row descriptor */ lp->row[i] = row = dmp_get_atom(lp->pool, sizeof(GLPROW)); row->i = i; row->name = NULL; row->node = NULL; #if 1 /* 20/IX-2008 */ row->level = 0; row->origin = 0; row->klass = 0; if (tree != NULL) { switch (tree->reason) { case 0: break; case GLP_IROWGEN: xassert(tree->curr != NULL); row->level = tree->curr->level; row->origin = GLP_RF_LAZY; break; case GLP_ICUTGEN: xassert(tree->curr != NULL); row->level = tree->curr->level; row->origin = GLP_RF_CUT; break; default: xassert(tree != tree); } } #endif row->type = GLP_FR; row->lb = row->ub = 0.0; row->ptr = NULL; row->rii = 1.0; row->stat = GLP_BS; #if 0 row->bind = -1; #else row->bind = 0; #endif row->prim = row->dual = 0.0; row->pval = row->dval = 0.0; row->mipx = 0.0; } /* set new number of rows */ lp->m = m_new; /* invalidate the basis factorization */ lp->valid = 0; #if 1 if (tree != NULL && tree->reason != 0) tree->reopt = 1; #endif /* return the ordinal number of the first row added */ return m_new - nrs + 1; } /*********************************************************************** * NAME * * glp_add_cols - add new columns to problem object * * SYNOPSIS * * int glp_add_cols(glp_prob *lp, int ncs); * * DESCRIPTION * * The routine glp_add_cols adds ncs columns (structural variables) to * the specified problem object. New columns are always added to the end * of the column list, so the ordinal numbers of existing columns remain * unchanged. * * Being added each new column is initially fixed at zero and has empty * list of the constraint coefficients. * * RETURNS * * The routine glp_add_cols returns the ordinal number of the first new * column added to the problem object. */ int glp_add_cols(glp_prob *lp, int ncs) { glp_tree *tree = lp->tree; GLPCOL *col; int n_new, j; if (tree != NULL && tree->reason != 0) xerror("glp_add_cols: operation not allowed\n"); /* determine new number of columns */ if (ncs < 1) xerror("glp_add_cols: ncs = %d; invalid number of columns\n", ncs); if (ncs > N_MAX - lp->n) xerror("glp_add_cols: ncs = %d; too many columns\n", ncs); n_new = lp->n + ncs; /* increase the room, if necessary */ if (lp->n_max < n_new) { GLPCOL **save = lp->col; while (lp->n_max < n_new) { lp->n_max += lp->n_max; xassert(lp->n_max > 0); } lp->col = xcalloc(1+lp->n_max, sizeof(GLPCOL *)); memcpy(&lp->col[1], &save[1], lp->n * sizeof(GLPCOL *)); xfree(save); } /* add new columns to the end of the column list */ for (j = lp->n+1; j <= n_new; j++) { /* create column descriptor */ lp->col[j] = col = dmp_get_atom(lp->pool, sizeof(GLPCOL)); col->j = j; col->name = NULL; col->node = NULL; col->kind = GLP_CV; col->type = GLP_FX; col->lb = col->ub = 0.0; col->coef = 0.0; col->ptr = NULL; col->sjj = 1.0; col->stat = GLP_NS; #if 0 col->bind = -1; #else col->bind = 0; /* the basis may remain valid */ #endif col->prim = col->dual = 0.0; col->pval = col->dval = 0.0; col->mipx = 0.0; } /* set new number of columns */ lp->n = n_new; /* return the ordinal number of the first column added */ return n_new - ncs + 1; } /*********************************************************************** * NAME * * glp_set_row_name - assign (change) row name * * SYNOPSIS * * void glp_set_row_name(glp_prob *lp, int i, const char *name); * * DESCRIPTION * * The routine glp_set_row_name assigns a given symbolic name (1 up to * 255 characters) to i-th row (auxiliary variable) of the specified * problem object. * * If the parameter name is NULL or empty string, the routine erases an * existing name of i-th row. */ void glp_set_row_name(glp_prob *lp, int i, const char *name) { glp_tree *tree = lp->tree; GLPROW *row; if (!(1 <= i && i <= lp->m)) xerror("glp_set_row_name: i = %d; row number out of range\n", i); row = lp->row[i]; if (tree != NULL && tree->reason != 0) { xassert(tree->curr != NULL); xassert(row->level == tree->curr->level); } if (row->name != NULL) { if (row->node != NULL) { xassert(lp->r_tree != NULL); avl_delete_node(lp->r_tree, row->node); row->node = NULL; } dmp_free_atom(lp->pool, row->name, strlen(row->name)+1); row->name = NULL; } if (!(name == NULL || name[0] == '\0')) { int k; for (k = 0; name[k] != '\0'; k++) { if (k == 256) xerror("glp_set_row_name: i = %d; row name too long\n", i); if (iscntrl((unsigned char)name[k])) xerror("glp_set_row_name: i = %d: row name contains inva" "lid character(s)\n", i); } row->name = dmp_get_atom(lp->pool, strlen(name)+1); strcpy(row->name, name); if (lp->r_tree != NULL) { xassert(row->node == NULL); row->node = avl_insert_node(lp->r_tree, row->name); avl_set_node_link(row->node, row); } } return; } /*********************************************************************** * NAME * * glp_set_col_name - assign (change) column name * * SYNOPSIS * * void glp_set_col_name(glp_prob *lp, int j, const char *name); * * DESCRIPTION * * The routine glp_set_col_name assigns a given symbolic name (1 up to * 255 characters) to j-th column (structural variable) of the specified * problem object. * * If the parameter name is NULL or empty string, the routine erases an * existing name of j-th column. */ void glp_set_col_name(glp_prob *lp, int j, const char *name) { glp_tree *tree = lp->tree; GLPCOL *col; if (tree != NULL && tree->reason != 0) xerror("glp_set_col_name: operation not allowed\n"); if (!(1 <= j && j <= lp->n)) xerror("glp_set_col_name: j = %d; column number out of range\n" , j); col = lp->col[j]; if (col->name != NULL) { if (col->node != NULL) { xassert(lp->c_tree != NULL); avl_delete_node(lp->c_tree, col->node); col->node = NULL; } dmp_free_atom(lp->pool, col->name, strlen(col->name)+1); col->name = NULL; } if (!(name == NULL || name[0] == '\0')) { int k; for (k = 0; name[k] != '\0'; k++) { if (k == 256) xerror("glp_set_col_name: j = %d; column name too long\n" , j); if (iscntrl((unsigned char)name[k])) xerror("glp_set_col_name: j = %d: column name contains i" "nvalid character(s)\n", j); } col->name = dmp_get_atom(lp->pool, strlen(name)+1); strcpy(col->name, name); if (lp->c_tree != NULL && col->name != NULL) { xassert(col->node == NULL); col->node = avl_insert_node(lp->c_tree, col->name); avl_set_node_link(col->node, col); } } return; } /*********************************************************************** * NAME * * glp_set_row_bnds - set (change) row bounds * * SYNOPSIS * * void glp_set_row_bnds(glp_prob *lp, int i, int type, double lb, * double ub); * * DESCRIPTION * * The routine glp_set_row_bnds sets (changes) the type and bounds of * i-th row (auxiliary variable) of the specified problem object. * * Parameters type, lb, and ub specify the type, lower bound, and upper * bound, respectively, as follows: * * Type Bounds Comments * ------------------------------------------------------ * GLP_FR -inf < x < +inf Free variable * GLP_LO lb <= x < +inf Variable with lower bound * GLP_UP -inf < x <= ub Variable with upper bound * GLP_DB lb <= x <= ub Double-bounded variable * GLP_FX x = lb Fixed variable * * where x is the auxiliary variable associated with i-th row. * * If the row has no lower bound, the parameter lb is ignored. If the * row has no upper bound, the parameter ub is ignored. If the row is * an equality constraint (i.e. the corresponding auxiliary variable is * of fixed type), only the parameter lb is used while the parameter ub * is ignored. */ void glp_set_row_bnds(glp_prob *lp, int i, int type, double lb, double ub) { GLPROW *row; if (!(1 <= i && i <= lp->m)) xerror("glp_set_row_bnds: i = %d; row number out of range\n", i); row = lp->row[i]; row->type = type; switch (type) { case GLP_FR: row->lb = row->ub = 0.0; if (row->stat != GLP_BS) row->stat = GLP_NF; break; case GLP_LO: row->lb = lb, row->ub = 0.0; if (row->stat != GLP_BS) row->stat = GLP_NL; break; case GLP_UP: row->lb = 0.0, row->ub = ub; if (row->stat != GLP_BS) row->stat = GLP_NU; break; case GLP_DB: row->lb = lb, row->ub = ub; if (!(row->stat == GLP_BS || row->stat == GLP_NL || row->stat == GLP_NU)) row->stat = (fabs(lb) <= fabs(ub) ? GLP_NL : GLP_NU); break; case GLP_FX: row->lb = row->ub = lb; if (row->stat != GLP_BS) row->stat = GLP_NS; break; default: xerror("glp_set_row_bnds: i = %d; type = %d; invalid row ty" "pe\n", i, type); } return; } /*********************************************************************** * NAME * * glp_set_col_bnds - set (change) column bounds * * SYNOPSIS * * void glp_set_col_bnds(glp_prob *lp, int j, int type, double lb, * double ub); * * DESCRIPTION * * The routine glp_set_col_bnds sets (changes) the type and bounds of * j-th column (structural variable) of the specified problem object. * * Parameters type, lb, and ub specify the type, lower bound, and upper * bound, respectively, as follows: * * Type Bounds Comments * ------------------------------------------------------ * GLP_FR -inf < x < +inf Free variable * GLP_LO lb <= x < +inf Variable with lower bound * GLP_UP -inf < x <= ub Variable with upper bound * GLP_DB lb <= x <= ub Double-bounded variable * GLP_FX x = lb Fixed variable * * where x is the structural variable associated with j-th column. * * If the column has no lower bound, the parameter lb is ignored. If the * column has no upper bound, the parameter ub is ignored. If the column * is of fixed type, only the parameter lb is used while the parameter * ub is ignored. */ void glp_set_col_bnds(glp_prob *lp, int j, int type, double lb, double ub) { GLPCOL *col; if (!(1 <= j && j <= lp->n)) xerror("glp_set_col_bnds: j = %d; column number out of range\n" , j); col = lp->col[j]; col->type = type; switch (type) { case GLP_FR: col->lb = col->ub = 0.0; if (col->stat != GLP_BS) col->stat = GLP_NF; break; case GLP_LO: col->lb = lb, col->ub = 0.0; if (col->stat != GLP_BS) col->stat = GLP_NL; break; case GLP_UP: col->lb = 0.0, col->ub = ub; if (col->stat != GLP_BS) col->stat = GLP_NU; break; case GLP_DB: col->lb = lb, col->ub = ub; if (!(col->stat == GLP_BS || col->stat == GLP_NL || col->stat == GLP_NU)) col->stat = (fabs(lb) <= fabs(ub) ? GLP_NL : GLP_NU); break; case GLP_FX: col->lb = col->ub = lb; if (col->stat != GLP_BS) col->stat = GLP_NS; break; default: xerror("glp_set_col_bnds: j = %d; type = %d; invalid column" " type\n", j, type); } return; } /*********************************************************************** * NAME * * glp_set_obj_coef - set (change) obj. coefficient or constant term * * SYNOPSIS * * void glp_set_obj_coef(glp_prob *lp, int j, double coef); * * DESCRIPTION * * The routine glp_set_obj_coef sets (changes) objective coefficient at * j-th column (structural variable) of the specified problem object. * * If the parameter j is 0, the routine sets (changes) the constant term * ("shift") of the objective function. */ void glp_set_obj_coef(glp_prob *lp, int j, double coef) { glp_tree *tree = lp->tree; if (tree != NULL && tree->reason != 0) xerror("glp_set_obj_coef: operation not allowed\n"); if (!(0 <= j && j <= lp->n)) xerror("glp_set_obj_coef: j = %d; column number out of range\n" , j); if (j == 0) lp->c0 = coef; else lp->col[j]->coef = coef; return; } /*********************************************************************** * NAME * * glp_set_mat_row - set (replace) row of the constraint matrix * * SYNOPSIS * * void glp_set_mat_row(glp_prob *lp, int i, int len, const int ind[], * const double val[]); * * DESCRIPTION * * The routine glp_set_mat_row stores (replaces) the contents of i-th * row of the constraint matrix of the specified problem object. * * Column indices and numeric values of new row elements must be placed * in locations ind[1], ..., ind[len] and val[1], ..., val[len], where * 0 <= len <= n is the new length of i-th row, n is the current number * of columns in the problem object. Elements with identical column * indices are not allowed. Zero elements are allowed, but they are not * stored in the constraint matrix. * * If the parameter len is zero, the parameters ind and/or val can be * specified as NULL. */ void glp_set_mat_row(glp_prob *lp, int i, int len, const int ind[], const double val[]) { glp_tree *tree = lp->tree; GLPROW *row; GLPCOL *col; GLPAIJ *aij, *next; int j, k; /* obtain pointer to i-th row */ if (!(1 <= i && i <= lp->m)) xerror("glp_set_mat_row: i = %d; row number out of range\n", i); row = lp->row[i]; if (tree != NULL && tree->reason != 0) { xassert(tree->curr != NULL); xassert(row->level == tree->curr->level); } /* remove all existing elements from i-th row */ while (row->ptr != NULL) { /* take next element in the row */ aij = row->ptr; /* remove the element from the row list */ row->ptr = aij->r_next; /* obtain pointer to corresponding column */ col = aij->col; /* remove the element from the column list */ if (aij->c_prev == NULL) 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; /* return the element to the memory pool */ dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--; /* if the corresponding column is basic, invalidate the basis factorization */ if (col->stat == GLP_BS) lp->valid = 0; } /* store new contents of i-th row */ if (!(0 <= len && len <= lp->n)) xerror("glp_set_mat_row: i = %d; len = %d; invalid row length " "\n", i, len); if (len > NNZ_MAX - lp->nnz) xerror("glp_set_mat_row: i = %d; len = %d; too many constraint" " coefficients\n", i, len); for (k = 1; k <= len; k++) { /* take number j of corresponding column */ j = ind[k]; /* obtain pointer to j-th column */ if (!(1 <= j && j <= lp->n)) xerror("glp_set_mat_row: i = %d; ind[%d] = %d; column index" " out of range\n", i, k, j); col = lp->col[j]; /* if there is element with the same column index, it can only be found in the beginning of j-th column list */ if (col->ptr != NULL && col->ptr->row->i == i) xerror("glp_set_mat_row: i = %d; ind[%d] = %d; duplicate co" "lumn indices not allowed\n", i, k, j); /* create new element */ aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++; aij->row = row; aij->col = col; aij->val = val[k]; /* add the new element to the beginning of i-th row and j-th column lists */ 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; /* if the corresponding column is basic, invalidate the basis factorization */ if (col->stat == GLP_BS && aij->val != 0.0) lp->valid = 0; } /* remove zero elements from i-th row */ for (aij = row->ptr; aij != NULL; aij = next) { next = aij->r_next; if (aij->val == 0.0) { /* remove the element from the row list */ if (aij->r_prev == NULL) row->ptr = next; else aij->r_prev->r_next = next; if (next == NULL) ; else next->r_prev = aij->r_prev; /* remove the element from the column list */ xassert(aij->c_prev == NULL); aij->col->ptr = aij->c_next; if (aij->c_next != NULL) aij->c_next->c_prev = NULL; /* return the element to the memory pool */ dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--; } } return; } /*********************************************************************** * NAME * * glp_set_mat_col - set (replace) column of the constraint matrix * * SYNOPSIS * * void glp_set_mat_col(glp_prob *lp, int j, int len, const int ind[], * const double val[]); * * DESCRIPTION * * The routine glp_set_mat_col stores (replaces) the contents of j-th * column of the constraint matrix of the specified problem object. * * Row indices and numeric values of new column elements must be placed * in locations ind[1], ..., ind[len] and val[1], ..., val[len], where * 0 <= len <= m is the new length of j-th column, m is the current * number of rows in the problem object. Elements with identical column * indices are not allowed. Zero elements are allowed, but they are not * stored in the constraint matrix. * * If the parameter len is zero, the parameters ind and/or val can be * specified as NULL. */ void glp_set_mat_col(glp_prob *lp, int j, int len, const int ind[], const double val[]) { glp_tree *tree = lp->tree; GLPROW *row; GLPCOL *col; GLPAIJ *aij, *next; int i, k; if (tree != NULL && tree->reason != 0) xerror("glp_set_mat_col: operation not allowed\n"); /* obtain pointer to j-th column */ if (!(1 <= j && j <= lp->n)) xerror("glp_set_mat_col: j = %d; column number out of range\n", j); col = lp->col[j]; /* remove all existing elements from j-th column */ while (col->ptr != NULL) { /* take next element in the column */ aij = col->ptr; /* remove the element from the column list */ col->ptr = aij->c_next; /* obtain pointer to corresponding row */ row = aij->row; /* remove the element from the row list */ if (aij->r_prev == NULL) 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; /* return the element to the memory pool */ dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--; } /* store new contents of j-th column */ if (!(0 <= len && len <= lp->m)) xerror("glp_set_mat_col: j = %d; len = %d; invalid column leng" "th\n", j, len); if (len > NNZ_MAX - lp->nnz) xerror("glp_set_mat_col: j = %d; len = %d; too many constraint" " coefficients\n", j, len); for (k = 1; k <= len; k++) { /* take number i of corresponding row */ i = ind[k]; /* obtain pointer to i-th row */ if (!(1 <= i && i <= lp->m)) xerror("glp_set_mat_col: j = %d; ind[%d] = %d; row index ou" "t of range\n", j, k, i); row = lp->row[i]; /* if there is element with the same row index, it can only be found in the beginning of i-th row list */ if (row->ptr != NULL && row->ptr->col->j == j) xerror("glp_set_mat_col: j = %d; ind[%d] = %d; duplicate ro" "w indices not allowed\n", j, k, i); /* create new element */ aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++; aij->row = row; aij->col = col; aij->val = val[k]; /* add the new element to the beginning of i-th row and j-th column lists */ 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; } /* remove zero elements from j-th column */ for (aij = col->ptr; aij != NULL; aij = next) { next = aij->c_next; if (aij->val == 0.0) { /* remove the element from the row list */ xassert(aij->r_prev == NULL); aij->row->ptr = aij->r_next; if (aij->r_next != NULL) aij->r_next->r_prev = NULL; /* remove the element from the column list */ if (aij->c_prev == NULL) col->ptr = next; else aij->c_prev->c_next = next; if (next == NULL) ; else next->c_prev = aij->c_prev; /* return the element to the memory pool */ dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--; } } /* if j-th column is basic, invalidate the basis factorization */ if (col->stat == GLP_BS) lp->valid = 0; return; } /*********************************************************************** * NAME * * glp_load_matrix - load (replace) the whole constraint matrix * * SYNOPSIS * * void glp_load_matrix(glp_prob *lp, int ne, const int ia[], * const int ja[], const double ar[]); * * DESCRIPTION * * The routine glp_load_matrix loads the constraint matrix passed in * the arrays ia, ja, and ar into the specified problem object. Before * loading the current contents of the constraint matrix is destroyed. * * Constraint coefficients (elements of the constraint matrix) must be * specified as triplets (ia[k], ja[k], ar[k]) for k = 1, ..., ne, * where ia[k] is the row index, ja[k] is the column index, ar[k] is a * numeric value of corresponding constraint coefficient. The parameter * ne specifies the total number of (non-zero) elements in the matrix * to be loaded. Coefficients with identical indices are not allowed. * Zero coefficients are allowed, however, they are not stored in the * constraint matrix. * * If the parameter ne is zero, the parameters ia, ja, and ar can be * specified as NULL. */ void glp_load_matrix(glp_prob *lp, int ne, const int ia[], const int ja[], const double ar[]) { glp_tree *tree = lp->tree; GLPROW *row; GLPCOL *col; GLPAIJ *aij, *next; int i, j, k; if (tree != NULL && tree->reason != 0) xerror("glp_load_matrix: operation not allowed\n"); /* clear the constraint matrix */ for (i = 1; i <= lp->m; i++) { row = lp->row[i]; while (row->ptr != NULL) { aij = row->ptr; row->ptr = aij->r_next; dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--; } } xassert(lp->nnz == 0); for (j = 1; j <= lp->n; j++) lp->col[j]->ptr = NULL; /* load the new contents of the constraint matrix and build its row lists */ if (ne < 0) xerror("glp_load_matrix: ne = %d; invalid number of constraint" " coefficients\n", ne); if (ne > NNZ_MAX) xerror("glp_load_matrix: ne = %d; too many constraint coeffici" "ents\n", ne); for (k = 1; k <= ne; k++) { /* take indices of new element */ i = ia[k], j = ja[k]; /* obtain pointer to i-th row */ if (!(1 <= i && i <= lp->m)) xerror("glp_load_matrix: ia[%d] = %d; row index out of rang" "e\n", k, i); row = lp->row[i]; /* obtain pointer to j-th column */ if (!(1 <= j && j <= lp->n)) xerror("glp_load_matrix: ja[%d] = %d; column index out of r" "ange\n", k, j); col = lp->col[j]; /* create new element */ aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++; aij->row = row; aij->col = col; aij->val = ar[k]; /* add the new element to the beginning of i-th row list */ aij->r_prev = NULL; aij->r_next = row->ptr; if (aij->r_next != NULL) aij->r_next->r_prev = aij; row->ptr = aij; } xassert(lp->nnz == ne); /* build column lists of the constraint matrix and check elements with identical indices */ for (i = 1; i <= lp->m; i++) { for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next) { /* obtain pointer to corresponding column */ col = aij->col; /* if there is element with identical indices, it can only be found in the beginning of j-th column list */ if (col->ptr != NULL && col->ptr->row->i == i) { for (k = 1; k <= ne; k++) if (ia[k] == i && ja[k] == col->j) break; xerror("glp_load_mat: ia[%d] = %d; ja[%d] = %d; duplicat" "e indices not allowed\n", k, i, k, col->j); } /* add the element to the beginning of j-th column list */ aij->c_prev = NULL; aij->c_next = col->ptr; if (aij->c_next != NULL) aij->c_next->c_prev = aij; col->ptr = aij; } } /* remove zero elements from the constraint matrix */ for (i = 1; i <= lp->m; i++) { row = lp->row[i]; for (aij = row->ptr; aij != NULL; aij = next) { next = aij->r_next; if (aij->val == 0.0) { /* remove the element from the row list */ if (aij->r_prev == NULL) row->ptr = next; else aij->r_prev->r_next = next; if (next == NULL) ; else next->r_prev = aij->r_prev; /* remove the element from the column list */ 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; /* return the element to the memory pool */ dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--; } } } /* invalidate the basis factorization */ lp->valid = 0; return; } /*********************************************************************** * NAME * * glp_check_dup - check for duplicate elements in sparse matrix * * SYNOPSIS * * int glp_check_dup(int m, int n, int ne, const int ia[], * const int ja[]); * * DESCRIPTION * * The routine glp_check_dup checks for duplicate elements (that is, * elements with identical indices) in a sparse matrix specified in the * coordinate format. * * The parameters m and n specifies, respectively, the number of rows * and columns in the matrix, m >= 0, n >= 0. * * The parameter ne specifies the number of (structurally) non-zero * elements in the matrix, ne >= 0. * * Elements of the matrix are specified as doublets (ia[k],ja[k]) for * k = 1,...,ne, where ia[k] is a row index, ja[k] is a column index. * * The routine glp_check_dup can be used prior to a call to the routine * glp_load_matrix to check that the constraint matrix to be loaded has * no duplicate elements. * * RETURNS * * The routine glp_check_dup returns one of the following values: * * 0 - the matrix has no duplicate elements; * * -k - indices ia[k] or/and ja[k] are out of range; * * +k - element (ia[k],ja[k]) is duplicate. */ int glp_check_dup(int m, int n, int ne, const int ia[], const int ja[]) { int i, j, k, *ptr, *next, ret; char *flag; if (m < 0) xerror("glp_check_dup: m = %d; invalid parameter\n"); if (n < 0) xerror("glp_check_dup: n = %d; invalid parameter\n"); if (ne < 0) xerror("glp_check_dup: ne = %d; invalid parameter\n"); if (ne > 0 && ia == NULL) xerror("glp_check_dup: ia = %p; invalid parameter\n", ia); if (ne > 0 && ja == NULL) xerror("glp_check_dup: ja = %p; invalid parameter\n", ja); for (k = 1; k <= ne; k++) { i = ia[k], j = ja[k]; if (!(1 <= i && i <= m && 1 <= j && j <= n)) { ret = -k; goto done; } } if (m == 0 || n == 0) { ret = 0; goto done; } /* allocate working arrays */ ptr = xcalloc(1+m, sizeof(int)); next = xcalloc(1+ne, sizeof(int)); flag = xcalloc(1+n, sizeof(char)); /* build row lists */ for (i = 1; i <= m; i++) ptr[i] = 0; for (k = 1; k <= ne; k++) { i = ia[k]; next[k] = ptr[i]; ptr[i] = k; } /* clear column flags */ for (j = 1; j <= n; j++) flag[j] = 0; /* check for duplicate elements */ for (i = 1; i <= m; i++) { for (k = ptr[i]; k != 0; k = next[k]) { j = ja[k]; if (flag[j]) { /* find first element (i,j) */ for (k = 1; k <= ne; k++) if (ia[k] == i && ja[k] == j) break; xassert(k <= ne); /* find next (duplicate) element (i,j) */ for (k++; k <= ne; k++) if (ia[k] == i && ja[k] == j) break; xassert(k <= ne); ret = +k; goto skip; } flag[j] = 1; } /* clear column flags */ for (k = ptr[i]; k != 0; k = next[k]) flag[ja[k]] = 0; } /* no duplicate element found */ ret = 0; skip: /* free working arrays */ xfree(ptr); xfree(next); xfree(flag); done: return ret; } /*********************************************************************** * NAME * * glp_sort_matrix - sort elements of the constraint matrix * * SYNOPSIS * * void glp_sort_matrix(glp_prob *P); * * DESCRIPTION * * The routine glp_sort_matrix sorts elements of the constraint matrix * rebuilding its row and column linked lists. On exit from the routine * the constraint matrix is not changed, however, elements in the row * linked lists become ordered by ascending column indices, and the * elements in the column linked lists become ordered by ascending row * indices. */ void glp_sort_matrix(glp_prob *P) { GLPAIJ *aij; int i, j; if (P == NULL || P->magic != GLP_PROB_MAGIC) xerror("glp_sort_matrix: P = %p; invalid problem object\n", P); /* rebuild row linked lists */ for (i = P->m; i >= 1; i--) P->row[i]->ptr = NULL; for (j = P->n; j >= 1; j--) { for (aij = P->col[j]->ptr; aij != NULL; aij = aij->c_next) { i = aij->row->i; aij->r_prev = NULL; aij->r_next = P->row[i]->ptr; if (aij->r_next != NULL) aij->r_next->r_prev = aij; P->row[i]->ptr = aij; } } /* rebuild column linked lists */ for (j = P->n; j >= 1; j--) P->col[j]->ptr = NULL; for (i = P->m; i >= 1; i--) { for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next) { j = aij->col->j; aij->c_prev = NULL; aij->c_next = P->col[j]->ptr; if (aij->c_next != NULL) aij->c_next->c_prev = aij; P->col[j]->ptr = aij; } } return; } /*********************************************************************** * NAME * * glp_del_rows - delete rows from problem object * * SYNOPSIS * * void glp_del_rows(glp_prob *lp, int nrs, const int num[]); * * DESCRIPTION * * The routine glp_del_rows deletes rows from the specified problem * object. Ordinal numbers of rows to be deleted should be placed in * locations num[1], ..., num[nrs], where nrs > 0. * * Note that deleting rows involves changing ordinal numbers of other * rows remaining in the problem object. New ordinal numbers of the * remaining rows are assigned under the assumption that the original * order of rows is not changed. */ void glp_del_rows(glp_prob *lp, int nrs, const int num[]) { glp_tree *tree = lp->tree; GLPROW *row; int i, k, m_new; /* mark rows to be deleted */ if (!(1 <= nrs && nrs <= lp->m)) xerror("glp_del_rows: nrs = %d; invalid number of rows\n", nrs); for (k = 1; k <= nrs; k++) { /* take the number of row to be deleted */ i = num[k]; /* obtain pointer to i-th row */ if (!(1 <= i && i <= lp->m)) xerror("glp_del_rows: num[%d] = %d; row number out of range" "\n", k, i); row = lp->row[i]; if (tree != NULL && tree->reason != 0) { if (!(tree->reason == GLP_IROWGEN || tree->reason == GLP_ICUTGEN)) xerror("glp_del_rows: operation not allowed\n"); xassert(tree->curr != NULL); if (row->level != tree->curr->level) xerror("glp_del_rows: num[%d] = %d; invalid attempt to d" "elete row created not in current subproblem\n", k,i); if (row->stat != GLP_BS) xerror("glp_del_rows: num[%d] = %d; invalid attempt to d" "elete active row (constraint)\n", k, i); tree->reinv = 1; } /* check that the row is not marked yet */ if (row->i == 0) xerror("glp_del_rows: num[%d] = %d; duplicate row numbers n" "ot allowed\n", k, i); /* erase symbolic name assigned to the row */ glp_set_row_name(lp, i, NULL); xassert(row->node == NULL); /* erase corresponding row of the constraint matrix */ glp_set_mat_row(lp, i, 0, NULL, NULL); xassert(row->ptr == NULL); /* mark the row to be deleted */ row->i = 0; } /* delete all marked rows from the row list */ m_new = 0; for (i = 1; i <= lp->m; i++) { /* obtain pointer to i-th row */ row = lp->row[i]; /* check if the row is marked */ if (row->i == 0) { /* it is marked, delete it */ dmp_free_atom(lp->pool, row, sizeof(GLPROW)); } else { /* it is not marked; keep it */ row->i = ++m_new; lp->row[row->i] = row; } } /* set new number of rows */ lp->m = m_new; /* invalidate the basis factorization */ lp->valid = 0; return; } /*********************************************************************** * NAME * * glp_del_cols - delete columns from problem object * * SYNOPSIS * * void glp_del_cols(glp_prob *lp, int ncs, const int num[]); * * DESCRIPTION * * The routine glp_del_cols deletes columns from the specified problem * object. Ordinal numbers of columns to be deleted should be placed in * locations num[1], ..., num[ncs], where ncs > 0. * * Note that deleting columns involves changing ordinal numbers of * other columns remaining in the problem object. New ordinal numbers * of the remaining columns are assigned under the assumption that the * original order of columns is not changed. */ void glp_del_cols(glp_prob *lp, int ncs, const int num[]) { glp_tree *tree = lp->tree; GLPCOL *col; int j, k, n_new; if (tree != NULL && tree->reason != 0) xerror("glp_del_cols: operation not allowed\n"); /* mark columns to be deleted */ if (!(1 <= ncs && ncs <= lp->n)) xerror("glp_del_cols: ncs = %d; invalid number of columns\n", ncs); for (k = 1; k <= ncs; k++) { /* take the number of column to be deleted */ j = num[k]; /* obtain pointer to j-th column */ if (!(1 <= j && j <= lp->n)) xerror("glp_del_cols: num[%d] = %d; column number out of ra" "nge", k, j); col = lp->col[j]; /* check that the column is not marked yet */ if (col->j == 0) xerror("glp_del_cols: num[%d] = %d; duplicate column number" "s not allowed\n", k, j); /* erase symbolic name assigned to the column */ glp_set_col_name(lp, j, NULL); xassert(col->node == NULL); /* erase corresponding column of the constraint matrix */ glp_set_mat_col(lp, j, 0, NULL, NULL); xassert(col->ptr == NULL); /* mark the column to be deleted */ col->j = 0; /* if it is basic, invalidate the basis factorization */ if (col->stat == GLP_BS) lp->valid = 0; } /* delete all marked columns from the column list */ n_new = 0; for (j = 1; j <= lp->n; j++) { /* obtain pointer to j-th column */ col = lp->col[j]; /* check if the column is marked */ if (col->j == 0) { /* it is marked; delete it */ dmp_free_atom(lp->pool, col, sizeof(GLPCOL)); } else { /* it is not marked; keep it */ col->j = ++n_new; lp->col[col->j] = col; } } /* set new number of columns */ lp->n = n_new; /* if the basis header is still valid, adjust it */ if (lp->valid) { int m = lp->m; int *head = lp->head; for (j = 1; j <= n_new; j++) { k = lp->col[j]->bind; if (k != 0) { xassert(1 <= k && k <= m); head[k] = m + j; } } } return; } /*********************************************************************** * NAME * * glp_copy_prob - copy problem object content * * SYNOPSIS * * void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names); * * DESCRIPTION * * The routine glp_copy_prob copies the content of the problem object * prob to the problem object dest. * * The parameter names is a flag. If it is non-zero, the routine also * copies all symbolic names; otherwise, if it is zero, symbolic names * are not copied. */ void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names) { glp_tree *tree = dest->tree; glp_bfcp bfcp; int i, j, len, *ind; double *val; if (tree != NULL && tree->reason != 0) xerror("glp_copy_prob: operation not allowed\n"); if (dest == prob) xerror("glp_copy_prob: copying problem object to itself not al" "lowed\n"); if (!(names == GLP_ON || names == GLP_OFF)) xerror("glp_copy_prob: names = %d; invalid parameter\n", names); glp_erase_prob(dest); if (names && prob->name != NULL) glp_set_prob_name(dest, prob->name); if (names && prob->obj != NULL) glp_set_obj_name(dest, prob->obj); dest->dir = prob->dir; dest->c0 = prob->c0; if (prob->m > 0) glp_add_rows(dest, prob->m); if (prob->n > 0) glp_add_cols(dest, prob->n); glp_get_bfcp(prob, &bfcp); glp_set_bfcp(dest, &bfcp); dest->pbs_stat = prob->pbs_stat; dest->dbs_stat = prob->dbs_stat; dest->obj_val = prob->obj_val; dest->some = prob->some; dest->ipt_stat = prob->ipt_stat; dest->ipt_obj = prob->ipt_obj; dest->mip_stat = prob->mip_stat; dest->mip_obj = prob->mip_obj; for (i = 1; i <= prob->m; i++) { GLPROW *to = dest->row[i]; GLPROW *from = prob->row[i]; if (names && from->name != NULL) glp_set_row_name(dest, i, from->name); to->type = from->type; to->lb = from->lb; to->ub = from->ub; to->rii = from->rii; to->stat = from->stat; to->prim = from->prim; to->dual = from->dual; to->pval = from->pval; to->dval = from->dval; to->mipx = from->mipx; } ind = xcalloc(1+prob->m, sizeof(int)); val = xcalloc(1+prob->m, sizeof(double)); for (j = 1; j <= prob->n; j++) { GLPCOL *to = dest->col[j]; GLPCOL *from = prob->col[j]; if (names && from->name != NULL) glp_set_col_name(dest, j, from->name); to->kind = from->kind; to->type = from->type; to->lb = from->lb; to->ub = from->ub; to->coef = from->coef; len = glp_get_mat_col(prob, j, ind, val); glp_set_mat_col(dest, j, len, ind, val); to->sjj = from->sjj; to->stat = from->stat; to->prim = from->prim; to->dual = from->dual; to->pval = from->pval; to->dval = from->dval; to->mipx = from->mipx; } xfree(ind); xfree(val); return; } /*********************************************************************** * NAME * * glp_erase_prob - erase problem object content * * SYNOPSIS * * void glp_erase_prob(glp_prob *lp); * * DESCRIPTION * * The routine glp_erase_prob erases the content of the specified * problem object. The effect of this operation is the same as if the * problem object would be deleted with the routine glp_delete_prob and * then created anew with the routine glp_create_prob, with exception * that the handle (pointer) to the problem object remains valid. */ static void delete_prob(glp_prob *lp); void glp_erase_prob(glp_prob *lp) { glp_tree *tree = lp->tree; if (tree != NULL && tree->reason != 0) xerror("glp_erase_prob: operation not allowed\n"); delete_prob(lp); create_prob(lp); return; } /*********************************************************************** * NAME * * glp_delete_prob - delete problem object * * SYNOPSIS * * void glp_delete_prob(glp_prob *lp); * * DESCRIPTION * * The routine glp_delete_prob deletes the specified problem object and * frees all the memory allocated to it. */ static void delete_prob(glp_prob *lp) { lp->magic = 0x3F3F3F3F; dmp_delete_pool(lp->pool); #if 0 /* 17/XI-2009 */ xfree(lp->cps); #else if (lp->parms != NULL) xfree(lp->parms); #endif xassert(lp->tree == NULL); #if 0 if (lp->cwa != NULL) xfree(lp->cwa); #endif xfree(lp->row); xfree(lp->col); if (lp->r_tree != NULL) avl_delete_tree(lp->r_tree); if (lp->c_tree != NULL) avl_delete_tree(lp->c_tree); xfree(lp->head); if (lp->bfcp != NULL) xfree(lp->bfcp); if (lp->bfd != NULL) bfd_delete_it(lp->bfd); return; } void glp_delete_prob(glp_prob *lp) { glp_tree *tree = lp->tree; if (tree != NULL && tree->reason != 0) xerror("glp_delete_prob: operation not allowed\n"); delete_prob(lp); xfree(lp); return; } /* eof */ Rglpk/src/GLPK/stdc.h0000644000176000001440000000245412245352174014025 0ustar ripleyusers/* stdc.h (standard ANSI C headers) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef STDC_H #define STDC_H #include #include #include #include #include #include #include #include #include #include #include #include #endif /* eof */ Rglpk/src/GLPK/glpavl.h0000644000176000001440000001036712245352174014357 0ustar ripleyusers/* glpavl.h (binary search tree) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPAVL_H #define GLPAVL_H #include "dmp.h" typedef struct AVL AVL; typedef struct AVLNODE AVLNODE; struct AVL { /* AVL tree (Adelson-Velsky & Landis binary search tree) */ DMP *pool; /* memory pool for allocating nodes */ AVLNODE *root; /* pointer to the root node */ int (*fcmp)(void *info, const void *key1, const void *key2); /* application-defined key comparison routine */ void *info; /* transit pointer passed to the routine fcmp */ int size; /* the tree size (the total number of nodes) */ int height; /* the tree height */ }; struct AVLNODE { /* node of AVL tree */ const void *key; /* pointer to the node key (data structure for representing keys is supplied by the application) */ int rank; /* node rank = relative position of the node in its own subtree = the number of nodes in the left subtree plus one */ int type; /* reserved for the application specific information */ void *link; /* reserved for the application specific information */ AVLNODE *up; /* pointer to the parent node */ short int flag; /* node flag: 0 - this node is the left child of its parent (or this node is the root of the tree and has no parent) 1 - this node is the right child of its parent */ short int bal; /* node balance = the difference between heights of the right and left subtrees: -1 - the left subtree is higher than the right one; 0 - the left and right subtrees have the same height; +1 - the left subtree is lower than the right one */ AVLNODE *left; /* pointer to the root of the left subtree */ AVLNODE *right; /* pointer to the root of the right subtree */ }; #define avl_create_tree _glp_avl_create_tree AVL *avl_create_tree(int (*fcmp)(void *info, const void *key1, const void *key2), void *info); /* create AVL tree */ #define avl_strcmp _glp_avl_strcmp int avl_strcmp(void *info, const void *key1, const void *key2); /* compare character string keys */ #define avl_insert_node _glp_avl_insert_node AVLNODE *avl_insert_node(AVL *tree, const void *key); /* insert new node into AVL tree */ #define avl_set_node_type _glp_avl_set_node_type void avl_set_node_type(AVLNODE *node, int type); /* assign the type field of specified node */ #define avl_set_node_link _glp_avl_set_node_link void avl_set_node_link(AVLNODE *node, void *link); /* assign the link field of specified node */ #define avl_find_node _glp_avl_find_node AVLNODE *avl_find_node(AVL *tree, const void *key); /* find node in AVL tree */ #define avl_get_node_type _glp_avl_get_node_type int avl_get_node_type(AVLNODE *node); /* retrieve the type field of specified node */ #define avl_get_node_link _glp_avl_get_node_link void *avl_get_node_link(AVLNODE *node); /* retrieve the link field of specified node */ #define avl_delete_node _glp_avl_delete_node void avl_delete_node(AVL *tree, AVLNODE *node); /* delete specified node from AVL tree */ #define avl_delete_tree _glp_avl_delete_tree void avl_delete_tree(AVL *tree); /* delete AVL tree */ #endif /* eof */ Rglpk/src/GLPK/glplib03.c0000644000176000001440000003554212245352174014503 0ustar ripleyusers/* glplib03.c (miscellaneous library routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #include "glplib.h" /*********************************************************************** * NAME * * str2int - convert character string to value of int type * * SYNOPSIS * * #include "glplib.h" * int str2int(const char *str, int *val); * * DESCRIPTION * * The routine str2int converts the character string str to a value of * integer type and stores the value into location, which the parameter * val points to (in the case of error content of this location is not * changed). * * RETURNS * * The routine returns one of the following error codes: * * 0 - no error; * 1 - value out of range; * 2 - character string is syntactically incorrect. */ int str2int(const char *str, int *_val) { int d, k, s, val = 0; /* scan optional sign */ if (str[0] == '+') s = +1, k = 1; else if (str[0] == '-') s = -1, k = 1; else s = +1, k = 0; /* check for the first digit */ if (!isdigit((unsigned char)str[k])) return 2; /* scan digits */ while (isdigit((unsigned char)str[k])) { d = str[k++] - '0'; if (s > 0) { if (val > INT_MAX / 10) return 1; val *= 10; if (val > INT_MAX - d) return 1; val += d; } else { if (val < INT_MIN / 10) return 1; val *= 10; if (val < INT_MIN + d) return 1; val -= d; } } /* check for terminator */ if (str[k] != '\0') return 2; /* conversion has been done */ *_val = val; return 0; } /*********************************************************************** * NAME * * str2num - convert character string to value of double type * * SYNOPSIS * * #include "glplib.h" * int str2num(const char *str, double *val); * * DESCRIPTION * * The routine str2num converts the character string str to a value of * double type and stores the value into location, which the parameter * val points to (in the case of error content of this location is not * changed). * * RETURNS * * The routine returns one of the following error codes: * * 0 - no error; * 1 - value out of range; * 2 - character string is syntactically incorrect. */ int str2num(const char *str, double *_val) { int k; double val; /* scan optional sign */ k = (str[0] == '+' || str[0] == '-' ? 1 : 0); /* check for decimal point */ if (str[k] == '.') { k++; /* a digit should follow it */ if (!isdigit((unsigned char)str[k])) return 2; k++; goto frac; } /* integer part should start with a digit */ if (!isdigit((unsigned char)str[k])) return 2; /* scan integer part */ while (isdigit((unsigned char)str[k])) k++; /* check for decimal point */ if (str[k] == '.') k++; frac: /* scan optional fraction part */ while (isdigit((unsigned char)str[k])) k++; /* check for decimal exponent */ if (str[k] == 'E' || str[k] == 'e') { k++; /* scan optional sign */ if (str[k] == '+' || str[k] == '-') k++; /* a digit should follow E, E+ or E- */ if (!isdigit((unsigned char)str[k])) return 2; } /* scan optional exponent part */ while (isdigit((unsigned char)str[k])) k++; /* check for terminator */ if (str[k] != '\0') return 2; /* perform conversion */ { char *endptr; val = strtod(str, &endptr); if (*endptr != '\0') return 2; } /* check for overflow */ if (!(-DBL_MAX <= val && val <= +DBL_MAX)) return 1; /* check for underflow */ if (-DBL_MIN < val && val < +DBL_MIN) val = 0.0; /* conversion has been done */ *_val = val; return 0; } /*********************************************************************** * NAME * * strspx - remove all spaces from character string * * SYNOPSIS * * #include "glplib.h" * char *strspx(char *str); * * DESCRIPTION * * The routine strspx removes all spaces from the character string str. * * RETURNS * * The routine returns a pointer to the character string. * * EXAMPLES * * strspx(" Errare humanum est ") => "Errarehumanumest" * * strspx(" ") => "" */ char *strspx(char *str) { char *s, *t; for (s = t = str; *s; s++) if (*s != ' ') *t++ = *s; *t = '\0'; return str; } /*********************************************************************** * NAME * * strtrim - remove trailing spaces from character string * * SYNOPSIS * * #include "glplib.h" * char *strtrim(char *str); * * DESCRIPTION * * The routine strtrim removes trailing spaces from the character * string str. * * RETURNS * * The routine returns a pointer to the character string. * * EXAMPLES * * strtrim("Errare humanum est ") => "Errare humanum est" * * strtrim(" ") => "" */ char *strtrim(char *str) { char *t; for (t = strrchr(str, '\0') - 1; t >= str; t--) { if (*t != ' ') break; *t = '\0'; } return str; } /*********************************************************************** * NAME * * strrev - reverse character string * * SYNOPSIS * * #include "glplib.h" * char *strrev(char *s); * * DESCRIPTION * * The routine strrev changes characters in a character string s to the * reverse order, except the terminating null character. * * RETURNS * * The routine returns the pointer s. * * EXAMPLES * * strrev("") => "" * * strrev("Today is Monday") => "yadnoM si yadoT" */ char *strrev(char *s) { int i, j; char t; for (i = 0, j = strlen(s)-1; i < j; i++, j--) t = s[i], s[i] = s[j], s[j] = t; return s; } /*********************************************************************** * NAME * * gcd - find greatest common divisor of two integers * * SYNOPSIS * * #include "glplib.h" * int gcd(int x, int y); * * RETURNS * * The routine gcd returns gcd(x, y), the greatest common divisor of * the two positive integers given. * * ALGORITHM * * The routine gcd is based on Euclid's algorithm. * * REFERENCES * * Don Knuth, The Art of Computer Programming, Vol.2: Seminumerical * Algorithms, 3rd Edition, Addison-Wesley, 1997. Section 4.5.2: The * Greatest Common Divisor, pp. 333-56. */ int gcd(int x, int y) { int r; xassert(x > 0 && y > 0); while (y > 0) r = x % y, x = y, y = r; return x; } /*********************************************************************** * NAME * * gcdn - find greatest common divisor of n integers * * SYNOPSIS * * #include "glplib.h" * int gcdn(int n, int x[]); * * RETURNS * * The routine gcdn returns gcd(x[1], x[2], ..., x[n]), the greatest * common divisor of n positive integers given, n > 0. * * BACKGROUND * * The routine gcdn is based on the following identity: * * gcd(x, y, z) = gcd(gcd(x, y), z). * * REFERENCES * * Don Knuth, The Art of Computer Programming, Vol.2: Seminumerical * Algorithms, 3rd Edition, Addison-Wesley, 1997. Section 4.5.2: The * Greatest Common Divisor, pp. 333-56. */ int gcdn(int n, int x[]) { int d, j; xassert(n > 0); for (j = 1; j <= n; j++) { xassert(x[j] > 0); if (j == 1) d = x[1]; else d = gcd(d, x[j]); if (d == 1) break; } return d; } /*********************************************************************** * NAME * * lcm - find least common multiple of two integers * * SYNOPSIS * * #include "glplib.h" * int lcm(int x, int y); * * RETURNS * * The routine lcm returns lcm(x, y), the least common multiple of the * two positive integers given. In case of integer overflow the routine * returns zero. * * BACKGROUND * * The routine lcm is based on the following identity: * * lcm(x, y) = (x * y) / gcd(x, y) = x * [y / gcd(x, y)], * * where gcd(x, y) is the greatest common divisor of x and y. */ int lcm(int x, int y) { xassert(x > 0); xassert(y > 0); y /= gcd(x, y); if (x > INT_MAX / y) return 0; return x * y; } /*********************************************************************** * NAME * * lcmn - find least common multiple of n integers * * SYNOPSIS * * #include "glplib.h" * int lcmn(int n, int x[]); * * RETURNS * * The routine lcmn returns lcm(x[1], x[2], ..., x[n]), the least * common multiple of n positive integers given, n > 0. In case of * integer overflow the routine returns zero. * * BACKGROUND * * The routine lcmn is based on the following identity: * * lcmn(x, y, z) = lcm(lcm(x, y), z), * * where lcm(x, y) is the least common multiple of x and y. */ int lcmn(int n, int x[]) { int m, j; xassert(n > 0); for (j = 1; j <= n; j++) { xassert(x[j] > 0); if (j == 1) m = x[1]; else m = lcm(m, x[j]); if (m == 0) break; } return m; } /*********************************************************************** * NAME * * round2n - round floating-point number to nearest power of two * * SYNOPSIS * * #include "glplib.h" * double round2n(double x); * * RETURNS * * Given a positive floating-point value x the routine round2n returns * 2^n such that |x - 2^n| is minimal. * * EXAMPLES * * round2n(10.1) = 2^3 = 8 * round2n(15.3) = 2^4 = 16 * round2n(0.01) = 2^(-7) = 0.0078125 * * BACKGROUND * * Let x = f * 2^e, where 0.5 <= f < 1 is a normalized fractional part, * e is an integer exponent. Then, obviously, 0.5 * 2^e <= x < 2^e, so * if x - 0.5 * 2^e <= 2^e - x, we choose 0.5 * 2^e = 2^(e-1), and 2^e * otherwise. The latter condition can be written as 2 * x <= 1.5 * 2^e * or 2 * f * 2^e <= 1.5 * 2^e or, finally, f <= 0.75. */ double round2n(double x) { int e; double f; xassert(x > 0.0); f = frexp(x, &e); return ldexp(1.0, f <= 0.75 ? e-1 : e); } /*********************************************************************** * NAME * * fp2rat - convert floating-point number to rational number * * SYNOPSIS * * #include "glplib.h" * int fp2rat(double x, double eps, double *p, double *q); * * DESCRIPTION * * Given a floating-point number 0 <= x < 1 the routine fp2rat finds * its "best" rational approximation p / q, where p >= 0 and q > 0 are * integer numbers, such that |x - p / q| <= eps. * * RETURNS * * The routine fp2rat returns the number of iterations used to achieve * the specified precision eps. * * EXAMPLES * * For x = sqrt(2) - 1 = 0.414213562373095 and eps = 1e-6 the routine * gives p = 408 and q = 985, where 408 / 985 = 0.414213197969543. * * BACKGROUND * * It is well known that every positive real number x can be expressed * as the following continued fraction: * * x = b[0] + a[1] * ------------------------ * b[1] + a[2] * ----------------- * b[2] + a[3] * ---------- * b[3] + ... * * where: * * a[k] = 1, k = 0, 1, 2, ... * * b[k] = floor(x[k]), k = 0, 1, 2, ... * * x[0] = x, * * x[k] = 1 / frac(x[k-1]), k = 1, 2, 3, ... * * To find the "best" rational approximation of x the routine computes * partial fractions f[k] by dropping after k terms as follows: * * f[k] = A[k] / B[k], * * where: * * A[-1] = 1, A[0] = b[0], B[-1] = 0, B[0] = 1, * * A[k] = b[k] * A[k-1] + a[k] * A[k-2], * * B[k] = b[k] * B[k-1] + a[k] * B[k-2]. * * Once the condition * * |x - f[k]| <= eps * * has been satisfied, the routine reports p = A[k] and q = B[k] as the * final answer. * * In the table below here is some statistics obtained for one million * random numbers uniformly distributed in the range [0, 1). * * eps max p mean p max q mean q max k mean k * ------------------------------------------------------------- * 1e-1 8 1.6 9 3.2 3 1.4 * 1e-2 98 6.2 99 12.4 5 2.4 * 1e-3 997 20.7 998 41.5 8 3.4 * 1e-4 9959 66.6 9960 133.5 10 4.4 * 1e-5 97403 211.7 97404 424.2 13 5.3 * 1e-6 479669 669.9 479670 1342.9 15 6.3 * 1e-7 1579030 2127.3 3962146 4257.8 16 7.3 * 1e-8 26188823 6749.4 26188824 13503.4 19 8.2 * * REFERENCES * * W. B. Jones and W. J. Thron, "Continued Fractions: Analytic Theory * and Applications," Encyclopedia on Mathematics and Its Applications, * Addison-Wesley, 1980. */ int fp2rat(double x, double eps, double *p, double *q) { int k; double xk, Akm1, Ak, Bkm1, Bk, ak, bk, fk, temp; if (!(0.0 <= x && x < 1.0)) xerror("fp2rat: x = %g; number out of range\n", x); for (k = 0; ; k++) { xassert(k <= 100); if (k == 0) { /* x[0] = x */ xk = x; /* A[-1] = 1 */ Akm1 = 1.0; /* A[0] = b[0] = floor(x[0]) = 0 */ Ak = 0.0; /* B[-1] = 0 */ Bkm1 = 0.0; /* B[0] = 1 */ Bk = 1.0; } else { /* x[k] = 1 / frac(x[k-1]) */ temp = xk - floor(xk); xassert(temp != 0.0); xk = 1.0 / temp; /* a[k] = 1 */ ak = 1.0; /* b[k] = floor(x[k]) */ bk = floor(xk); /* A[k] = b[k] * A[k-1] + a[k] * A[k-2] */ temp = bk * Ak + ak * Akm1; Akm1 = Ak, Ak = temp; /* B[k] = b[k] * B[k-1] + a[k] * B[k-2] */ temp = bk * Bk + ak * Bkm1; Bkm1 = Bk, Bk = temp; } /* f[k] = A[k] / B[k] */ fk = Ak / Bk; #if 0 print("%.*g / %.*g = %.*g", DBL_DIG, Ak, DBL_DIG, Bk, DBL_DIG, fk); #endif if (fabs(x - fk) <= eps) break; } *p = Ak; *q = Bk; return k; } /* eof */ Rglpk/src/GLPK/fhv.c0000644000176000001440000005476312245352174013660 0ustar ripleyusers/* fhv.c (sparse updatable FHV-factorization) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #include "fhv.h" /*********************************************************************** * fhv_ft_update - update FHV-factorization (Forrest-Tomlin) * * This routine updates FHV-factorization of the original matrix A * after replacing its j-th column by a new one. The routine is based * on the method proposed by Forrest and Tomlin [1]. * * The parameter q specifies the number of column of A, which has been * replaced, 1 <= q <= n, where n is the order of A. * * Row indices and numerical values of non-zero elements of the new * j-th column of A should be placed in locations aq_ind[1], ..., * aq_ind[aq_len] and aq_val[1], ..., aq_val[aq_len], respectively, * where aq_len is the number of non-zeros. Neither zero nor duplicate * elements are allowed. * * The working arrays ind, val, and work should have at least 1+n * elements (0-th elements are not used). * * RETURNS * * 0 The factorization has been successfully updated. * * 1 New matrix U = P'* V * Q' is upper triangular with zero diagonal * element u[s,s]. (Elimination was not performed.) * * 2 New matrix U = P'* V * Q' is upper triangular, and its diagonal * element u[s,s] or u[t,t] is too small in magnitude. (Elimination * was not performed.) * * 3 The same as 2, but after performing elimination. * * 4 The factorization has not been updated, because maximal number of * updates has been reached. * * 5 Accuracy test failed for the updated factorization. * * BACKGROUND * * The routine is based on the updating method proposed by Forrest and * Tomlin [1]. * * Let q-th column of the original matrix A have been replaced by new * column A[q]. Then, to keep the equality A = F * H * V, q-th column * of matrix V should be replaced by column V[q] = inv(F * H) * A[q]. * From the standpoint of matrix U = P'* V * Q' such replacement is * equivalent to replacement of s-th column of matrix U, where s is * determined from q by permutation matrix Q. Thus, matrix U loses its * upper triangular form and becomes the following: * * 1 s t n * 1 x x * x x x x x x * . x * x x x x x x * s . . * x x x x x x * . . * x x x x x x * . . * . x x x x x * . . * . . x x x x * t . . * . . . x x x * . . . . . . . x x * n . . . . . . . . x * * where t is largest row index of a non-zero element in s-th column. * * The routine makes matrix U upper triangular as follows. First, it * moves rows and columns s+1, ..., t by one position to the left and * upwards, resp., and moves s-th row and s-th column to position t. * Due to such symmetric permutations matrix U becomes the following * (note that all diagonal elements remain on the diagonal, and element * u[s,s] becomes u[t,t]): * * 1 s t n * 1 x x x x x x * x x * . x x x x x * x x * s . . x x x x * x x * . . . x x x * x x * . . . . x x * x x * . . . . . x * x x * t . . x x x x * x x * . . . . . . . x x * n . . . . . . . . x * * Then the routine performs gaussian elimination to eliminate * subdiagonal elements u[t,s], ..., u[t,t-1] using diagonal elements * u[s,s], ..., u[t-1,t-1] as pivots. During the elimination process * the routine permutes neither rows nor columns, so only t-th row is * changed. Should note that actually all operations are performed on * matrix V = P * U * Q, since matrix U is not stored. * * To keep the equality A = F * H * V, the routine appends new row-like * factor H[k] to matrix H, and every time it applies elementary * gaussian transformation to eliminate u[t,j'] = v[p,j] using pivot * u[j',j'] = v[i,j], it also adds new element f[p,j] = v[p,j] / v[i,j] * (gaussian multiplier) to factor H[k], which initially is a unity * matrix. At the end of elimination process the row-like factor H[k] * may look as follows: * * 1 n 1 s t n * 1 1 . . . . . . . . 1 1 . . . . . . . . * . 1 . . . . . . . . 1 . . . . . . . * . . 1 . . . . . . s . . 1 . . . . . . * p . x x 1 . x . x . . . . 1 . . . . . * . . . . 1 . . . . . . . . 1 . . . . * . . . . . 1 . . . . . . . . 1 . . . * . . . . . . 1 . . t . . x x x x 1 . . * . . . . . . . 1 . . . . . . . . 1 . * n . . . . . . . . 1 n . . . . . . . . 1 * * H[k] inv(P) * H[k] * P * * If, however, s = t, no elimination is needed, in which case no new * row-like factor is created. * * REFERENCES * * 1. J.J.H.Forrest and J.A.Tomlin, "Updated triangular factors of the * basis to maintain sparsity in the product form simplex method," * Math. Prog. 2 (1972), pp. 263-78. */ int fhv_ft_update(FHV *fhv, int q, int aq_len, const int aq_ind[], const double aq_val[], int ind[/*1+n*/], double val[/*1+n*/], double work[/*1+n*/]) { LUF *luf = fhv->luf; int n = luf->n; SVA *sva = luf->sva; int *sv_ind = sva->ind; double *sv_val = sva->val; int vr_ref = luf->vr_ref; int *vr_ptr = &sva->ptr[vr_ref-1]; int *vr_len = &sva->len[vr_ref-1]; int *vr_cap = &sva->cap[vr_ref-1]; double *vr_piv = luf->vr_piv; int vc_ref = luf->vc_ref; int *vc_ptr = &sva->ptr[vc_ref-1]; int *vc_len = &sva->len[vc_ref-1]; int *vc_cap = &sva->cap[vc_ref-1]; int *pp_ind = luf->pp_ind; int *pp_inv = luf->pp_inv; int *qq_ind = luf->qq_ind; int *qq_inv = luf->qq_inv; int *hh_ind = fhv->hh_ind; int hh_ref = fhv->hh_ref; int *hh_ptr = &sva->ptr[hh_ref-1]; int *hh_len = &sva->len[hh_ref-1]; #if 1 /* FIXME */ const double eps_tol = DBL_EPSILON; const double vpq_tol = 1e-5; const double err_tol = 1e-10; #endif int end, i, i_end, i_ptr, j, j_end, j_ptr, k, len, nnz, p, p_end, p_ptr, ptr, q_end, q_ptr, s, t; double f, vpq, temp; /*--------------------------------------------------------------*/ /* replace current q-th column of matrix V by new one */ /*--------------------------------------------------------------*/ xassert(1 <= q && q <= n); /* convert new q-th column of matrix A to dense format */ for (i = 1; i <= n; i++) val[i] = 0.0; xassert(0 <= aq_len && aq_len <= n); for (k = 1; k <= aq_len; k++) { i = aq_ind[k]; xassert(1 <= i && i <= n); xassert(val[i] == 0.0); xassert(aq_val[k] != 0.0); val[i] = aq_val[k]; } /* compute new q-th column of matrix V: * new V[q] = inv(F * H) * (new A[q]) */ luf->pp_ind = fhv->p0_ind; luf->pp_inv = fhv->p0_inv; luf_f_solve(luf, val); luf->pp_ind = pp_ind; luf->pp_inv = pp_inv; fhv_h_solve(fhv, val); /* q-th column of V = s-th column of U */ s = qq_inv[q]; /* determine row number of element v[p,q] that corresponds to * diagonal element u[s,s] */ p = pp_inv[s]; /* convert new q-th column of V to sparse format; * element v[p,q] = u[s,s] is not included in the element list * and stored separately */ vpq = 0.0; len = 0; for (i = 1; i <= n; i++) { temp = val[i]; #if 1 /* FIXME */ if (-eps_tol < temp && temp < +eps_tol) #endif /* nop */; else if (i == p) vpq = temp; else { ind[++len] = i; val[len] = temp; } } /* clear q-th column of matrix V */ for (q_end = (q_ptr = vc_ptr[q]) + vc_len[q]; q_ptr < q_end; q_ptr++) { /* get row index of v[i,q] */ i = sv_ind[q_ptr]; /* find and remove v[i,q] from i-th row */ for (i_end = (i_ptr = vr_ptr[i]) + vr_len[i]; sv_ind[i_ptr] != q; i_ptr++) /* nop */; xassert(i_ptr < i_end); sv_ind[i_ptr] = sv_ind[i_end-1]; sv_val[i_ptr] = sv_val[i_end-1]; vr_len[i]--; } /* now q-th column of matrix V is empty */ vc_len[q] = 0; /* put new q-th column of V (except element v[p,q] = u[s,s]) in * column-wise format */ if (len > 0) { if (vc_cap[q] < len) { if (sva->r_ptr - sva->m_ptr < len) { sva_more_space(sva, len); sv_ind = sva->ind; sv_val = sva->val; } sva_enlarge_cap(sva, vc_ref-1+q, len, 0); } ptr = vc_ptr[q]; memcpy(&sv_ind[ptr], &ind[1], len * sizeof(int)); memcpy(&sv_val[ptr], &val[1], len * sizeof(double)); vc_len[q] = len; } /* put new q-th column of V (except element v[p,q] = u[s,s]) in * row-wise format, and determine largest row number t such that * u[s,t] != 0 */ t = (vpq == 0.0 ? 0 : s); for (k = 1; k <= len; k++) { /* get row index of v[i,q] */ i = ind[k]; /* put v[i,q] to i-th row */ if (vr_cap[i] == vr_len[i]) { /* reserve extra locations in i-th row to reduce further * relocations of that row */ #if 1 /* FIXME */ int need = vr_len[i] + 5; #endif if (sva->r_ptr - sva->m_ptr < need) { sva_more_space(sva, need); sv_ind = sva->ind; sv_val = sva->val; } sva_enlarge_cap(sva, vr_ref-1+i, need, 0); } sv_ind[ptr = vr_ptr[i] + (vr_len[i]++)] = q; sv_val[ptr] = val[k]; /* v[i,q] is non-zero; increase t */ if (t < pp_ind[i]) t = pp_ind[i]; } /*--------------------------------------------------------------*/ /* check if matrix U is already upper triangular */ /*--------------------------------------------------------------*/ /* check if there is a spike in s-th column of matrix U, which * is q-th column of matrix V */ if (s >= t) { /* no spike; matrix U is already upper triangular */ /* store its diagonal element u[s,s] = v[p,q] */ vr_piv[p] = vpq; if (s > t) { /* matrix U is structurally singular, because its diagonal * element u[s,s] = v[p,q] is exact zero */ xassert(vpq == 0.0); return 1; } #if 1 /* FIXME */ else if (-vpq_tol < vpq && vpq < +vpq_tol) #endif { /* matrix U is not well conditioned, because its diagonal * element u[s,s] = v[p,q] is too small in magnitude */ return 2; } else { /* normal case */ return 0; } } /*--------------------------------------------------------------*/ /* perform implicit symmetric permutations of rows and columns */ /* of matrix U */ /*--------------------------------------------------------------*/ /* currently v[p,q] = u[s,s] */ xassert(p == pp_inv[s] && q == qq_ind[s]); for (k = s; k < t; k++) { pp_ind[pp_inv[k] = pp_inv[k+1]] = k; qq_inv[qq_ind[k] = qq_ind[k+1]] = k; } /* now v[p,q] = u[t,t] */ pp_ind[pp_inv[t] = p] = qq_inv[qq_ind[t] = q] = t; /*--------------------------------------------------------------*/ /* check if matrix U is already upper triangular */ /*--------------------------------------------------------------*/ /* check if there is a spike in t-th row of matrix U, which is * p-th row of matrix V */ for (p_end = (p_ptr = vr_ptr[p]) + vr_len[p]; p_ptr < p_end; p_ptr++) { if (qq_inv[sv_ind[p_ptr]] < t) break; /* spike detected */ } if (p_ptr == p_end) { /* no spike; matrix U is already upper triangular */ /* store its diagonal element u[t,t] = v[p,q] */ vr_piv[p] = vpq; #if 1 /* FIXME */ if (-vpq_tol < vpq && vpq < +vpq_tol) #endif { /* matrix U is not well conditioned, because its diagonal * element u[t,t] = v[p,q] is too small in magnitude */ return 2; } else { /* normal case */ return 0; } } /*--------------------------------------------------------------*/ /* copy p-th row of matrix V, which is t-th row of matrix U, to */ /* working array */ /*--------------------------------------------------------------*/ /* copy p-th row of matrix V, including element v[p,q] = u[t,t], * to the working array in dense format and remove these elements * from matrix V; since no pivoting is used, only this row will * change during elimination */ for (j = 1; j <= n; j++) work[j] = 0.0; work[q] = vpq; for (p_end = (p_ptr = vr_ptr[p]) + vr_len[p]; p_ptr < p_end; p_ptr++) { /* get column index of v[p,j] and store this element to the * working array */ work[j = sv_ind[p_ptr]] = sv_val[p_ptr]; /* find and remove v[p,j] from j-th column */ for (j_end = (j_ptr = vc_ptr[j]) + vc_len[j]; sv_ind[j_ptr] != p; j_ptr++) /* nop */; xassert(j_ptr < j_end); sv_ind[j_ptr] = sv_ind[j_end-1]; sv_val[j_ptr] = sv_val[j_end-1]; vc_len[j]--; } /* now p-th row of matrix V is temporarily empty */ vr_len[p] = 0; /*--------------------------------------------------------------*/ /* perform gaussian elimination */ /*--------------------------------------------------------------*/ /* transform p-th row of matrix V stored in working array, which * is t-th row of matrix U, to eliminate subdiagonal elements * u[t,s], ..., u[t,t-1]; corresponding gaussian multipliers will * form non-trivial row of new row-like factor */ nnz = 0; /* number of non-zero gaussian multipliers */ for (k = s; k < t; k++) { /* diagonal element u[k,k] = v[i,j] is used as pivot */ i = pp_inv[k], j = qq_ind[k]; /* take subdiagonal element u[t,k] = v[p,j] */ temp = work[j]; #if 1 /* FIXME */ if (-eps_tol < temp && temp < +eps_tol) continue; #endif /* compute and save gaussian multiplier: * f := u[t,k] / u[k,k] = v[p,j] / v[i,j] */ ind[++nnz] = i; val[nnz] = f = work[j] / vr_piv[i]; /* gaussian transformation to eliminate u[t,k] = v[p,j]: * (p-th row of V) := (p-th row of V) - f * (i-th row of V) */ for (i_end = (i_ptr = vr_ptr[i]) + vr_len[i]; i_ptr < i_end; i_ptr++) work[sv_ind[i_ptr]] -= f * sv_val[i_ptr]; } /* now matrix U is again upper triangular */ #if 1 /* FIXME */ if (-vpq_tol < work[q] && work[q] < +vpq_tol) #endif { /* however, its new diagonal element u[t,t] = v[p,q] is too * small in magnitude */ return 3; } /*--------------------------------------------------------------*/ /* create new row-like factor H[k] and add to eta file H */ /*--------------------------------------------------------------*/ /* (nnz = 0 means that all subdiagonal elements were too small * in magnitude) */ if (nnz > 0) { if (fhv->nfs == fhv->nfs_max) { /* maximal number of row-like factors has been reached */ return 4; } k = ++(fhv->nfs); hh_ind[k] = p; /* store non-trivial row of H[k] in right (dynamic) part of * SVA (diagonal unity element is not stored) */ if (sva->r_ptr - sva->m_ptr < nnz) { sva_more_space(sva, nnz); sv_ind = sva->ind; sv_val = sva->val; } sva_reserve_cap(sva, fhv->hh_ref-1+k, nnz); ptr = hh_ptr[k]; memcpy(&sv_ind[ptr], &ind[1], nnz * sizeof(int)); memcpy(&sv_val[ptr], &val[1], nnz * sizeof(double)); hh_len[k] = nnz; } /*--------------------------------------------------------------*/ /* copy transformed p-th row of matrix V, which is t-th row of */ /* matrix U, from working array back to matrix V */ /*--------------------------------------------------------------*/ /* copy elements of transformed p-th row of matrix V, which are * non-diagonal elements u[t,t+1], ..., u[t,n] of matrix U, from * working array to corresponding columns of matrix V (note that * diagonal element u[t,t] = v[p,q] not copied); also transform * p-th row of matrix V to sparse format */ len = 0; for (k = t+1; k <= n; k++) { /* j-th column of V = k-th column of U */ j = qq_ind[k]; /* take non-diagonal element v[p,j] = u[t,k] */ temp = work[j]; #if 1 /* FIXME */ if (-eps_tol < temp && temp < +eps_tol) continue; #endif /* add v[p,j] to j-th column of matrix V */ if (vc_cap[j] == vc_len[j]) { /* reserve extra locations in j-th column to reduce further * relocations of that column */ #if 1 /* FIXME */ int need = vc_len[j] + 5; #endif if (sva->r_ptr - sva->m_ptr < need) { sva_more_space(sva, need); sv_ind = sva->ind; sv_val = sva->val; } sva_enlarge_cap(sva, vc_ref-1+j, need, 0); } sv_ind[ptr = vc_ptr[j] + (vc_len[j]++)] = p; sv_val[ptr] = temp; /* store element v[p,j] = u[t,k] to working sparse vector */ ind[++len] = j; val[len] = temp; } /* copy elements from working sparse vector to p-th row of matrix * V (this row is currently empty) */ if (vr_cap[p] < len) { if (sva->r_ptr - sva->m_ptr < len) { sva_more_space(sva, len); sv_ind = sva->ind; sv_val = sva->val; } sva_enlarge_cap(sva, vr_ref-1+p, len, 0); } ptr = vr_ptr[p]; memcpy(&sv_ind[ptr], &ind[1], len * sizeof(int)); memcpy(&sv_val[ptr], &val[1], len * sizeof(double)); vr_len[p] = len; /* store new diagonal element u[t,t] = v[p,q] */ vr_piv[p] = work[q]; /*--------------------------------------------------------------*/ /* perform accuracy test (only if new H[k] was added) */ /*--------------------------------------------------------------*/ if (nnz > 0) { /* copy p-th (non-trivial) row of row-like factor H[k] (except * unity diagonal element) to working array in dense format */ for (j = 1; j <= n; j++) work[j] = 0.0; k = fhv->nfs; for (end = (ptr = hh_ptr[k]) + hh_len[k]; ptr < end; ptr++) work[sv_ind[ptr]] = sv_val[ptr]; /* compute inner product of p-th (non-trivial) row of matrix * H[k] and q-th column of matrix V */ temp = vr_piv[p]; /* 1 * v[p,q] */ ptr = vc_ptr[q]; end = ptr + vc_len[q]; for (; ptr < end; ptr++) temp += work[sv_ind[ptr]] * sv_val[ptr]; /* inner product should be equal to element v[p,q] *before* * matrix V was transformed */ /* compute relative error */ temp = fabs(vpq - temp) / (1.0 + fabs(vpq)); #if 1 /* FIXME */ if (temp > err_tol) #endif { /* relative error is too large */ return 5; } } /* factorization has been successfully updated */ return 0; } /*********************************************************************** * fhv_h_solve - solve system H * x = b * * This routine solves the system H * x = b, where the matrix H is the * middle factor of the sparse updatable FHV-factorization. * * On entry the array x should contain elements of the right-hand side * vector b in locations x[1], ..., x[n], where n is the order of the * matrix F. On exit this array will contain elements of the solution * vector x in the same locations. */ void fhv_h_solve(FHV *fhv, double x[/*1+n*/]) { SVA *sva = fhv->luf->sva; int *sv_ind = sva->ind; double *sv_val = sva->val; int nfs = fhv->nfs; int *hh_ind = fhv->hh_ind; int hh_ref = fhv->hh_ref; int *hh_ptr = &sva->ptr[hh_ref-1]; int *hh_len = &sva->len[hh_ref-1]; int i, k, end, ptr; double x_i; for (k = 1; k <= nfs; k++) { x_i = x[i = hh_ind[k]]; for (end = (ptr = hh_ptr[k]) + hh_len[k]; ptr < end; ptr++) x_i -= sv_val[ptr] * x[sv_ind[ptr]]; x[i] = x_i; } return; } /*********************************************************************** * fhv_ht_solve - solve system H' * x = b * * This routine solves the system H' * x = b, where H' is a matrix * transposed to the matrix H, which is the middle factor of the sparse * updatable FHV-factorization. * * On entry the array x should contain elements of the right-hand side * vector b in locations x[1], ..., x[n], where n is the order of the * matrix F. On exit this array will contain elements of the solution * vector x in the same locations. */ void fhv_ht_solve(FHV *fhv, double x[/*1+n*/]) { SVA *sva = fhv->luf->sva; int *sv_ind = sva->ind; double *sv_val = sva->val; int nfs = fhv->nfs; int *hh_ind = fhv->hh_ind; int hh_ref = fhv->hh_ref; int *hh_ptr = &sva->ptr[hh_ref-1]; int *hh_len = &sva->len[hh_ref-1]; int k, end, ptr; double x_j; for (k = nfs; k >= 1; k--) { if ((x_j = x[hh_ind[k]]) == 0.0) continue; for (end = (ptr = hh_ptr[k]) + hh_len[k]; ptr < end; ptr++) x[sv_ind[ptr]] -= sv_val[ptr] * x_j; } return; } /* eof */ Rglpk/src/GLPK/glprgr.h0000644000176000001440000000246112245352174014363 0ustar ripleyusers/* glprgr.h (raster graphics) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef GLPRGR_H #define GLPRGR_H #define rgr_write_bmp16 _glp_rgr_write_bmp16 int rgr_write_bmp16(const char *fname, int m, int n, const char map[]); /* write 16-color raster image in BMP file format */ #endif /* eof */ Rglpk/src/GLPK/glpapi09.c0000644000176000001440000006163212245352174014513 0ustar ripleyusers/* glpapi09.c (mixed integer programming routines) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpios.h" #include "glpnpp.h" /*********************************************************************** * NAME * * glp_set_col_kind - set (change) column kind * * SYNOPSIS * * void glp_set_col_kind(glp_prob *mip, int j, int kind); * * DESCRIPTION * * The routine glp_set_col_kind sets (changes) the kind of j-th column * (structural variable) as specified by the parameter kind: * * GLP_CV - continuous variable; * GLP_IV - integer variable; * GLP_BV - binary variable. */ void glp_set_col_kind(glp_prob *mip, int j, int kind) { GLPCOL *col; if (!(1 <= j && j <= mip->n)) xerror("glp_set_col_kind: j = %d; column number out of range\n" , j); col = mip->col[j]; switch (kind) { case GLP_CV: col->kind = GLP_CV; break; case GLP_IV: col->kind = GLP_IV; break; case GLP_BV: col->kind = GLP_IV; if (!(col->type == GLP_DB && col->lb == 0.0 && col->ub == 1.0)) glp_set_col_bnds(mip, j, GLP_DB, 0.0, 1.0); break; default: xerror("glp_set_col_kind: j = %d; kind = %d; invalid column" " kind\n", j, kind); } return; } /*********************************************************************** * NAME * * glp_get_col_kind - retrieve column kind * * SYNOPSIS * * int glp_get_col_kind(glp_prob *mip, int j); * * RETURNS * * The routine glp_get_col_kind returns the kind of j-th column, i.e. * the kind of corresponding structural variable, as follows: * * GLP_CV - continuous variable; * GLP_IV - integer variable; * GLP_BV - binary variable */ int glp_get_col_kind(glp_prob *mip, int j) { GLPCOL *col; int kind; if (!(1 <= j && j <= mip->n)) xerror("glp_get_col_kind: j = %d; column number out of range\n" , j); col = mip->col[j]; kind = col->kind; switch (kind) { case GLP_CV: break; case GLP_IV: if (col->type == GLP_DB && col->lb == 0.0 && col->ub == 1.0) kind = GLP_BV; break; default: xassert(kind != kind); } return kind; } /*********************************************************************** * NAME * * glp_get_num_int - retrieve number of integer columns * * SYNOPSIS * * int glp_get_num_int(glp_prob *mip); * * RETURNS * * The routine glp_get_num_int returns the current number of columns, * which are marked as integer. */ int glp_get_num_int(glp_prob *mip) { GLPCOL *col; int j, count = 0; for (j = 1; j <= mip->n; j++) { col = mip->col[j]; if (col->kind == GLP_IV) count++; } return count; } /*********************************************************************** * NAME * * glp_get_num_bin - retrieve number of binary columns * * SYNOPSIS * * int glp_get_num_bin(glp_prob *mip); * * RETURNS * * The routine glp_get_num_bin returns the current number of columns, * which are marked as binary. */ int glp_get_num_bin(glp_prob *mip) { GLPCOL *col; int j, count = 0; for (j = 1; j <= mip->n; j++) { col = mip->col[j]; if (col->kind == GLP_IV && col->type == GLP_DB && col->lb == 0.0 && col->ub == 1.0) count++; } return count; } /*********************************************************************** * NAME * * glp_intopt - solve MIP problem with the branch-and-bound method * * SYNOPSIS * * int glp_intopt(glp_prob *P, const glp_iocp *parm); * * DESCRIPTION * * The routine glp_intopt is a driver to the MIP solver based on the * branch-and-bound method. * * On entry the problem object should contain optimal solution to LP * relaxation (which can be obtained with the routine glp_simplex). * * The MIP solver has a set of control parameters. Values of the control * parameters can be passed in a structure glp_iocp, which the parameter * parm points to. * * The parameter parm can be specified as NULL, in which case the MIP * solver uses default settings. * * RETURNS * * 0 The MIP problem instance has been successfully solved. This code * does not necessarily mean that the solver has found optimal * solution. It only means that the solution process was successful. * * GLP_EBOUND * Unable to start the search, because some double-bounded variables * have incorrect bounds or some integer variables have non-integer * (fractional) bounds. * * GLP_EROOT * Unable to start the search, because optimal basis for initial LP * relaxation is not provided. * * GLP_EFAIL * The search was prematurely terminated due to the solver failure. * * GLP_EMIPGAP * The search was prematurely terminated, because the relative mip * gap tolerance has been reached. * * GLP_ETMLIM * The search was prematurely terminated, because the time limit has * been exceeded. * * GLP_ENOPFS * The MIP problem instance has no primal feasible solution (only if * the MIP presolver is used). * * GLP_ENODFS * LP relaxation of the MIP problem instance has no dual feasible * solution (only if the MIP presolver is used). * * GLP_ESTOP * The search was prematurely terminated by application. */ #if 0 /* 11/VII-2013 */ static int solve_mip(glp_prob *P, const glp_iocp *parm) #else static int solve_mip(glp_prob *P, const glp_iocp *parm, glp_prob *P0 /* problem passed to glp_intopt */, NPP *npp /* preprocessor workspace or NULL */) #endif { /* solve MIP directly without using the preprocessor */ glp_tree *T; int ret; /* optimal basis to LP relaxation must be provided */ if (glp_get_status(P) != GLP_OPT) { if (parm->msg_lev >= GLP_MSG_ERR) xprintf("glp_intopt: optimal basis to initial LP relaxation" " not provided\n"); ret = GLP_EROOT; goto done; } /* it seems all is ok */ if (parm->msg_lev >= GLP_MSG_ALL) xprintf("Integer optimization begins...\n"); /* create the branch-and-bound tree */ T = ios_create_tree(P, parm); #if 1 /* 11/VII-2013 */ T->P = P0; T->npp = npp; #endif /* solve the problem instance */ ret = ios_driver(T); /* delete the branch-and-bound tree */ ios_delete_tree(T); /* analyze exit code reported by the mip driver */ if (ret == 0) { if (P->mip_stat == GLP_FEAS) { if (parm->msg_lev >= GLP_MSG_ALL) xprintf("INTEGER OPTIMAL SOLUTION FOUND\n"); P->mip_stat = GLP_OPT; } else { if (parm->msg_lev >= GLP_MSG_ALL) xprintf("PROBLEM HAS NO INTEGER FEASIBLE SOLUTION\n"); P->mip_stat = GLP_NOFEAS; } } else if (ret == GLP_EMIPGAP) { if (parm->msg_lev >= GLP_MSG_ALL) xprintf("RELATIVE MIP GAP TOLERANCE REACHED; SEARCH TERMINA" "TED\n"); } else if (ret == GLP_ETMLIM) { if (parm->msg_lev >= GLP_MSG_ALL) xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n"); } else if (ret == GLP_EFAIL) { if (parm->msg_lev >= GLP_MSG_ERR) xprintf("glp_intopt: cannot solve current LP relaxation\n"); } else if (ret == GLP_ESTOP) { if (parm->msg_lev >= GLP_MSG_ALL) xprintf("SEARCH TERMINATED BY APPLICATION\n"); } else xassert(ret != ret); done: return ret; } static int preprocess_and_solve_mip(glp_prob *P, const glp_iocp *parm) { /* solve MIP using the preprocessor */ ENV *env = get_env_ptr(); int term_out = env->term_out; NPP *npp; glp_prob *mip = NULL; glp_bfcp bfcp; glp_smcp smcp; int ret; if (parm->msg_lev >= GLP_MSG_ALL) xprintf("Preprocessing...\n"); /* create preprocessor workspace */ npp = npp_create_wksp(); /* load original problem into the preprocessor workspace */ npp_load_prob(npp, P, GLP_OFF, GLP_MIP, GLP_OFF); /* process MIP prior to applying the branch-and-bound method */ if (!term_out || parm->msg_lev < GLP_MSG_ALL) env->term_out = GLP_OFF; else env->term_out = GLP_ON; ret = npp_integer(npp, parm); env->term_out = term_out; if (ret == 0) ; else if (ret == GLP_ENOPFS) { if (parm->msg_lev >= GLP_MSG_ALL) xprintf("PROBLEM HAS NO PRIMAL FEASIBLE SOLUTION\n"); } else if (ret == GLP_ENODFS) { if (parm->msg_lev >= GLP_MSG_ALL) xprintf("LP RELAXATION HAS NO DUAL FEASIBLE SOLUTION\n"); } else xassert(ret != ret); if (ret != 0) goto done; /* build transformed MIP */ mip = glp_create_prob(); npp_build_prob(npp, mip); /* if the transformed MIP is empty, it has empty solution, which is optimal */ if (mip->m == 0 && mip->n == 0) { mip->mip_stat = GLP_OPT; mip->mip_obj = mip->c0; if (parm->msg_lev >= GLP_MSG_ALL) { xprintf("Objective value = %17.9e\n", mip->mip_obj); xprintf("INTEGER OPTIMAL SOLUTION FOUND BY MIP PREPROCESSOR" "\n"); } goto post; } /* display some statistics */ if (parm->msg_lev >= GLP_MSG_ALL) { int ni = glp_get_num_int(mip); int nb = glp_get_num_bin(mip); char s[50]; xprintf("%d row%s, %d column%s, %d non-zero%s\n", mip->m, mip->m == 1 ? "" : "s", mip->n, mip->n == 1 ? "" : "s", mip->nnz, mip->nnz == 1 ? "" : "s"); if (nb == 0) strcpy(s, "none of"); else if (ni == 1 && nb == 1) strcpy(s, ""); else if (nb == 1) strcpy(s, "one of"); else if (nb == ni) strcpy(s, "all of"); else sprintf(s, "%d of", nb); xprintf("%d integer variable%s, %s which %s binary\n", ni, ni == 1 ? "" : "s", s, nb == 1 ? "is" : "are"); } /* inherit basis factorization control parameters */ glp_get_bfcp(P, &bfcp); glp_set_bfcp(mip, &bfcp); /* scale the transformed problem */ if (!term_out || parm->msg_lev < GLP_MSG_ALL) env->term_out = GLP_OFF; else env->term_out = GLP_ON; glp_scale_prob(mip, GLP_SF_GM | GLP_SF_EQ | GLP_SF_2N | GLP_SF_SKIP); env->term_out = term_out; /* build advanced initial basis */ if (!term_out || parm->msg_lev < GLP_MSG_ALL) env->term_out = GLP_OFF; else env->term_out = GLP_ON; glp_adv_basis(mip, 0); env->term_out = term_out; /* solve initial LP relaxation */ if (parm->msg_lev >= GLP_MSG_ALL) xprintf("Solving LP relaxation...\n"); glp_init_smcp(&smcp); smcp.msg_lev = parm->msg_lev; mip->it_cnt = P->it_cnt; ret = glp_simplex(mip, &smcp); P->it_cnt = mip->it_cnt; if (ret != 0) { if (parm->msg_lev >= GLP_MSG_ERR) xprintf("glp_intopt: cannot solve LP relaxation\n"); ret = GLP_EFAIL; goto done; } /* check status of the basic solution */ ret = glp_get_status(mip); if (ret == GLP_OPT) ret = 0; else if (ret == GLP_NOFEAS) ret = GLP_ENOPFS; else if (ret == GLP_UNBND) ret = GLP_ENODFS; else xassert(ret != ret); if (ret != 0) goto done; /* solve the transformed MIP */ mip->it_cnt = P->it_cnt; #if 0 /* 11/VII-2013 */ ret = solve_mip(mip, parm); #else if (parm->use_sol) { mip->mip_stat = P->mip_stat; mip->mip_obj = P->mip_obj; } ret = solve_mip(mip, parm, P, npp); #endif P->it_cnt = mip->it_cnt; /* only integer feasible solution can be postprocessed */ if (!(mip->mip_stat == GLP_OPT || mip->mip_stat == GLP_FEAS)) { P->mip_stat = mip->mip_stat; goto done; } /* postprocess solution from the transformed MIP */ post: npp_postprocess(npp, mip); /* the transformed MIP is no longer needed */ glp_delete_prob(mip), mip = NULL; /* store solution to the original problem */ npp_unload_sol(npp, P); done: /* delete the transformed MIP, if it exists */ if (mip != NULL) glp_delete_prob(mip); /* delete preprocessor workspace */ npp_delete_wksp(npp); return ret; } #ifndef HAVE_ALIEN_SOLVER /* 28/V-2010 */ int _glp_intopt1(glp_prob *P, const glp_iocp *parm) { xassert(P == P); xassert(parm == parm); xprintf("glp_intopt: no alien solver is available\n"); return GLP_EFAIL; } #endif int glp_intopt(glp_prob *P, const glp_iocp *parm) { /* solve MIP problem with the branch-and-bound method */ glp_iocp _parm; int i, j, ret; /* check problem object */ if (P == NULL || P->magic != GLP_PROB_MAGIC) xerror("glp_intopt: P = %p; invalid problem object\n", P); if (P->tree != NULL) xerror("glp_intopt: operation not allowed\n"); /* check control parameters */ if (parm == NULL) parm = &_parm, glp_init_iocp((glp_iocp *)parm); if (!(parm->msg_lev == GLP_MSG_OFF || parm->msg_lev == GLP_MSG_ERR || parm->msg_lev == GLP_MSG_ON || parm->msg_lev == GLP_MSG_ALL || parm->msg_lev == GLP_MSG_DBG)) xerror("glp_intopt: msg_lev = %d; invalid parameter\n", parm->msg_lev); if (!(parm->br_tech == GLP_BR_FFV || parm->br_tech == GLP_BR_LFV || parm->br_tech == GLP_BR_MFV || parm->br_tech == GLP_BR_DTH || parm->br_tech == GLP_BR_PCH)) xerror("glp_intopt: br_tech = %d; invalid parameter\n", parm->br_tech); if (!(parm->bt_tech == GLP_BT_DFS || parm->bt_tech == GLP_BT_BFS || parm->bt_tech == GLP_BT_BLB || parm->bt_tech == GLP_BT_BPH)) xerror("glp_intopt: bt_tech = %d; invalid parameter\n", parm->bt_tech); if (!(0.0 < parm->tol_int && parm->tol_int < 1.0)) xerror("glp_intopt: tol_int = %g; invalid parameter\n", parm->tol_int); if (!(0.0 < parm->tol_obj && parm->tol_obj < 1.0)) xerror("glp_intopt: tol_obj = %g; invalid parameter\n", parm->tol_obj); if (parm->tm_lim < 0) xerror("glp_intopt: tm_lim = %d; invalid parameter\n", parm->tm_lim); if (parm->out_frq < 0) xerror("glp_intopt: out_frq = %d; invalid parameter\n", parm->out_frq); if (parm->out_dly < 0) xerror("glp_intopt: out_dly = %d; invalid parameter\n", parm->out_dly); if (!(0 <= parm->cb_size && parm->cb_size <= 256)) xerror("glp_intopt: cb_size = %d; invalid parameter\n", parm->cb_size); if (!(parm->pp_tech == GLP_PP_NONE || parm->pp_tech == GLP_PP_ROOT || parm->pp_tech == GLP_PP_ALL)) xerror("glp_intopt: pp_tech = %d; invalid parameter\n", parm->pp_tech); if (parm->mip_gap < 0.0) xerror("glp_intopt: mip_gap = %g; invalid parameter\n", parm->mip_gap); if (!(parm->mir_cuts == GLP_ON || parm->mir_cuts == GLP_OFF)) xerror("glp_intopt: mir_cuts = %d; invalid parameter\n", parm->mir_cuts); if (!(parm->gmi_cuts == GLP_ON || parm->gmi_cuts == GLP_OFF)) xerror("glp_intopt: gmi_cuts = %d; invalid parameter\n", parm->gmi_cuts); if (!(parm->cov_cuts == GLP_ON || parm->cov_cuts == GLP_OFF)) xerror("glp_intopt: cov_cuts = %d; invalid parameter\n", parm->cov_cuts); if (!(parm->clq_cuts == GLP_ON || parm->clq_cuts == GLP_OFF)) xerror("glp_intopt: clq_cuts = %d; invalid parameter\n", parm->clq_cuts); if (!(parm->presolve == GLP_ON || parm->presolve == GLP_OFF)) xerror("glp_intopt: presolve = %d; invalid parameter\n", parm->presolve); if (!(parm->binarize == GLP_ON || parm->binarize == GLP_OFF)) xerror("glp_intopt: binarize = %d; invalid parameter\n", parm->binarize); if (!(parm->fp_heur == GLP_ON || parm->fp_heur == GLP_OFF)) xerror("glp_intopt: fp_heur = %d; invalid parameter\n", parm->fp_heur); #if 1 /* 28/V-2010 */ if (!(parm->alien == GLP_ON || parm->alien == GLP_OFF)) xerror("glp_intopt: alien = %d; invalid parameter\n", parm->alien); #endif #if 0 /* 11/VII-2013 */ /* integer solution is currently undefined */ P->mip_stat = GLP_UNDEF; P->mip_obj = 0.0; #else if (!parm->use_sol) P->mip_stat = GLP_UNDEF; if (P->mip_stat == GLP_NOFEAS) P->mip_stat = GLP_UNDEF; if (P->mip_stat == GLP_UNDEF) P->mip_obj = 0.0; else if (P->mip_stat == GLP_OPT) P->mip_stat = GLP_FEAS; #endif /* check bounds of double-bounded variables */ for (i = 1; i <= P->m; i++) { GLPROW *row = P->row[i]; if (row->type == GLP_DB && row->lb >= row->ub) { if (parm->msg_lev >= GLP_MSG_ERR) xprintf("glp_intopt: row %d: lb = %g, ub = %g; incorrect" " bounds\n", i, row->lb, row->ub); ret = GLP_EBOUND; goto done; } } for (j = 1; j <= P->n; j++) { GLPCOL *col = P->col[j]; if (col->type == GLP_DB && col->lb >= col->ub) { if (parm->msg_lev >= GLP_MSG_ERR) xprintf("glp_intopt: column %d: lb = %g, ub = %g; incorr" "ect bounds\n", j, col->lb, col->ub); ret = GLP_EBOUND; goto done; } } /* bounds of all integer variables must be integral */ for (j = 1; j <= P->n; j++) { GLPCOL *col = P->col[j]; if (col->kind != GLP_IV) continue; if (col->type == GLP_LO || col->type == GLP_DB) { if (col->lb != floor(col->lb)) { if (parm->msg_lev >= GLP_MSG_ERR) xprintf("glp_intopt: integer column %d has non-intege" "r lower bound %g\n", j, col->lb); ret = GLP_EBOUND; goto done; } } if (col->type == GLP_UP || col->type == GLP_DB) { if (col->ub != floor(col->ub)) { if (parm->msg_lev >= GLP_MSG_ERR) xprintf("glp_intopt: integer column %d has non-intege" "r upper bound %g\n", j, col->ub); ret = GLP_EBOUND; goto done; } } if (col->type == GLP_FX) { if (col->lb != floor(col->lb)) { if (parm->msg_lev >= GLP_MSG_ERR) xprintf("glp_intopt: integer column %d has non-intege" "r fixed value %g\n", j, col->lb); ret = GLP_EBOUND; goto done; } } } /* solve MIP problem */ if (parm->msg_lev >= GLP_MSG_ALL) { int ni = glp_get_num_int(P); int nb = glp_get_num_bin(P); char s[50]; xprintf("GLPK Integer Optimizer, v%s\n", glp_version()); xprintf("%d row%s, %d column%s, %d non-zero%s\n", P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s", P->nnz, P->nnz == 1 ? "" : "s"); if (nb == 0) strcpy(s, "none of"); else if (ni == 1 && nb == 1) strcpy(s, ""); else if (nb == 1) strcpy(s, "one of"); else if (nb == ni) strcpy(s, "all of"); else sprintf(s, "%d of", nb); xprintf("%d integer variable%s, %s which %s binary\n", ni, ni == 1 ? "" : "s", s, nb == 1 ? "is" : "are"); } #if 1 /* 28/V-2010 */ if (parm->alien) { /* use alien integer optimizer */ ret = _glp_intopt1(P, parm); goto done; } #endif if (!parm->presolve) #if 0 /* 11/VII-2013 */ ret = solve_mip(P, parm); #else ret = solve_mip(P, parm, P, NULL); #endif else ret = preprocess_and_solve_mip(P, parm); done: /* return to the application program */ return ret; } /*********************************************************************** * NAME * * glp_init_iocp - initialize integer optimizer control parameters * * SYNOPSIS * * void glp_init_iocp(glp_iocp *parm); * * DESCRIPTION * * The routine glp_init_iocp initializes control parameters, which are * used by the integer optimizer, with default values. * * Default values of the control parameters are stored in a glp_iocp * structure, which the parameter parm points to. */ void glp_init_iocp(glp_iocp *parm) { parm->msg_lev = GLP_MSG_ALL; parm->br_tech = GLP_BR_DTH; parm->bt_tech = GLP_BT_BLB; parm->tol_int = 1e-5; parm->tol_obj = 1e-7; parm->tm_lim = INT_MAX; parm->out_frq = 5000; parm->out_dly = 10000; parm->cb_func = NULL; parm->cb_info = NULL; parm->cb_size = 0; parm->pp_tech = GLP_PP_ALL; parm->mip_gap = 0.0; parm->mir_cuts = GLP_OFF; parm->gmi_cuts = GLP_OFF; parm->cov_cuts = GLP_OFF; parm->clq_cuts = GLP_OFF; parm->presolve = GLP_OFF; parm->binarize = GLP_OFF; parm->fp_heur = GLP_OFF; #if 1 /* 25/V-2013 */ parm->ps_heur = GLP_OFF; #endif #if 1 /* 29/VI-2013 */ parm->ps_tm_lim = 60000; /* 1 minute */ #endif #if 1 /* 11/VII-2013 */ parm->use_sol = GLP_OFF; parm->save_sol = NULL; #endif #if 1 /* 28/V-2010 */ parm->alien = GLP_OFF; #endif return; } /*********************************************************************** * NAME * * glp_mip_status - retrieve status of MIP solution * * SYNOPSIS * * int glp_mip_status(glp_prob *mip); * * RETURNS * * The routine lpx_mip_status reports the status of MIP solution found * by the branch-and-bound solver as follows: * * GLP_UNDEF - MIP solution is undefined; * GLP_OPT - MIP solution is integer optimal; * GLP_FEAS - MIP solution is integer feasible but its optimality * (or non-optimality) has not been proven, perhaps due to * premature termination of the search; * GLP_NOFEAS - problem has no integer feasible solution (proven by the * solver). */ int glp_mip_status(glp_prob *mip) { int mip_stat = mip->mip_stat; return mip_stat; } /*********************************************************************** * NAME * * glp_mip_obj_val - retrieve objective value (MIP solution) * * SYNOPSIS * * double glp_mip_obj_val(glp_prob *mip); * * RETURNS * * The routine glp_mip_obj_val returns value of the objective function * for MIP solution. */ double glp_mip_obj_val(glp_prob *mip) { /*struct LPXCPS *cps = mip->cps;*/ double z; z = mip->mip_obj; /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/ return z; } /*********************************************************************** * NAME * * glp_mip_row_val - retrieve row value (MIP solution) * * SYNOPSIS * * double glp_mip_row_val(glp_prob *mip, int i); * * RETURNS * * The routine glp_mip_row_val returns value of the auxiliary variable * associated with i-th row. */ double glp_mip_row_val(glp_prob *mip, int i) { /*struct LPXCPS *cps = mip->cps;*/ double mipx; if (!(1 <= i && i <= mip->m)) xerror("glp_mip_row_val: i = %d; row number out of range\n", i) ; mipx = mip->row[i]->mipx; /*if (cps->round && fabs(mipx) < 1e-9) mipx = 0.0;*/ return mipx; } /*********************************************************************** * NAME * * glp_mip_col_val - retrieve column value (MIP solution) * * SYNOPSIS * * double glp_mip_col_val(glp_prob *mip, int j); * * RETURNS * * The routine glp_mip_col_val returns value of the structural variable * associated with j-th column. */ double glp_mip_col_val(glp_prob *mip, int j) { /*struct LPXCPS *cps = mip->cps;*/ double mipx; if (!(1 <= j && j <= mip->n)) xerror("glp_mip_col_val: j = %d; column number out of range\n", j); mipx = mip->col[j]->mipx; /*if (cps->round && fabs(mipx) < 1e-9) mipx = 0.0;*/ return mipx; } /* eof */ Rglpk/src/GLPK/triang.c0000644000176000001440000002775112245352174014356 0ustar ripleyusers/* triang.c (find maximal triangular part of rectangular matrix) */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2012, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "env.h" #include "triang.h" /*********************************************************************** * triang - find maximal triangular part of rectangular matrix * * Given a mxn sparse matrix A this routine finds permutation matrices * P and Q such that matrix A' = P * A * Q has the following structure: * * 1 s n * 1 * . . . . . x x x x x * * * . . . . x x x x x * * * * . . . x x x x x * * * * * . . x x x x x * * * * * * . x x x x x * s * * * * * * x x x x x * x x x x x x x x x x x * x x x x x x x x x x x * m x x x x x x x x x x x * * where '*' are elements of the triangular part, '.' are structural * zeros, 'x' are other elements. * * The formal routine mat specifies the original matrix A in both row- * and column-wise format. If the routine mat is called with k = +i, * 1 <= i <= m, it should store column indices and values of non-zero * elements of i-th row of A in locations ind[1], ..., ind[len] and * val[1], ..., val[len], resp., where len is the returned number of * non-zeros in the row, 0 <= len <= n. Similarly, if the routine mat * is called with k = -j, 1 <= j <= n, it should store row indices and * values of non-zero elements of j-th column of A and return len, the * number of non-zeros in the column, 0 <= len <= m. Should note that * duplicate indices are not allowed. * * The parameter info is a transit pointer passed to the routine mat. * * The parameter tol is a tolerance. The routine triang guarantees that * each diagonal element in the triangular part of matrix A' is not * less in magnitude than tol * max, where max is the maximal magnitude * of elements in corresponding column. * * On exit the routine triang stores information on the triangular part * found in the arrays rn and cn. Elements rn[1], ..., rn[s] specify * row numbers and elements cn[1], ..., cn[s] specify column numbers * of the original matrix A, which correspond to rows/columns 1, ..., s * of matrix A', where s is the size of the triangular part returned by * the routine, 0 <= s <= min(m, n). The order of rows and columns that * are not included in the triangular part remains unspecified. * * ALGORITHM * * The routine triang uses a simple greedy heuristic. * * At some step the matrix A' = P * A * Q has the following structure: * * 1 n * 1 * . . . . . . . x x x * * * . . . . . . x x x * * * * . . . . . x x x * * * * * . . . . x x x * x x x x # # # # x x x * x x x x # # # # x x x * x x x x # # # # x x x * x x x x # # # # x x x * m x x x x # # # # x x x * * where '#' are elements of active submatrix. Initially P = Q = I, so * the active submatrix is the original matrix A = A'. * * If some row has exactly one non-zero in the active submatrix (row * singleton), the routine includes this row and corresponding column * in the triangular part, and removes the column from the active * submatrix. Otherwise, the routine simply removes a column having * maximal number of non-zeros from the active submatrix in the hope * that new row singleton(s) will appear. * * COMPLEXITY * * The time complexity of the routine triang is O(nnz), where nnz is * number of non-zeros in the original matrix A. */ int triang(int m, int n, int (*mat)(void *info, int k, int ind[], double val[]), void *info, double tol, int rn[], int cn[]) { int head, i, j, jj, k, kk, ks, len, len2, next_j, ns, size; int *cind, *rind, *cnt, *ptr, *list, *prev, *next; double *cval, *rval, *big; char *flag; /* allocate working arrays */ cind = talloc(1+m, int); cval = talloc(1+m, double); rind = talloc(1+n, int); rval = talloc(1+n, double); cnt = ptr = talloc(1+m, int); list = talloc(1+n, int); prev = talloc(1+n, int); next = talloc(1+n, int); big = talloc(1+n, double); flag = talloc(1+n, char); /*--------------------------------------------------------------*/ /* build linked lists of columns having equal lengths */ /*--------------------------------------------------------------*/ /* ptr[len], 0 <= len <= m, is number of first column of length * len; * next[j], 1 <= j <= n, is number of next column having the same * length as column j; * big[j], 1 <= j <= n, is maximal magnitude of elements in j-th * column */ for (len = 0; len <= m; len++) ptr[len] = 0; for (j = 1; j <= n; j++) { /* get j-th column */ len = mat(info, -j, cind, cval); xassert(0 <= len && len <= m); /* add this column to beginning of list ptr[len] */ next[j] = ptr[len]; ptr[len] = j; /* determine maximal magnitude of elements in this column */ big[j] = 0.0; for (k = 1; k <= len; k++) { if (big[j] < fabs(cval[k])) big[j] = fabs(cval[k]); } } /*--------------------------------------------------------------*/ /* build doubly linked list of columns ordered by decreasing */ /* column lengths */ /*--------------------------------------------------------------*/ /* head is number of first column in the list; * prev[j], 1 <= j <= n, is number of column that precedes j-th * column in the list; * next[j], 1 <= j <= n, is number of column that follows j-th * column in the list */ head = 0; for (len = 0; len <= m; len++) { /* walk thru list of columns of length len */ for (j = ptr[len]; j != 0; j = next_j) { next_j = next[j]; /* add j-th column to beginning of the column list */ prev[j] = 0; next[j] = head; if (head != 0) prev[head] = j; head = j; } } /*--------------------------------------------------------------*/ /* build initial singleton list */ /*--------------------------------------------------------------*/ /* there are used two list of columns: * 1) doubly linked list of active columns, in which all columns * are ordered by decreasing column lengths; * 2) singleton list; an active column is included in this list * if it has at least one row singleton in active submatrix */ /* flag[j], 1 <= j <= n, is a flag of j-th column: * 0 j-th column is inactive; * 1 j-th column is active; * 2 j-th column is active and has row singleton(s) */ /* initially all columns are active */ for (j = 1; j <= n; j++) flag[j] = 1; /* initialize row counts and build initial singleton list */ /* cnt[i], 1 <= i <= m, is number of non-zeros, which i-th row * has in active submatrix; * ns is size of singleton list; * list[1], ..., list[ns] are numbers of active columns included * in the singleton list */ ns = 0; for (i = 1; i <= m; i++) { /* get i-th row */ len = cnt[i] = mat(info, +i, rind, rval); xassert(0 <= len && len <= n); if (len == 1) { /* a[i,j] is row singleton */ j = rind[1]; xassert(1 <= j && j <= n); if (flag[j] != 2) { /* include j-th column in singleton list */ flag[j] = 2; list[++ns] = j; } } } /*--------------------------------------------------------------*/ /* main loop */ /*--------------------------------------------------------------*/ size = 0; /* size of triangular part */ /* loop until active column list is non-empty, i.e. until the * active submatrix has at least one column */ while (head != 0) { if (ns == 0) { /* singleton list is empty */ /* remove from the active submatrix a column of maximal * length in the hope that some row singletons appear */ j = head; len = mat(info, -j, cind, cval); xassert(0 <= len && len <= m); goto drop; } /* take column j from the singleton list */ j = list[ns--]; xassert(flag[j] == 2); /* j-th column has at least one row singleton in the active * submatrix; choose one having maximal magnitude */ len = mat(info, -j, cind, cval); xassert(0 <= len && len <= m); kk = 0; for (k = 1; k <= len; k++) { i = cind[k]; xassert(1 <= i && i <= m); if (cnt[i] == 1) { /* a[i,j] is row singleton */ if (kk == 0 || fabs(cval[kk]) < fabs(cval[k])) kk = k; } } xassert(kk > 0); /* check magnitude of the row singleton chosen */ if (fabs(cval[kk]) < tol * big[j]) { /* all row singletons are too small in magnitude; drop j-th * column */ goto drop; } /* row singleton a[i,j] is ok; add i-th row and j-th column to * the triangular part */ size++; rn[size] = cind[kk]; cn[size] = j; drop: /* remove j-th column from the active submatrix */ xassert(flag[j]); flag[j] = 0; if (prev[j] == 0) head = next[j]; else next[prev[j]] = next[j]; if (next[j] == 0) ; else prev[next[j]] = prev[j]; /* decrease row counts */ for (k = 1; k <= len; k++) { i = cind[k]; xassert(1 <= i && i <= m); xassert(cnt[i] > 0); cnt[i]--; if (cnt[i] == 1) { /* new singleton appeared in i-th row; determine number * of corresponding column (it is the only active column * in this row) */ len2 = mat(info, +i, rind, rval); xassert(0 <= len2 && len2 <= n); ks = 0; for (kk = 1; kk <= len2; kk++) { jj = rind[kk]; xassert(1 <= jj && jj <= n); if (flag[jj]) { xassert(ks == 0); ks = kk; } } xassert(ks > 0); /* a[i,jj] is new row singleton */ jj = rind[ks]; if (flag[jj] != 2) { /* include jj-th column in the singleton list */ flag[jj] = 2; list[++ns] = jj; } } } } /* now all row counts should be zero */ for (i = 1; i <= m; i++) xassert(cnt[i] == 0); /* deallocate working arrays */ tfree(cind); tfree(cval); tfree(rind); tfree(rval); tfree(ptr); tfree(list); tfree(prev); tfree(next); tfree(big); tfree(flag); return size; } /* eof */ Rglpk/src/GLPK/glpnpp02.c0000644000176000001440000012625012245352174014526 0ustar ripleyusers/* glpnpp02.c */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, * 2009, 2010, 2011, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #include "glpnpp.h" /*********************************************************************** * NAME * * npp_free_row - process free (unbounded) row * * SYNOPSIS * * #include "glpnpp.h" * void npp_free_row(NPP *npp, NPPROW *p); * * DESCRIPTION * * The routine npp_free_row processes row p, which is free (i.e. has * no finite bounds): * * -inf < sum a[p,j] x[j] < +inf. (1) * j * * PROBLEM TRANSFORMATION * * Constraint (1) cannot be active, so it is redundant and can be * removed from the original problem. * * Removing row p leads to removing a column of multiplier pi[p] for * this row in the dual system. Since row p has no bounds, pi[p] = 0, * so removing the column does not affect the dual solution. * * RECOVERING BASIC SOLUTION * * In solution to the original problem row p is inactive constraint, * so it is assigned status GLP_BS, and multiplier pi[p] is assigned * zero value. * * RECOVERING INTERIOR-POINT SOLUTION * * In solution to the original problem row p is inactive constraint, * so its multiplier pi[p] is assigned zero value. * * RECOVERING MIP SOLUTION * * None needed. */ struct free_row { /* free (unbounded) row */ int p; /* row reference number */ }; static int rcv_free_row(NPP *npp, void *info); void npp_free_row(NPP *npp, NPPROW *p) { /* process free (unbounded) row */ struct free_row *info; /* the row must be free */ xassert(p->lb == -DBL_MAX && p->ub == +DBL_MAX); /* create transformation stack entry */ info = npp_push_tse(npp, rcv_free_row, sizeof(struct free_row)); info->p = p->i; /* remove the row from the problem */ npp_del_row(npp, p); return; } static int rcv_free_row(NPP *npp, void *_info) { /* recover free (unbounded) row */ struct free_row *info = _info; if (npp->sol == GLP_SOL) npp->r_stat[info->p] = GLP_BS; if (npp->sol != GLP_MIP) npp->r_pi[info->p] = 0.0; return 0; } /*********************************************************************** * NAME * * npp_geq_row - process row of 'not less than' type * * SYNOPSIS * * #include "glpnpp.h" * void npp_geq_row(NPP *npp, NPPROW *p); * * DESCRIPTION * * The routine npp_geq_row processes row p, which is 'not less than' * inequality constraint: * * L[p] <= sum a[p,j] x[j] (<= U[p]), (1) * j * * where L[p] < U[p], and upper bound may not exist (U[p] = +oo). * * PROBLEM TRANSFORMATION * * Constraint (1) can be replaced by equality constraint: * * sum a[p,j] x[j] - s = L[p], (2) * j * * where * * 0 <= s (<= U[p] - L[p]) (3) * * is a non-negative surplus variable. * * Since in the primal system there appears column s having the only * non-zero coefficient in row p, in the dual system there appears a * new row: * * (-1) pi[p] + lambda = 0, (4) * * where (-1) is coefficient of column s in row p, pi[p] is multiplier * of row p, lambda is multiplier of column q, 0 is coefficient of * column s in the objective row. * * RECOVERING BASIC SOLUTION * * Status of row p in solution to the original problem is determined * by its status and status of column q in solution to the transformed * problem as follows: * * +--------------------------------------+------------------+ * | Transformed problem | Original problem | * +-----------------+--------------------+------------------+ * | Status of row p | Status of column s | Status of row p | * +-----------------+--------------------+------------------+ * | GLP_BS | GLP_BS | N/A | * | GLP_BS | GLP_NL | GLP_BS | * | GLP_BS | GLP_NU | GLP_BS | * | GLP_NS | GLP_BS | GLP_BS | * | GLP_NS | GLP_NL | GLP_NL | * | GLP_NS | GLP_NU | GLP_NU | * +-----------------+--------------------+------------------+ * * Value of row multiplier pi[p] in solution to the original problem * is the same as in solution to the transformed problem. * * 1. In solution to the transformed problem row p and column q cannot * be basic at the same time; otherwise the basis matrix would have * two linear dependent columns: unity column of auxiliary variable * of row p and unity column of variable s. * * 2. Though in the transformed problem row p is equality constraint, * it may be basic due to primal degenerate solution. * * RECOVERING INTERIOR-POINT SOLUTION * * Value of row multiplier pi[p] in solution to the original problem * is the same as in solution to the transformed problem. * * RECOVERING MIP SOLUTION * * None needed. */ struct ineq_row { /* inequality constraint row */ int p; /* row reference number */ int s; /* column reference number for slack/surplus variable */ }; static int rcv_geq_row(NPP *npp, void *info); void npp_geq_row(NPP *npp, NPPROW *p) { /* process row of 'not less than' type */ struct ineq_row *info; NPPCOL *s; /* the row must have lower bound */ xassert(p->lb != -DBL_MAX); xassert(p->lb < p->ub); /* create column for surplus variable */ s = npp_add_col(npp); s->lb = 0.0; s->ub = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub - p->lb); /* and add it to the transformed problem */ npp_add_aij(npp, p, s, -1.0); /* create transformation stack entry */ info = npp_push_tse(npp, rcv_geq_row, sizeof(struct ineq_row)); info->p = p->i; info->s = s->j; /* replace the row by equality constraint */ p->ub = p->lb; return; } static int rcv_geq_row(NPP *npp, void *_info) { /* recover row of 'not less than' type */ struct ineq_row *info = _info; if (npp->sol == GLP_SOL) { if (npp->r_stat[info->p] == GLP_BS) { if (npp->c_stat[info->s] == GLP_BS) { npp_error(); return 1; } else if (npp->c_stat[info->s] == GLP_NL || npp->c_stat[info->s] == GLP_NU) npp->r_stat[info->p] = GLP_BS; else { npp_error(); return 1; } } else if (npp->r_stat[info->p] == GLP_NS) { if (npp->c_stat[info->s] == GLP_BS) npp->r_stat[info->p] = GLP_BS; else if (npp->c_stat[info->s] == GLP_NL) npp->r_stat[info->p] = GLP_NL; else if (npp->c_stat[info->s] == GLP_NU) npp->r_stat[info->p] = GLP_NU; else { npp_error(); return 1; } } else { npp_error(); return 1; } } return 0; } /*********************************************************************** * NAME * * npp_leq_row - process row of 'not greater than' type * * SYNOPSIS * * #include "glpnpp.h" * void npp_leq_row(NPP *npp, NPPROW *p); * * DESCRIPTION * * The routine npp_leq_row processes row p, which is 'not greater than' * inequality constraint: * * (L[p] <=) sum a[p,j] x[j] <= U[p], (1) * j * * where L[p] < U[p], and lower bound may not exist (L[p] = +oo). * * PROBLEM TRANSFORMATION * * Constraint (1) can be replaced by equality constraint: * * sum a[p,j] x[j] + s = L[p], (2) * j * * where * * 0 <= s (<= U[p] - L[p]) (3) * * is a non-negative slack variable. * * Since in the primal system there appears column s having the only * non-zero coefficient in row p, in the dual system there appears a * new row: * * (+1) pi[p] + lambda = 0, (4) * * where (+1) is coefficient of column s in row p, pi[p] is multiplier * of row p, lambda is multiplier of column q, 0 is coefficient of * column s in the objective row. * * RECOVERING BASIC SOLUTION * * Status of row p in solution to the original problem is determined * by its status and status of column q in solution to the transformed * problem as follows: * * +--------------------------------------+------------------+ * | Transformed problem | Original problem | * +-----------------+--------------------+------------------+ * | Status of row p | Status of column s | Status of row p | * +-----------------+--------------------+------------------+ * | GLP_BS | GLP_BS | N/A | * | GLP_BS | GLP_NL | GLP_BS | * | GLP_BS | GLP_NU | GLP_BS | * | GLP_NS | GLP_BS | GLP_BS | * | GLP_NS | GLP_NL | GLP_NU | * | GLP_NS | GLP_NU | GLP_NL | * +-----------------+--------------------+------------------+ * * Value of row multiplier pi[p] in solution to the original problem * is the same as in solution to the transformed problem. * * 1. In solution to the transformed problem row p and column q cannot * be basic at the same time; otherwise the basis matrix would have * two linear dependent columns: unity column of auxiliary variable * of row p and unity column of variable s. * * 2. Though in the transformed problem row p is equality constraint, * it may be basic due to primal degeneracy. * * RECOVERING INTERIOR-POINT SOLUTION * * Value of row multiplier pi[p] in solution to the original problem * is the same as in solution to the transformed problem. * * RECOVERING MIP SOLUTION * * None needed. */ static int rcv_leq_row(NPP *npp, void *info); void npp_leq_row(NPP *npp, NPPROW *p) { /* process row of 'not greater than' type */ struct ineq_row *info; NPPCOL *s; /* the row must have upper bound */ xassert(p->ub != +DBL_MAX); xassert(p->lb < p->ub); /* create column for slack variable */ s = npp_add_col(npp); s->lb = 0.0; s->ub = (p->lb == -DBL_MAX ? +DBL_MAX : p->ub - p->lb); /* and add it to the transformed problem */ npp_add_aij(npp, p, s, +1.0); /* create transformation stack entry */ info = npp_push_tse(npp, rcv_leq_row, sizeof(struct ineq_row)); info->p = p->i; info->s = s->j; /* replace the row by equality constraint */ p->lb = p->ub; return; } static int rcv_leq_row(NPP *npp, void *_info) { /* recover row of 'not greater than' type */ struct ineq_row *info = _info; if (npp->sol == GLP_SOL) { if (npp->r_stat[info->p] == GLP_BS) { if (npp->c_stat[info->s] == GLP_BS) { npp_error(); return 1; } else if (npp->c_stat[info->s] == GLP_NL || npp->c_stat[info->s] == GLP_NU) npp->r_stat[info->p] = GLP_BS; else { npp_error(); return 1; } } else if (npp->r_stat[info->p] == GLP_NS) { if (npp->c_stat[info->s] == GLP_BS) npp->r_stat[info->p] = GLP_BS; else if (npp->c_stat[info->s] == GLP_NL) npp->r_stat[info->p] = GLP_NU; else if (npp->c_stat[info->s] == GLP_NU) npp->r_stat[info->p] = GLP_NL; else { npp_error(); return 1; } } else { npp_error(); return 1; } } return 0; } /*********************************************************************** * NAME * * npp_free_col - process free (unbounded) column * * SYNOPSIS * * #include "glpnpp.h" * void npp_free_col(NPP *npp, NPPCOL *q); * * DESCRIPTION * * The routine npp_free_col processes column q, which is free (i.e. has * no finite bounds): * * -oo < x[q] < +oo. (1) * * PROBLEM TRANSFORMATION * * Free (unbounded) variable can be replaced by the difference of two * non-negative variables: * * x[q] = s' - s'', s', s'' >= 0. (2) * * Assuming that in the transformed problem x[q] becomes s', * transformation (2) causes new column s'' to appear, which differs * from column s' only in the sign of coefficients in constraint and * objective rows. Thus, if in the dual system the following row * corresponds to column s': * * sum a[i,q] pi[i] + lambda' = c[q], (3) * i * * the row which corresponds to column s'' is the following: * * sum (-a[i,q]) pi[i] + lambda'' = -c[q]. (4) * i * * Then from (3) and (4) it follows that: * * lambda' + lambda'' = 0 => lambda' = lmabda'' = 0, (5) * * where lambda' and lambda'' are multipliers for columns s' and s'', * resp. * * RECOVERING BASIC SOLUTION * * With respect to (5) status of column q in solution to the original * problem is determined by statuses of columns s' and s'' in solution * to the transformed problem as follows: * * +--------------------------------------+------------------+ * | Transformed problem | Original problem | * +------------------+-------------------+------------------+ * | Status of col s' | Status of col s'' | Status of col q | * +------------------+-------------------+------------------+ * | GLP_BS | GLP_BS | N/A | * | GLP_BS | GLP_NL | GLP_BS | * | GLP_NL | GLP_BS | GLP_BS | * | GLP_NL | GLP_NL | GLP_NF | * +------------------+-------------------+------------------+ * * Value of column q is computed with formula (2). * * 1. In solution to the transformed problem columns s' and s'' cannot * be basic at the same time, because they differ only in the sign, * hence, are linear dependent. * * 2. Though column q is free, it can be non-basic due to dual * degeneracy. * * 3. If column q is integral, columns s' and s'' are also integral. * * RECOVERING INTERIOR-POINT SOLUTION * * Value of column q is computed with formula (2). * * RECOVERING MIP SOLUTION * * Value of column q is computed with formula (2). */ struct free_col { /* free (unbounded) column */ int q; /* column reference number for variables x[q] and s' */ int s; /* column reference number for variable s'' */ }; static int rcv_free_col(NPP *npp, void *info); void npp_free_col(NPP *npp, NPPCOL *q) { /* process free (unbounded) column */ struct free_col *info; NPPCOL *s; NPPAIJ *aij; /* the column must be free */ xassert(q->lb == -DBL_MAX && q->ub == +DBL_MAX); /* variable x[q] becomes s' */ q->lb = 0.0, q->ub = +DBL_MAX; /* create variable s'' */ s = npp_add_col(npp); s->is_int = q->is_int; s->lb = 0.0, s->ub = +DBL_MAX; /* duplicate objective coefficient */ s->coef = -q->coef; /* duplicate column of the constraint matrix */ for (aij = q->ptr; aij != NULL; aij = aij->c_next) npp_add_aij(npp, aij->row, s, -aij->val); /* create transformation stack entry */ info = npp_push_tse(npp, rcv_free_col, sizeof(struct free_col)); info->q = q->j; info->s = s->j; return; } static int rcv_free_col(NPP *npp, void *_info) { /* recover free (unbounded) column */ struct free_col *info = _info; if (npp->sol == GLP_SOL) { if (npp->c_stat[info->q] == GLP_BS) { if (npp->c_stat[info->s] == GLP_BS) { npp_error(); return 1; } else if (npp->c_stat[info->s] == GLP_NL) npp->c_stat[info->q] = GLP_BS; else { npp_error(); return -1; } } else if (npp->c_stat[info->q] == GLP_NL) { if (npp->c_stat[info->s] == GLP_BS) npp->c_stat[info->q] = GLP_BS; else if (npp->c_stat[info->s] == GLP_NL) npp->c_stat[info->q] = GLP_NF; else { npp_error(); return -1; } } else { npp_error(); return -1; } } /* compute value of x[q] with formula (2) */ npp->c_value[info->q] -= npp->c_value[info->s]; return 0; } /*********************************************************************** * NAME * * npp_lbnd_col - process column with (non-zero) lower bound * * SYNOPSIS * * #include "glpnpp.h" * void npp_lbnd_col(NPP *npp, NPPCOL *q); * * DESCRIPTION * * The routine npp_lbnd_col processes column q, which has (non-zero) * lower bound: * * l[q] <= x[q] (<= u[q]), (1) * * where l[q] < u[q], and upper bound may not exist (u[q] = +oo). * * PROBLEM TRANSFORMATION * * Column q can be replaced as follows: * * x[q] = l[q] + s, (2) * * where * * 0 <= s (<= u[q] - l[q]) (3) * * is a non-negative variable. * * Substituting x[q] from (2) into the objective row, we have: * * z = sum c[j] x[j] + c0 = * j * * = sum c[j] x[j] + c[q] x[q] + c0 = * j!=q * * = sum c[j] x[j] + c[q] (l[q] + s) + c0 = * j!=q * * = sum c[j] x[j] + c[q] s + c~0, * * where * * c~0 = c0 + c[q] l[q] (4) * * is the constant term of the objective in the transformed problem. * Similarly, substituting x[q] into constraint row i, we have: * * L[i] <= sum a[i,j] x[j] <= U[i] ==> * j * * L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==> * j!=q * * L[i] <= sum a[i,j] x[j] + a[i,q] (l[q] + s) <= U[i] ==> * j!=q * * L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i], * j!=q * * where * * L~[i] = L[i] - a[i,q] l[q], U~[i] = U[i] - a[i,q] l[q] (5) * * are lower and upper bounds of row i in the transformed problem, * resp. * * Transformation (2) does not affect the dual system. * * RECOVERING BASIC SOLUTION * * Status of column q in solution to the original problem is the same * as in solution to the transformed problem (GLP_BS, GLP_NL or GLP_NU). * Value of column q is computed with formula (2). * * RECOVERING INTERIOR-POINT SOLUTION * * Value of column q is computed with formula (2). * * RECOVERING MIP SOLUTION * * Value of column q is computed with formula (2). */ struct bnd_col { /* bounded column */ int q; /* column reference number for variables x[q] and s */ double bnd; /* lower/upper bound l[q] or u[q] */ }; static int rcv_lbnd_col(NPP *npp, void *info); void npp_lbnd_col(NPP *npp, NPPCOL *q) { /* process column with (non-zero) lower bound */ struct bnd_col *info; NPPROW *i; NPPAIJ *aij; /* the column must have non-zero lower bound */ xassert(q->lb != 0.0); xassert(q->lb != -DBL_MAX); xassert(q->lb < q->ub); /* create transformation stack entry */ info = npp_push_tse(npp, rcv_lbnd_col, sizeof(struct bnd_col)); info->q = q->j; info->bnd = q->lb; /* substitute x[q] into objective row */ npp->c0 += q->coef * q->lb; /* substitute x[q] into constraint rows */ for (aij = q->ptr; aij != NULL; aij = aij->c_next) { i = aij->row; if (i->lb == i->ub) i->ub = (i->lb -= aij->val * q->lb); else { if (i->lb != -DBL_MAX) i->lb -= aij->val * q->lb; if (i->ub != +DBL_MAX) i->ub -= aij->val * q->lb; } } /* column x[q] becomes column s */ if (q->ub != +DBL_MAX) q->ub -= q->lb; q->lb = 0.0; return; } static int rcv_lbnd_col(NPP *npp, void *_info) { /* recover column with (non-zero) lower bound */ struct bnd_col *info = _info; if (npp->sol == GLP_SOL) { if (npp->c_stat[info->q] == GLP_BS || npp->c_stat[info->q] == GLP_NL || npp->c_stat[info->q] == GLP_NU) npp->c_stat[info->q] = npp->c_stat[info->q]; else { npp_error(); return 1; } } /* compute value of x[q] with formula (2) */ npp->c_value[info->q] = info->bnd + npp->c_value[info->q]; return 0; } /*********************************************************************** * NAME * * npp_ubnd_col - process column with upper bound * * SYNOPSIS * * #include "glpnpp.h" * void npp_ubnd_col(NPP *npp, NPPCOL *q); * * DESCRIPTION * * The routine npp_ubnd_col processes column q, which has upper bound: * * (l[q] <=) x[q] <= u[q], (1) * * where l[q] < u[q], and lower bound may not exist (l[q] = -oo). * * PROBLEM TRANSFORMATION * * Column q can be replaced as follows: * * x[q] = u[q] - s, (2) * * where * * 0 <= s (<= u[q] - l[q]) (3) * * is a non-negative variable. * * Substituting x[q] from (2) into the objective row, we have: * * z = sum c[j] x[j] + c0 = * j * * = sum c[j] x[j] + c[q] x[q] + c0 = * j!=q * * = sum c[j] x[j] + c[q] (u[q] - s) + c0 = * j!=q * * = sum c[j] x[j] - c[q] s + c~0, * * where * * c~0 = c0 + c[q] u[q] (4) * * is the constant term of the objective in the transformed problem. * Similarly, substituting x[q] into constraint row i, we have: * * L[i] <= sum a[i,j] x[j] <= U[i] ==> * j * * L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==> * j!=q * * L[i] <= sum a[i,j] x[j] + a[i,q] (u[q] - s) <= U[i] ==> * j!=q * * L~[i] <= sum a[i,j] x[j] - a[i,q] s <= U~[i], * j!=q * * where * * L~[i] = L[i] - a[i,q] u[q], U~[i] = U[i] - a[i,q] u[q] (5) * * are lower and upper bounds of row i in the transformed problem, * resp. * * Note that in the transformed problem coefficients c[q] and a[i,q] * change their sign. Thus, the row of the dual system corresponding to * column q: * * sum a[i,q] pi[i] + lambda[q] = c[q] (6) * i * * in the transformed problem becomes the following: * * sum (-a[i,q]) pi[i] + lambda[s] = -c[q]. (7) * i * * Therefore: * * lambda[q] = - lambda[s], (8) * * where lambda[q] is multiplier for column q, lambda[s] is multiplier * for column s. * * RECOVERING BASIC SOLUTION * * With respect to (8) status of column q in solution to the original * problem is determined by status of column s in solution to the * transformed problem as follows: * * +-----------------------+--------------------+ * | Status of column s | Status of column q | * | (transformed problem) | (original problem) | * +-----------------------+--------------------+ * | GLP_BS | GLP_BS | * | GLP_NL | GLP_NU | * | GLP_NU | GLP_NL | * +-----------------------+--------------------+ * * Value of column q is computed with formula (2). * * RECOVERING INTERIOR-POINT SOLUTION * * Value of column q is computed with formula (2). * * RECOVERING MIP SOLUTION * * Value of column q is computed with formula (2). */ static int rcv_ubnd_col(NPP *npp, void *info); void npp_ubnd_col(NPP *npp, NPPCOL *q) { /* process column with upper bound */ struct bnd_col *info; NPPROW *i; NPPAIJ *aij; /* the column must have upper bound */ xassert(q->ub != +DBL_MAX); xassert(q->lb < q->ub); /* create transformation stack entry */ info = npp_push_tse(npp, rcv_ubnd_col, sizeof(struct bnd_col)); info->q = q->j; info->bnd = q->ub; /* substitute x[q] into objective row */ npp->c0 += q->coef * q->ub; q->coef = -q->coef; /* substitute x[q] into constraint rows */ for (aij = q->ptr; aij != NULL; aij = aij->c_next) { i = aij->row; if (i->lb == i->ub) i->ub = (i->lb -= aij->val * q->ub); else { if (i->lb != -DBL_MAX) i->lb -= aij->val * q->ub; if (i->ub != +DBL_MAX) i->ub -= aij->val * q->ub; } aij->val = -aij->val; } /* column x[q] becomes column s */ if (q->lb != -DBL_MAX) q->ub -= q->lb; else q->ub = +DBL_MAX; q->lb = 0.0; return; } static int rcv_ubnd_col(NPP *npp, void *_info) { /* recover column with upper bound */ struct bnd_col *info = _info; if (npp->sol == GLP_BS) { if (npp->c_stat[info->q] == GLP_BS) npp->c_stat[info->q] = GLP_BS; else if (npp->c_stat[info->q] == GLP_NL) npp->c_stat[info->q] = GLP_NU; else if (npp->c_stat[info->q] == GLP_NU) npp->c_stat[info->q] = GLP_NL; else { npp_error(); return 1; } } /* compute value of x[q] with formula (2) */ npp->c_value[info->q] = info->bnd - npp->c_value[info->q]; return 0; } /*********************************************************************** * NAME * * npp_dbnd_col - process non-negative column with upper bound * * SYNOPSIS * * #include "glpnpp.h" * void npp_dbnd_col(NPP *npp, NPPCOL *q); * * DESCRIPTION * * The routine npp_dbnd_col processes column q, which is non-negative * and has upper bound: * * 0 <= x[q] <= u[q], (1) * * where u[q] > 0. * * PROBLEM TRANSFORMATION * * Upper bound of column q can be replaced by the following equality * constraint: * * x[q] + s = u[q], (2) * * where s >= 0 is a non-negative complement variable. * * Since in the primal system along with new row (2) there appears a * new column s having the only non-zero coefficient in this row, in * the dual system there appears a new row: * * (+1)pi + lambda[s] = 0, (3) * * where (+1) is coefficient at column s in row (2), pi is multiplier * for row (2), lambda[s] is multiplier for column s, 0 is coefficient * at column s in the objective row. * * RECOVERING BASIC SOLUTION * * Status of column q in solution to the original problem is determined * by its status and status of column s in solution to the transformed * problem as follows: * * +-----------------------------------+------------------+ * | Transformed problem | Original problem | * +-----------------+-----------------+------------------+ * | Status of col q | Status of col s | Status of col q | * +-----------------+-----------------+------------------+ * | GLP_BS | GLP_BS | GLP_BS | * | GLP_BS | GLP_NL | GLP_NU | * | GLP_NL | GLP_BS | GLP_NL | * | GLP_NL | GLP_NL | GLP_NL (*) | * +-----------------+-----------------+------------------+ * * Value of column q in solution to the original problem is the same as * in solution to the transformed problem. * * 1. Formally, in solution to the transformed problem columns q and s * cannot be non-basic at the same time, since the constraint (2) * would be violated. However, if u[q] is close to zero, violation * may be less than a working precision even if both columns q and s * are non-basic. In this degenerate case row (2) can be only basic, * i.e. non-active constraint (otherwise corresponding row of the * basis matrix would be zero). This allows to pivot out auxiliary * variable and pivot in column s, in which case the row becomes * active while column s becomes basic. * * 2. If column q is integral, column s is also integral. * * RECOVERING INTERIOR-POINT SOLUTION * * Value of column q in solution to the original problem is the same as * in solution to the transformed problem. * * RECOVERING MIP SOLUTION * * Value of column q in solution to the original problem is the same as * in solution to the transformed problem. */ struct dbnd_col { /* double-bounded column */ int q; /* column reference number for variable x[q] */ int s; /* column reference number for complement variable s */ }; static int rcv_dbnd_col(NPP *npp, void *info); void npp_dbnd_col(NPP *npp, NPPCOL *q) { /* process non-negative column with upper bound */ struct dbnd_col *info; NPPROW *p; NPPCOL *s; /* the column must be non-negative with upper bound */ xassert(q->lb == 0.0); xassert(q->ub > 0.0); xassert(q->ub != +DBL_MAX); /* create variable s */ s = npp_add_col(npp); s->is_int = q->is_int; s->lb = 0.0, s->ub = +DBL_MAX; /* create equality constraint (2) */ p = npp_add_row(npp); p->lb = p->ub = q->ub; npp_add_aij(npp, p, q, +1.0); npp_add_aij(npp, p, s, +1.0); /* create transformation stack entry */ info = npp_push_tse(npp, rcv_dbnd_col, sizeof(struct dbnd_col)); info->q = q->j; info->s = s->j; /* remove upper bound of x[q] */ q->ub = +DBL_MAX; return; } static int rcv_dbnd_col(NPP *npp, void *_info) { /* recover non-negative column with upper bound */ struct dbnd_col *info = _info; if (npp->sol == GLP_BS) { if (npp->c_stat[info->q] == GLP_BS) { if (npp->c_stat[info->s] == GLP_BS) npp->c_stat[info->q] = GLP_BS; else if (npp->c_stat[info->s] == GLP_NL) npp->c_stat[info->q] = GLP_NU; else { npp_error(); return 1; } } else if (npp->c_stat[info->q] == GLP_NL) { if (npp->c_stat[info->s] == GLP_BS || npp->c_stat[info->s] == GLP_NL) npp->c_stat[info->q] = GLP_NL; else { npp_error(); return 1; } } else { npp_error(); return 1; } } return 0; } /*********************************************************************** * NAME * * npp_fixed_col - process fixed column * * SYNOPSIS * * #include "glpnpp.h" * void npp_fixed_col(NPP *npp, NPPCOL *q); * * DESCRIPTION * * The routine npp_fixed_col processes column q, which is fixed: * * x[q] = s[q], (1) * * where s[q] is a fixed column value. * * PROBLEM TRANSFORMATION * * The value of a fixed column can be substituted into the objective * and constraint rows that allows removing the column from the problem. * * Substituting x[q] = s[q] into the objective row, we have: * * z = sum c[j] x[j] + c0 = * j * * = sum c[j] x[j] + c[q] x[q] + c0 = * j!=q * * = sum c[j] x[j] + c[q] s[q] + c0 = * j!=q * * = sum c[j] x[j] + c~0, * j!=q * * where * * c~0 = c0 + c[q] s[q] (2) * * is the constant term of the objective in the transformed problem. * Similarly, substituting x[q] = s[q] into constraint row i, we have: * * L[i] <= sum a[i,j] x[j] <= U[i] ==> * j * * L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==> * j!=q * * L[i] <= sum a[i,j] x[j] + a[i,q] s[q] <= U[i] ==> * j!=q * * L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i], * j!=q * * where * * L~[i] = L[i] - a[i,q] s[q], U~[i] = U[i] - a[i,q] s[q] (3) * * are lower and upper bounds of row i in the transformed problem, * resp. * * RECOVERING BASIC SOLUTION * * Column q is assigned status GLP_NS and its value is assigned s[q]. * * RECOVERING INTERIOR-POINT SOLUTION * * Value of column q is assigned s[q]. * * RECOVERING MIP SOLUTION * * Value of column q is assigned s[q]. */ struct fixed_col { /* fixed column */ int q; /* column reference number for variable x[q] */ double s; /* value, at which x[q] is fixed */ }; static int rcv_fixed_col(NPP *npp, void *info); void npp_fixed_col(NPP *npp, NPPCOL *q) { /* process fixed column */ struct fixed_col *info; NPPROW *i; NPPAIJ *aij; /* the column must be fixed */ xassert(q->lb == q->ub); /* create transformation stack entry */ info = npp_push_tse(npp, rcv_fixed_col, sizeof(struct fixed_col)); info->q = q->j; info->s = q->lb; /* substitute x[q] = s[q] into objective row */ npp->c0 += q->coef * q->lb; /* substitute x[q] = s[q] into constraint rows */ for (aij = q->ptr; aij != NULL; aij = aij->c_next) { i = aij->row; if (i->lb == i->ub) i->ub = (i->lb -= aij->val * q->lb); else { if (i->lb != -DBL_MAX) i->lb -= aij->val * q->lb; if (i->ub != +DBL_MAX) i->ub -= aij->val * q->lb; } } /* remove the column from the problem */ npp_del_col(npp, q); return; } static int rcv_fixed_col(NPP *npp, void *_info) { /* recover fixed column */ struct fixed_col *info = _info; if (npp->sol == GLP_SOL) npp->c_stat[info->q] = GLP_NS; npp->c_value[info->q] = info->s; return 0; } /*********************************************************************** * NAME * * npp_make_equality - process row with almost identical bounds * * SYNOPSIS * * #include "glpnpp.h" * int npp_make_equality(NPP *npp, NPPROW *p); * * DESCRIPTION * * The routine npp_make_equality processes row p: * * L[p] <= sum a[p,j] x[j] <= U[p], (1) * j * * where -oo < L[p] < U[p] < +oo, i.e. which is double-sided inequality * constraint. * * RETURNS * * 0 - row bounds have not been changed; * * 1 - row has been replaced by equality constraint. * * PROBLEM TRANSFORMATION * * If bounds of row (1) are very close to each other: * * U[p] - L[p] <= eps, (2) * * where eps is an absolute tolerance for row value, the row can be * replaced by the following almost equivalent equiality constraint: * * sum a[p,j] x[j] = b, (3) * j * * where b = (L[p] + U[p]) / 2. If the right-hand side in (3) happens * to be very close to its nearest integer: * * |b - floor(b + 0.5)| <= eps, (4) * * it is reasonable to use this nearest integer as the right-hand side. * * RECOVERING BASIC SOLUTION * * Status of row p in solution to the original problem is determined * by its status and the sign of its multiplier pi[p] in solution to * the transformed problem as follows: * * +-----------------------+---------+--------------------+ * | Status of row p | Sign of | Status of row p | * | (transformed problem) | pi[p] | (original problem) | * +-----------------------+---------+--------------------+ * | GLP_BS | + / - | GLP_BS | * | GLP_NS | + | GLP_NL | * | GLP_NS | - | GLP_NU | * +-----------------------+---------+--------------------+ * * Value of row multiplier pi[p] in solution to the original problem is * the same as in solution to the transformed problem. * * RECOVERING INTERIOR POINT SOLUTION * * Value of row multiplier pi[p] in solution to the original problem is * the same as in solution to the transformed problem. * * RECOVERING MIP SOLUTION * * None needed. */ struct make_equality { /* row with almost identical bounds */ int p; /* row reference number */ }; static int rcv_make_equality(NPP *npp, void *info); int npp_make_equality(NPP *npp, NPPROW *p) { /* process row with almost identical bounds */ struct make_equality *info; double b, eps, nint; /* the row must be double-sided inequality */ xassert(p->lb != -DBL_MAX); xassert(p->ub != +DBL_MAX); xassert(p->lb < p->ub); /* check row bounds */ eps = 1e-9 + 1e-12 * fabs(p->lb); if (p->ub - p->lb > eps) return 0; /* row bounds are very close to each other */ /* create transformation stack entry */ info = npp_push_tse(npp, rcv_make_equality, sizeof(struct make_equality)); info->p = p->i; /* compute right-hand side */ b = 0.5 * (p->ub + p->lb); nint = floor(b + 0.5); if (fabs(b - nint) <= eps) b = nint; /* replace row p by almost equivalent equality constraint */ p->lb = p->ub = b; return 1; } int rcv_make_equality(NPP *npp, void *_info) { /* recover row with almost identical bounds */ struct make_equality *info = _info; if (npp->sol == GLP_SOL) { if (npp->r_stat[info->p] == GLP_BS) npp->r_stat[info->p] = GLP_BS; else if (npp->r_stat[info->p] == GLP_NS) { if (npp->r_pi[info->p] >= 0.0) npp->r_stat[info->p] = GLP_NL; else npp->r_stat[info->p] = GLP_NU; } else { npp_error(); return 1; } } return 0; } /*********************************************************************** * NAME * * npp_make_fixed - process column with almost identical bounds * * SYNOPSIS * * #include "glpnpp.h" * int npp_make_fixed(NPP *npp, NPPCOL *q); * * DESCRIPTION * * The routine npp_make_fixed processes column q: * * l[q] <= x[q] <= u[q], (1) * * where -oo < l[q] < u[q] < +oo, i.e. which has both lower and upper * bounds. * * RETURNS * * 0 - column bounds have not been changed; * * 1 - column has been fixed. * * PROBLEM TRANSFORMATION * * If bounds of column (1) are very close to each other: * * u[q] - l[q] <= eps, (2) * * where eps is an absolute tolerance for column value, the column can * be fixed: * * x[q] = s[q], (3) * * where s[q] = (l[q] + u[q]) / 2. And if the fixed column value s[q] * happens to be very close to its nearest integer: * * |s[q] - floor(s[q] + 0.5)| <= eps, (4) * * it is reasonable to use this nearest integer as the fixed value. * * RECOVERING BASIC SOLUTION * * In the dual system of the original (as well as transformed) problem * column q corresponds to the following row: * * sum a[i,q] pi[i] + lambda[q] = c[q]. (5) * i * * Since multipliers pi[i] are known for all rows from solution to the * transformed problem, formula (5) allows computing value of multiplier * (reduced cost) for column q: * * lambda[q] = c[q] - sum a[i,q] pi[i]. (6) * i * * Status of column q in solution to the original problem is determined * by its status and the sign of its multiplier lambda[q] in solution to * the transformed problem as follows: * * +-----------------------+-----------+--------------------+ * | Status of column q | Sign of | Status of column q | * | (transformed problem) | lambda[q] | (original problem) | * +-----------------------+-----------+--------------------+ * | GLP_BS | + / - | GLP_BS | * | GLP_NS | + | GLP_NL | * | GLP_NS | - | GLP_NU | * +-----------------------+-----------+--------------------+ * * Value of column q in solution to the original problem is the same as * in solution to the transformed problem. * * RECOVERING INTERIOR POINT SOLUTION * * Value of column q in solution to the original problem is the same as * in solution to the transformed problem. * * RECOVERING MIP SOLUTION * * None needed. */ struct make_fixed { /* column with almost identical bounds */ int q; /* column reference number */ double c; /* objective coefficient at x[q] */ NPPLFE *ptr; /* list of non-zero coefficients a[i,q] */ }; static int rcv_make_fixed(NPP *npp, void *info); int npp_make_fixed(NPP *npp, NPPCOL *q) { /* process column with almost identical bounds */ struct make_fixed *info; NPPAIJ *aij; NPPLFE *lfe; double s, eps, nint; /* the column must be double-bounded */ xassert(q->lb != -DBL_MAX); xassert(q->ub != +DBL_MAX); xassert(q->lb < q->ub); /* check column bounds */ eps = 1e-9 + 1e-12 * fabs(q->lb); if (q->ub - q->lb > eps) return 0; /* column bounds are very close to each other */ /* create transformation stack entry */ info = npp_push_tse(npp, rcv_make_fixed, sizeof(struct make_fixed)); info->q = q->j; info->c = q->coef; info->ptr = NULL; /* save column coefficients a[i,q] (needed for basic solution only) */ if (npp->sol == GLP_SOL) { for (aij = q->ptr; aij != NULL; aij = aij->c_next) { lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE)); lfe->ref = aij->row->i; lfe->val = aij->val; lfe->next = info->ptr; info->ptr = lfe; } } /* compute column fixed value */ s = 0.5 * (q->ub + q->lb); nint = floor(s + 0.5); if (fabs(s - nint) <= eps) s = nint; /* make column q fixed */ q->lb = q->ub = s; return 1; } static int rcv_make_fixed(NPP *npp, void *_info) { /* recover column with almost identical bounds */ struct make_fixed *info = _info; NPPLFE *lfe; double lambda; if (npp->sol == GLP_SOL) { if (npp->c_stat[info->q] == GLP_BS) npp->c_stat[info->q] = GLP_BS; else if (npp->c_stat[info->q] == GLP_NS) { /* compute multiplier for column q with formula (6) */ lambda = info->c; for (lfe = info->ptr; lfe != NULL; lfe = lfe->next) lambda -= lfe->val * npp->r_pi[lfe->ref]; /* assign status to non-basic column */ if (lambda >= 0.0) npp->c_stat[info->q] = GLP_NL; else npp->c_stat[info->q] = GLP_NU; } else { npp_error(); return 1; } } return 0; } /* eof */ Rglpk/src/GLPK/mc13d.h0000644000176000001440000000236612245352174014001 0ustar ripleyusers/* mc13d.h */ /*********************************************************************** * This code is part of GLPK (GNU Linear Programming Kit). * * Copyright (C) 2009, 2013 Andrew Makhorin, Department for Applied * Informatics, Moscow Aviation Institute, Moscow, Russia. All rights * reserved. E-mail: . * * 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 . ***********************************************************************/ #ifndef MC13D_H #define MC13D_H #define mc13d _glp_mc13d int mc13d(int n, const int icn[], const int ip[], const int lenr[], int ior[], int ib[], int lowl[], int numb[], int prev[]); /* permutations to block triangular form */ #endif /* eof */ Rglpk/src/Makevars.win0000755000176000001440000000034112245350420014436 0ustar ripleyusers#-*- Makefile -*- # PKG_CPPFLAGS = -IGLPK -IGLPK/amd -IGLPK/colamd -IGLPK/minisat -IGLPK/proxy -IGLPK/zlib PKG_LIBS = GLPK/libglpk.a all: libs $(SHLIB) libs: GLPK/libglpk.a GLPK/libglpk.a: $(MAKE) -C GLPK -f Makefile.win Rglpk/src/Rglpk_initialize.c0000644000176000001440000000110712245352174015620 0ustar ripleyusers#include "Rglpk.h" // Rglpk_print: print hook for redirecting GLPKs terminal output // note: info is not used here static int Rglpk_print(void *info, const char *message){ Rprintf("%s", message); return 1; /* Tell GLPK not to print */ } // Rglpk_initialize is called after loading the dynlib void Rglpk_initialize(void){ // set print hook for terminal glp_term_hook(Rglpk_print, NULL); } // returns the version of the GLPK callable library void Rglpk_get_engine_version(char **GLPK_version){ const char *str; str = glp_version(); *GLPK_version = (char *) str; } Rglpk/NAMESPACE0000644000176000001440000000017112245336313012601 0ustar ripleyusersuseDynLib("Rglpk") import("slam") export("Rglpk_solve_LP") export("Rglpk_read_file") export("print.MP_data_from_file") Rglpk/R/0000755000176000001440000000000012245352174011567 5ustar ripleyusersRglpk/R/Rglpk_solve.R0000644000176000001440000001336012245336313014201 0ustar ripleyusers## the R-ported GNU Linear Programming kit ## solve function --- C Interface Rglpk_solve_LP <- function(obj, mat, dir, rhs, bounds = NULL, types = NULL, max = FALSE, control = list(), ...) { ## validate direction of optimization if(!identical( max, TRUE ) && !identical( max, FALSE )) stop("'Argument 'max' must be either TRUE or FALSE.") direction_of_optimization <- as.integer(max) ## validate control list dots <- list(...) control[names(dots)] <- dots control <- .check_control_parameters( control ) verb <- control$verbose ## match direction of constraints n_of_constraints <- length(dir) ## match relational operators to requested input direction_of_constraints <- match( dir, c("<", "<=", ">", ">=", "==") ) if( any(is.na(direction_of_constraints)) ) stop("Argument 'dir' must be either '<', '<=', '>', '>=' or '=='.") ## we need to verify that obj is a numeric vector ## FIXME: always use STMs? if(slam::is.simple_triplet_matrix(obj)) obj <- as.matrix(obj) obj <- as.numeric(obj) n_of_objective_vars <- length( obj ) constraint_matrix <- as.simple_triplet_matrix(mat) ## types of objective coefficients ## Default: "C" if(is.null(types)) types <- "C" ## check if valid types if(any(is.na(match(types, c("I", "B", "C"), nomatch = NA)))) stop("'types' must be either 'B', 'C' or 'I'.") ## replicate types to fit number of columns types <- rep(types, length.out = n_of_objective_vars) ## need a TRUE/FALSE integer/binary representation integers <- types == "I" binaries <- types == "B" ## do we have a mixed integer linear program? is_integer <- any( binaries | integers ) ## bounds of objective coefficients bounds <- as.glp_bounds( as.list( bounds ), n_of_objective_vars ) ## Sanity check: mat/dir/rhs if( !all(c(dim(mat)[ 1 ], length(rhs)) == n_of_constraints) ) stop( "Arguments 'mat', 'dir', and/or 'rhs' not conformable." ) ## Sanity check: mat, obj if( dim(mat)[ 2 ] != n_of_objective_vars ) stop( "Arguments 'mat' and 'obj' not conformable." ) ## call the C interface - this actually runs the solver x <- glp_call_interface(obj, n_of_objective_vars, constraint_matrix$i, constraint_matrix$j, constraint_matrix$v, length(constraint_matrix$v), rhs, direction_of_constraints, n_of_constraints, is_integer, integers, binaries, direction_of_optimization, bounds[, 1L], bounds[, 2L], bounds[, 3L], verb) solution <- x$lp_objective_vars_values ## are integer variables really integers? better round values solution[integers | binaries] <- round( solution[integers | binaries]) ## match status of solution status <- as.integer(x$lp_status) if(control$canonicalize_status){ ## 0 -> optimal solution (5 in GLPK) else 1 status <- as.integer(status != 5L) } list(optimum = sum(solution * obj), solution = solution, status = status) } ## this function calls the C interface glp_call_interface <- function(lp_objective_coefficients, lp_n_of_objective_vars, lp_constraint_matrix_i, lp_constraint_matrix_j, lp_constraint_matrix_v, lp_n_of_values_in_constraint_matrix, lp_right_hand_side, lp_direction_of_constraints, lp_n_of_constraints, lp_is_integer, lp_objective_var_is_integer, lp_objective_var_is_binary, lp_direction_of_optimization, lp_bounds_type, lp_bounds_lower, lp_bounds_upper, verbose) { out <- .C("R_glp_solve", lp_direction_of_optimization= as.integer(lp_direction_of_optimization), lp_n_of_constraints = as.integer(lp_n_of_constraints), lp_direction_of_constraints = as.integer(lp_direction_of_constraints), lp_right_hand_side = as.double(lp_right_hand_side), lp_n_of_objective_vars = as.integer(lp_n_of_objective_vars), lp_objective_coefficients = as.double(lp_objective_coefficients), lp_objective_var_is_integer = as.integer(lp_objective_var_is_integer), lp_objective_var_is_binary = as.integer(lp_objective_var_is_binary), lp_is_integer = as.integer(lp_is_integer), lp_n_of_values_in_constraint_matrix = as.integer(lp_n_of_values_in_constraint_matrix), lp_constraint_matrix_i = as.integer(lp_constraint_matrix_i), lp_constraint_matrix_j = as.integer(lp_constraint_matrix_j), lp_constraint_matrix_values = as.double(lp_constraint_matrix_v), lp_bounds_type = as.integer(lp_bounds_type), lp_bounds_lower = as.double(lp_bounds_lower), ## lp_n_of_bounds_l = as.integer(length(lp_lower_bounds_i)), lp_bounds_upper = as.double(lp_bounds_upper), ## lp_n_of_bounds_u = as.integer(length(lp_upper_bounds_i)), lp_optimum = double(1), lp_objective_vars_values = double(lp_n_of_objective_vars), lp_verbosity = as.integer(verbose), lp_status = integer(1), NAOK = TRUE, PACKAGE = "Rglpk") out } ## Convenience function for solving MILP objects ## upcoming ROI package (or for solving problems read with filereader) .ROI_glpk_solve <- function(x, control = list()){ if(!inherits(x, "MILP")) stop("'x' must be of class 'MILP'") if(is.null(control$verbose)) control$verbose <- FALSE Rglpk_solve_LP(x$objective, x$constraints[[1]], x$constraints[[2]], x$constraints[[3]], types = x$types, max = x$maximum, bounds = x$bounds, verbose = control$verbose) } Rglpk/R/milp.R0000644000176000001440000000146012245336313012651 0ustar ripleyusers## MILP constructor ## borrowed from KH's relations package ## objective: numeric vector ## constraints: list [[1]] constr_mat ## [[2]] constr_dir, ## [[3]] constr_rhs), ## integers: ## maximum: logical MILP <- function(objective, constraints, bounds = NULL, types = NULL, maximum = FALSE) { ## In the simples case, 'constraints' is a (not necessarily named) ## list with mat, dir and rhs. Advanced solvers might allow for ## more advanced constraints, but let's worry about this later (and ## maybe also a little MILP_constraints() wrapper ...). structure(list(objective = slam::as.simple_triplet_matrix(objective), constraints = constraints, bounds = bounds, types = types, maximum = maximum), class = "MILP") } Rglpk/R/control.R0000644000176000001440000000117612245336313013374 0ustar ripleyusers.check_control_parameters <- function( control ){ stopifnot(is.list(control)) ## Default paramenters (currently only verbosity supported) out <- list(verbose = FALSE, canonicalize_status = TRUE) out[names(control)] <- control if (!is.null(out$verbose)) { out$verbose <- as.integer(out$verbose) if (!out$verbose %in% c(0L, 1L)) { warning("Improper value for 'verbose' parameter. Using default.") out$verbose <- 0L } } if (!is.null(out$canonicalize_status)) { out$canonicalize_status <- as.logical(out$canonicalize_status) } out } Rglpk/R/Misc.R0000644000176000001440000000247712245336313012614 0ustar ripleyusers## Miscellaneous functions used in this package ## Get the right representation of integer vector. ## This function takes an index vector and returns a vector of logicals ## with length 'n'. #glp_integers <- #function(x, n) #{ # if(!all(x <= n)) #stop("Indices must not exceed the number of objective coefficients.") # out <- logical(n) # out[x] <- TRUE # out #} print.MP_data_from_file <- function(x, ...){ if(!inherits(x, "MP_data_from_file")) stop("'x' must be of class 'MP_data_from_file'") if(attr(x, "n_integer_vars") > 0L){ writeLines(paste("A mixed integer linear program with", attr(x, "n_objective_vars"), "objective variables,")) writeLines(paste(attr(x, "n_integer_vars"), "are integer and", attr(x, "n_binary_vars"), "of which are binary variables.")) writeLines(paste("This problem has", attr(x, "n_constraints"), "constraints with", attr(x, "n_nonzeros"), "non-zero values in the constraint matrix.")) } else{ writeLines(paste("A linear program with", attr(x, "n_objective_vars"), "objective variables.")) writeLines(paste("This problem has", attr(x, "n_constraints"), "constraints with", attr(x, "n_nonzeros"), "non-zero values in the constraint matrix.")) } } Rglpk/R/bounds.R0000644000176000001440000000601512245336676013217 0ustar ripleyusers## bounds of objective coefficients ## fixes the GLPK bound types given a data.frame with bounds ## GLP_FR 1 free variable ## GLP_LO 2 variable with lower bound ## GLP_UP 3 variable with upper bound ## GLP_DB 4 double-bounded variable ## GLP_FX 5 fixed variable glp_fix_bound_type <- function(x) { if(!inherits(x,"bound_table")) stop("'x' is not of class 'bound_table'") x$type <- ifelse(is.finite(x$lower), ifelse(is.finite(x$upper), 4L, 2L), ifelse(is.finite(x$upper), 3L, 1L)) x$type[x$upper == x$lower] <- 5L x } ## TODO: should be a generic function providing methods for ## different representations (e.g., a matrix, list of vectors, ...) ## ## A generic function which allows to take different dense and sparse ## representations of bounds. as.glp_bounds <- function(x, ...) UseMethod("as.glp_bounds") ## No default representation. as.glp_bounds.default <- function(x) stop("There is no default method for bounds representations.") ## returns identity as.glp_bounds.bound_table <- function(x, n) x ## list -> GLPK bounds representation as.glp_bounds.list <- function(x, n) glp_bounds(x, n) glp_bounds <- function(x, n) { ## General input validation ##if(!is.list(x)) ## stop("Bounds have to be of type list") ## Initialize default matrix bound_table <- expand.grid(type = rep.int(2L, n), lower = 0.0, upper = Inf) class(bound_table) <- c("bound_table", class(bound_table)) ## Lower bounds lower <- x$lower ## check for zero-length bounds if( !any(unlist(lapply(lower, length))) ) lower <- NULL if(!is.null(lower)){ ## input validation glp_bounds_check_sanity(lower, n) if(any(lower[[1L]] == Inf)) stop("Lower bound cannot be 'Inf'") ## if everything is OK set new lower bounds bound_table[lower[[1L]], 2L] <- lower[[2L]] } ## Upper bounds upper <- x$upper ## check for zero-length bounds if( !any(unlist(lapply(upper, length))) ) upper <- NULL if(!is.null(upper)){ ## input validation glp_bounds_check_sanity(upper, n) if(any(upper[[1L]] == -Inf)) stop("Upper bound cannot be '-Inf'") ## so far, the same as with lower bounds but in addition we have to be ## sure that upper bounds are greater than or equal to lower bounds if(any(bound_table[upper[[1L]], 2L] > upper[[2L]])) stop("Upper bounds have to be greater than or equal to lower bounds") bound_table[upper[[1L]], 3L] <- upper[[2L]] } ## Fix bound types out <- glp_fix_bound_type(bound_table) out } glp_bounds_check_sanity <- function(x, n) { if(!is.numeric(x[[1L]])) warning("Bound indices not numeric. Coercing to integers ...") x[[1L]] <- as.integer(x[[1L]]) if(length(x[[1L]]) != length(x[[2L]])) stop("Length of bound indices must be equal to the length of the corresponding bound values.") if(any(duplicated(x[[1L]]))) stop("Duplicated entries in bound indices found.") if((max(x[[1L]]) > n)) stop("Bound indices must not exceed number of objective coefficients.") } Rglpk/R/zzz.R0000644000176000001440000000056012245336313012545 0ustar ripleyusers.onLoad <- function(libname, pkgname){ ## initialize print routines .C("Rglpk_initialize", PACKAGE = pkgname) } .onAttach <- function(libname, pkgname){ version <- .C( "Rglpk_get_engine_version", GLPK_version = character(1L), PACKAGE = pkgname ) packageStartupMessage( sprintf("Using the GLPK callable library version %s", version) ) } Rglpk/R/filereader.R0000644000176000001440000002773012245336313014022 0ustar ripleyusers## Reads linear programs from MPS files ## uses GLPK's facilities for reading these files ## Interface to GLPK's MPS file reader ## Since 2012-01-11: Rglpk supports MathProg files and retrieves ## variables names and constraints names. Thanks to Michael Kapler! ## Input: Path to a file specifying a mathematical program (MP), ## the model specification language ## Output: an object of class 'MP_data_from_file' describing the MP ## Mathematical Programming (MP) Data Object (consisting of 2 parts) ## o MILP class ##$objective ... a 1 x n simple_triplet_matrix representing objective coeffs ##$constraints[[1]] ... a m x n simple_triplet_matrix specifying the constraints ##$constraints[[2]] ... contains the m direction of constraints ##$constraints[[3]] ... vector of m right hand side values ##$bounds ... a list with elements $upper and $lower. Each of which contains indices and bounds of objective variables ##$types ... a character vector specifying which objective variable is of type 'binary' (B), continuous (C), or 'integer' (I) ##$maximum ... can be either 'min' or 'max' ## o ATTRIBUTES ##$n_objective_vars ... number of objective variables ##$n_integer_vars ... number of variables which are of type 'integer' ##$n_binary_vars ... number of variables which are of type 'binary' ##$n_constraints ... number of constraints ##$n_nonzero ... number of values in constraint matrix ##$problem_name ... name of the problem ##$objective_name ... name of the problem ##$constraint_names ... names of the constraints ##$objective_vars_names ... names of the objective vars ##$file_name ... absolute path to original data file ##$file_type ... file type (currently 'MPS-fixed', 'MPS-free', 'CPLEX LP', 'MathProg') Rglpk_read_file <- function(file, type = c("MPS_fixed", "MPS_free", "CPLEX_LP", "MathProg"), ignore_first_row = FALSE, verbose = FALSE){ if(!file.exists(file)) stop(paste("There is no file called", file, "!")) ## which file type to read from type <- match.arg(type) type_db <- c("MPS_fixed" = 1L, "MPS_free" = 2L, "CPLEX_LP" = 3L, "MathProg" = 4L ) type <- type_db[type] obj <- list(file = tools::file_path_as_absolute(file), type = type) ## read files in a two step approach ## first, retrieve meta data: e.g., the number of objective variables, etc. ## we need this to allocate memory on the R level for the result vectors meta_data <- glp_get_meta_data_from_file(obj, verbose) ## second, read all remaining data milp_data <- glp_retrieve_MP_from_file(meta_data, ignore_first_row, verbose) ## merge everything together MP_data <- glp_merge_MP_data(meta_data, milp_data) ## Post processing MP_data$type <- names(type_db[type_db == MP_data$type]) ## and a direction '<=' dir_db <- c("FR" = 1L, ">=" = 2L, "<=" = 3L, "DB" = 4L, "==" = 5L) MP_data$direction_of_constraints <- names(dir_db[MP_data$direction_of_constraints]) ## we remove constraints marked as unbounded (GLP_FR) ind_FR <- MP_data$direction_of_constraints == "FR" if(any(ind_FR)){ MP_data$constraint_matrix <- MP_data$constraint_matrix[ !ind_FR, ] MP_data$right_hand_side <- MP_data$right_hand_side[ !ind_FR ] MP_data$left_hand_side <- MP_data$left_hand_side[ !ind_FR ] MP_data$direction_of_constraints <- MP_data$direction_of_constraints[ !ind_FR ] MP_data$constraint_names <- MP_data$constraint_names[ !ind_FR ] MP_data$n_constraints <- MP_data$n_constraints - sum( ind_FR ) } ## we add an additional constraint for double bounded constraints(GLP_DB) ind_DB <- MP_data$direction_of_constraints == "DB" if(any(ind_DB)){ n_double_bounded <- sum( ind_DB ) MP_data$constraint_matrix <- rbind( MP_data$constraint_matrix, MP_data$constraint_matrix[ ind_DB, ] ) ## upper bounds already in rhs vector MP_data$direction_of_constraints[ ind_DB ] <- "<=" length(MP_data$direction_of_constraints) <- length(MP_data$direction_of_constraints) + sum(ind_DB) MP_data$direction_of_constraints[is.na(MP_data$direction_of_constraints)] <- ">=" length(MP_data$right_hand_side) <- length(MP_data$right_hand_side) + sum(ind_DB) MP_data$right_hand_side[is.na(MP_data$right_hand_side)] <- MP_data$left_hand_side[ind_DB ] MP_data$constraint_names <- c(MP_data$constraint_names, MP_data$constraint_names[ ind_DB ]) MP_data$n_constraints <- MP_data$n_constraints + sum( ind_DB ) } ## default is to have only continuous variables ## if any is binary or integer set the value accordingly types <- rep("C", length.out = MP_data$n_objective_vars) if(any(MP_data$objective_var_is_integer)){ types[MP_data$objective_var_is_integer] <- "I" } if(any(MP_data$objective_var_is_binary)){ types[MP_data$objective_var_is_binary] <- "B" } ## recalculate number of nonzeroes MP_data$n_values_in_constraint_matrix <- length(MP_data$constraint_matrix$v) ## build object we want to return ## First add MILP to the object out <- MILP(objective = MP_data$objective_coefficients, constraints = list(MP_data$constraint_matrix, MP_data$direction_of_constraints, MP_data$right_hand_side), bounds = MP_data$bounds, types = types, maximum = MP_data$maximize ) attr(out, "n_objective_vars") <- MP_data$n_objective_vars attr(out, "n_integer_vars") <- MP_data$n_integer_vars attr(out, "n_binary_vars") <- MP_data$n_binary_vars attr(out, "n_constraints") <- MP_data$n_constraints attr(out, "n_nonzeros") <- MP_data$n_values_in_constraint_matrix attr(out, "problem_name") <- MP_data$problem_name attr(out, "objective_name") <- MP_data$objective_name attr(out, "objective_vars_names") <- MP_data$objective_vars_names attr(out, "constraint_names") <- MP_data$constraint_names attr(out, "file_type") <- MP_data$type attr(out, "file_name") <- MP_data$file class(out) <- c("MP_data_from_file", class(out)) out } ## First parse file to get some meta data of the LP/MILP ## (number of constraints/objective variables, direction of optimization, ...) glp_get_meta_data_from_file <- function(x, verbose){ res <- .C("Rglpk_read_file", file = as.character(x$file), type = as.integer(x$type), direction_of_optimization = integer(1L), n_constraints = integer(1L), n_objective_vars = integer(1L), n_values_in_constraint_matrix = integer(1L), n_integer_vars = integer(1L), n_binary_vars = integer(1L), problem_name = character(1L), objective_name = character(1L), verbosity = as.integer(verbose), PACKAGE = "Rglpk") ## free memory by deleting C-level problem object .C("Rglpk_delete_prob", PACKAGE = "Rglpk") res } ## Retrieve all missing elements of the LP/MILP glp_retrieve_MP_from_file <- function(x, ignore_first_row, verbose = FALSE){ res <- .C("Rglpk_retrieve_MP_from_file", file = as.character(x$file), type = as.integer(x$type), n_constraints = x$n_constraints, n_objective_vars = x$n_objective_vars, objective_coefficients = double(x$n_objective_vars), constraint_matrix_i = integer(x$n_values_in_constraint_matrix), constraint_matrix_j = integer(x$n_values_in_constraint_matrix), constraint_matrix_values = double(x$n_values_in_constraint_matrix), direction_of_constraints = integer(x$n_constraints), right_hand_side = double(x$n_constraints), left_hand_side = double(x$n_constraints), objective_var_is_integer = integer(x$n_objective_vars), objective_var_is_binary = integer(x$n_objective_vars), bounds_type = integer(x$n_objective_vars), bounds_lower = double(x$n_objective_vars), bounds_upper = double(x$n_objective_vars), lp_ignore_first_row = as.integer(ignore_first_row), verbosity = as.integer(verbose), constraint_names = rep(character(1L), x$n_constraints), objective_vars_names = rep(character(1L), x$n_objective_vars), PACKAGE = "Rglpk") ## free memory by deleting C-level problem object .C("Rglpk_delete_prob", PACKAGE = "Rglpk") ## lp_is_integer = as.integer(lp_is_integer), ## replace infinity values res$bounds_lower <- replace(res$bounds_lower, res$bounds_lower == -.Machine$double.xmax, -Inf) res$bounds_upper <- replace(res$bounds_upper, res$bounds_upper == .Machine$double.xmax, Inf) ## in MPS definition first row is sometimes problematic. E.g., in MIPLIB2003 ## it has to be removed! if(ignore_first_row){ res$n_constraints <- res$n_constraints - 1 ## zeros values in the constraint matrix have to be removed, these ## are the values from the first row to_remove <- which(res$constraint_matrix_values == 0) res$constraint_matrix_i <- res$constraint_matrix_i[-to_remove] - 1 res$constraint_matrix_j <- res$constraint_matrix_j[-to_remove] res$constraint_matrix_values <- res$constraint_matrix_values[-to_remove] res$right_hand_side <- res$right_hand_side[-1] res$left_hand_side <- res$left_hand_side[-1] #res$direction_of_constraints <- res$direction_of_constraints[-length(res$right_hand_side)] } res } glp_merge_MP_data <- function(x, y){ out <- list(objective_coefficients = y$objective_coefficients, constraint_matrix = simple_triplet_matrix( y$constraint_matrix_i, y$constraint_matrix_j, y$constraint_matrix_values, y$n_constraints, y$n_objective_vars), direction_of_constraints = y$direction_of_constraints, right_hand_side = y$right_hand_side, left_hand_side = y$left_hand_side, objective_var_is_integer = as.logical(y$objective_var_is_integer), objective_var_is_binary = as.logical(y$objective_var_is_binary), ## minimization if GLP_MIN (1L) or max if GLP_MAX (2L) maximize = x$direction_of_optimization == 2L, bounds = list(lower = list(ind = 1L:x$n_objective_vars, val = y$bounds_lower), upper = list(ind = 1L:x$n_objective_vars, val = y$bounds_upper)), n_objective_vars = x$n_objective_vars, n_integer_vars = x$n_integer_vars, n_binary_vars = x$n_binary_vars, ## here from y because it might have changed -> ignore_first_row_parameter n_constraints = y$n_constraints, n_values_in_constraint_matrix = x$n_values_in_constraint_matrix, ## problem_name = x$problem_name, file = x$file, type = x$type, problem_name = x$problem_name, objective_name = x$objective_name, constraint_names = y$constraint_names, objective_vars_names = y$objective_vars_names ) out } Rglpk/MD50000644000176000001440000003124012245405147011675 0ustar ripleyusers6417dec5fa425aa82e99459f4087be61 *DESCRIPTION ffc7fdfda4b522c2c8f5193e1ec7d88b *NAMESPACE 89802f16b53ebb2fb07679fb89ac7b33 *R/Misc.R 9a943f0a4c55276f9be37ac780e1943d *R/Rglpk_solve.R d4b39ae0e53f3ee9e1e23c5de5cec533 *R/bounds.R f1a6209be56503b40d292618c846396f *R/control.R faa5f26eb76db3d27ef13252da904d5e *R/filereader.R f8672da398fee3461bded8d8de6cec02 *R/milp.R 9a3dde9c92c8c109ba717446f2d7b2b2 *R/zzz.R 5299c161b149974ccae263af06494afc *cleanup 1262f7a12fddb89ebbe29f58c04a1c00 *configure 68b329da9893e34099c7d8ad5cb9c940 *configure.win 462ba6e448cd15f4bebbd006bde8299f *inst/CHANGELOG bdee58c3965c7b68c5923ee60183e736 *inst/examples/assign.mod 72aa9eab3996ee9aa7abeaeb4c05ff12 *inst/examples/plan.lp 45e60857cbfdfb15805eb12cc2e17d94 *inst/examples/plan.mod 0a0c722569a00b732639ed320453181c *inst/examples/plan.mps 9e22c38d5268676761f77a2c82020cf8 *man/Rglpk_read_file.Rd 378c9dbc172f711573eb516471b82335 *man/Rglpk_solve.Rd 55e5bfce5a3bd2fdb62669edb97fe1cd *src/GLPK/Makefile 1fa7a390ff204d652b33468939d93102 *src/GLPK/Makefile.am 6e0306358b3d0d89d943a5f86c19461c *src/GLPK/Makefile.in e2c6b287129de8a2b800a378b49c0aa5 *src/GLPK/Makefile.win d0d08a993019f987f424b270560a4d32 *src/GLPK/alloc.c e66651809cac5da60c8b80e9e4e79e08 *src/GLPK/amd/COPYING bfdd79e55fe996c63b0636e065173e3b *src/GLPK/amd/README f17b9ad6c570189c90e054e5ad22a48c *src/GLPK/amd/amd.h 0e443173d6720b1300cf605bbaece04b *src/GLPK/amd/amd_1.c 0f09e90ebfb03a2835ca90772cff2903 *src/GLPK/amd/amd_2.c 8e9bef15f0f6a04b9a825f8d52174d2d *src/GLPK/amd/amd_aat.c da7c5120c89bb6c50a71d9826416b8ca *src/GLPK/amd/amd_control.c 49e3189ef6df390a6ee6d32efcf37d2c *src/GLPK/amd/amd_defaults.c 7a507df8b9319bcd17a6cad1dbda3fa7 *src/GLPK/amd/amd_dump.c 63b58adb1033575a7733723f79b923d0 *src/GLPK/amd/amd_info.c 1916b4e4e6116b4756843117c4debbaf *src/GLPK/amd/amd_internal.h 9934cb05c930024d300d62c91c654307 *src/GLPK/amd/amd_order.c 5a26434fda9351c3cd2c440f09e3d031 *src/GLPK/amd/amd_post_tree.c b82d8ed7fea392e568f4fd8962cbb928 *src/GLPK/amd/amd_postorder.c 2def6a2ca54e5d6ceccf7bdf1cdf5a7d *src/GLPK/amd/amd_preprocess.c 44c8934cd1690b307fb15b90a66924f3 *src/GLPK/amd/amd_valid.c 254eb54d691c645baeae4051427ca853 *src/GLPK/bignum.c 33b17b67e97d357f55e65308f949383e *src/GLPK/bignum.h 0db3634b41da3bd55a965398ed3c0930 *src/GLPK/cfg.c bfd17df7dd4c1328baff05cd36993056 *src/GLPK/cfg.h afac0dd706e4695586669c70c8af3dbb *src/GLPK/cfg1.c e66651809cac5da60c8b80e9e4e79e08 *src/GLPK/colamd/COPYING 0495db11d882533d3e1d77314aa08501 *src/GLPK/colamd/README e1b0790a561a36994f2491f68b4237be *src/GLPK/colamd/colamd.c 64862c5f680f1ed283f29e91213affa7 *src/GLPK/colamd/colamd.h 14fd477d61454580ad3afc8df0c072a3 *src/GLPK/dmp.c ccc6ab85decf1d61020676aeb8ccc6d0 *src/GLPK/dmp.h a8b8a2082a78e0ef66eae449d2dfa6f9 *src/GLPK/env.c 27baf85ef963002585812de4c071accf *src/GLPK/env.h 0e18622fcec2c883831e419fa592447a *src/GLPK/env2.h 480a24e5f7f8eb1a5d0bf55dc6b638ad *src/GLPK/error.c 2de173f6effeafdb7678c2c385124eb3 *src/GLPK/ffalg.c 16b3e85dc59c378f665a879ec6532a63 *src/GLPK/ffalg.h d3f6eda4ac1aa2eb3629ed7cf9548ca6 *src/GLPK/fhv.c 0d476f3b14d2cde64cfe1521f648b05a *src/GLPK/fhv.h 29a20358451179aaf0e7ba0b816fbf9b *src/GLPK/fhvint.c adb18a622831736a6926da16b343dbab *src/GLPK/fhvint.h 9b5f3536c7c4fed4cf3c21100563fced *src/GLPK/glpapi.h 94f980fa5a5d1de1a20177bd2ed01cf6 *src/GLPK/glpapi01.c 008c6acf1c25d266798e3cb41295addf *src/GLPK/glpapi02.c 8c25cf3d8a628b3ee8c10bc9d5b830c7 *src/GLPK/glpapi03.c 4114920a6df6173319841b14df0f13ad *src/GLPK/glpapi04.c 4653d64b56ecce5213582243095aff11 *src/GLPK/glpapi05.c b5922cfd9dde2c42c4a5821be36ddc21 *src/GLPK/glpapi06.c 5fd42bd2bfe410c6051fd5ec2477eb7a *src/GLPK/glpapi07.c 3403d6e1d44971f29a56fb84c4231ca7 *src/GLPK/glpapi08.c 2f040909c47dcceee723784f1b6e15d0 *src/GLPK/glpapi09.c 3d266b8e68330ed7a5ef6ca2def55442 *src/GLPK/glpapi10.c d2952ce0c9853bfbe1a03b6ff4f35c5f *src/GLPK/glpapi11.c 1113e08c27bbeb2207ba0103e39353ca *src/GLPK/glpapi12.c 6d6afe9df4c67180873124186403206f *src/GLPK/glpapi13.c bb53e74b503baf692274a23caa38ae12 *src/GLPK/glpapi14.c 797f4751902b2ec55f04ab8839569db7 *src/GLPK/glpapi15.c 1a843124a559d7ef0c574e49dfe03b36 *src/GLPK/glpapi16.c 4a85a142036b0a0b6bec4db79898d72f *src/GLPK/glpapi17.c 9a251ede4cc14353d016fd1005ca9186 *src/GLPK/glpapi18.c 164f63f50ba7c08347375b4297db03ac *src/GLPK/glpapi19.c 7d6327224ae46ad2e979691222363058 *src/GLPK/glpapi20.c 3c80b9e4929037960b74d03892e9b4eb *src/GLPK/glpapi21.c c39b76f8fc1f56c367b798a80d23fcbb *src/GLPK/glpavl.c 086e7e6ed2c86a889535a26f2c008fff *src/GLPK/glpavl.h ccfbd8c1104ed96dcb0bfd22a3c3db8d *src/GLPK/glpbfd.c 9b27acba81ebf14abe9e586242e199ed *src/GLPK/glpbfd.h 693d469b83a2511efe1b194c4971108f *src/GLPK/glpbfx.c 5c8a5c945ce6828b7218449e4622ae1c *src/GLPK/glpbfx.h 7e0aaef1064564038695cf63ffab74ba *src/GLPK/glpcpx.c c3490aea8c5cf205c2d98916017d1947 *src/GLPK/glpdmx.c 1274378bdf62d60d8a8f7c9e478e7b1b *src/GLPK/glpenv07.c 060243286b82408c0ca3e69a7592bf84 *src/GLPK/glpenv07.c.orig 2778d17004a765cdef9daefd4ae27fb8 *src/GLPK/glpenv08.c 56e000533ddba2127389cc21b7d24f41 *src/GLPK/glpgmp.c d5f2c2cd8ea73a4f6782708199da059f *src/GLPK/glpgmp.h 8a1c2a7f22b17a1009b0bc4e4ad95279 *src/GLPK/glphbm.c 4f4aa0a9adf6fbc64e2243b67461259e *src/GLPK/glphbm.h 0ce6c6f0d0d7ff51a1c41289155e7300 *src/GLPK/glpini01.c 55af74fde63d101cd3c0c3f372e4c73d *src/GLPK/glpini02.c a8f2f3a126d443bb6f56a50ab755d199 *src/GLPK/glpios.h bd04827ae1526d527535d3a6799e0477 *src/GLPK/glpios01.c 5c2066a85605b3aa7c16eeca5e5bb3e0 *src/GLPK/glpios02.c 4abe4a5b6fb0d4a447ccdcbe6cea780d *src/GLPK/glpios03.c 8bc066b59c939de5a1029d90f73c401f *src/GLPK/glpios04.c a4aad4eb70f86f31014b1f748ad682d4 *src/GLPK/glpios05.c e5186d6bd8a0f34938927268282ee98e *src/GLPK/glpios06.c 36930bdc2e72d6a988be5580d7783054 *src/GLPK/glpios07.c 1c4b8e4cf8f774cc5de514f21b1bf345 *src/GLPK/glpios08.c a29d9eebd2879a252df7ad42bf1fc325 *src/GLPK/glpios09.c 1f79ccbc1dcbdcbdb91df1daf59a1cab *src/GLPK/glpios10.c d3b99cadaf1b3e41aa9c7a7be685a20b *src/GLPK/glpios11.c be97924cb88afefb473d5951e43c31f5 *src/GLPK/glpios12.c eba06e2d9b42511030b1d50e8dec7c50 *src/GLPK/glpipm.c 5cff3a04ee5c5d5422b6f7985fbb46f8 *src/GLPK/glpipm.h a298516259b43c153d195f0dabda9131 *src/GLPK/glpk.h ab70e8d4ec744ad09e3897b167f1011d *src/GLPK/glplib.h a470505736c1f20b18e284d64166b0e5 *src/GLPK/glplib03.c 6eaf1d7c14f53187683d60db64d1709b *src/GLPK/glplpf.c a774144df372e76c8575c232f41e82de *src/GLPK/glplpf.h dd78e0c674df98a4d4e268a05db24a62 *src/GLPK/glplpx.h aaa9ebcbb16bb92dee266e8e24db799c *src/GLPK/glplpx01.c a7e9dea63f73fcc8dd5aa3d5958d33e8 *src/GLPK/glplpx02.c 217045287f86fa6f7f1fe06b4abc8de6 *src/GLPK/glplpx03.c 8dd95195ee34c9b5a2d3636b80fb995d *src/GLPK/glplux.c bc77c29378d70d7e85b0a77cbcd6feec *src/GLPK/glplux.h a12e765ffb7c57df11a9ceb9efb77526 *src/GLPK/glpmat.c cec9974e5d75f55609d5a52fdfc4a8c7 *src/GLPK/glpmat.h 09a85b880fdd1768e5ac4a05e8f7aae4 *src/GLPK/glpmpl.h ca610303e69aa2feab95af278f3576f1 *src/GLPK/glpmpl01.c 87cce283312aedcf616f65ad94641450 *src/GLPK/glpmpl02.c 6603c5fe0f4cb3202f6209495f58f58d *src/GLPK/glpmpl03.c 2cc86c1071683462214befe9472c093e *src/GLPK/glpmpl04.c e7dbac0814ee6133f17d5201b08e929a *src/GLPK/glpmpl05.c 1b4874960d40d559ebd122d77c51f196 *src/GLPK/glpmpl06.c 3adde890f7d2757b777f3fba45d454d3 *src/GLPK/glpmps.c fabcb85a9239c5835b8ba997a1089cb5 *src/GLPK/glpnet03.c 4637ef746c4eeba1071583ae1c0a3b0e *src/GLPK/glpnet04.c 39572efa82af7d3afb4322db8bb56f88 *src/GLPK/glpnet05.c ca235121e2cd412cc2119ae3b1d77c8b *src/GLPK/glpnpp.h fcb297c8e058bbb123e4626e21b875b5 *src/GLPK/glpnpp01.c b7d57f0a6bc0e00af8bc1c90c322067f *src/GLPK/glpnpp02.c a78c3aa4ba27afb765e64b90609833f8 *src/GLPK/glpnpp03.c 32dae06b8332f2c9c0621fcc20debcc7 *src/GLPK/glpnpp04.c b1226174620aaf32ff4a050ac1edb622 *src/GLPK/glpnpp05.c a577ceab7b5eb05cb45f4e9340001b21 *src/GLPK/glpnpp06.c e7249b95a032cec9a262184623b4ff71 *src/GLPK/glprgr.c 6bcda8432ce61d2d8a495af06738fc2c *src/GLPK/glprgr.h ff116f2421a3a1360300614512ca679b *src/GLPK/glpscf.c aa70b3bf47c03d79ab360744af3d61c4 *src/GLPK/glpscf.h 09db0c825ecfd794a95e0c9aed0f6256 *src/GLPK/glpscl.c efa06471d3bc844b6855a184b767e308 *src/GLPK/glpsdf.c 73cb302f9913dccd5a63641e7cdc2f80 *src/GLPK/glpsdf.h 11cc3d3f1a0ff362ca6bd85dff33b7ec *src/GLPK/glpspm.c 60132bb08c1cdf5a82f937c81f7c9ba9 *src/GLPK/glpspm.h 669fe9567ebc17d3b58a1dfd453b65d7 *src/GLPK/glpspx.h 7bba106d45fd2014c697228b4ad4c609 *src/GLPK/glpspx01.c 009ab6002b26ba0e30a2fff6c1ece04e *src/GLPK/glpspx02.c 908609e150a479f30364e617168be682 *src/GLPK/glpsql.c d0b744954c20cd504f63d1f2c03dedd5 *src/GLPK/glpsql.h 249c641881a14d8826e3f804fc623241 *src/GLPK/glpssx.h 4332676e0d90bf06ce9f1f32ba02f809 *src/GLPK/glpssx01.c fdd6171cc1f8aa251608650117f56020 *src/GLPK/glpssx02.c 3b3d680e72649da5251a3930b6198477 *src/GLPK/glptsp.c c59fd8af80d9b7aefeca8f34897e65cd *src/GLPK/glptsp.h d8d24e65e9b2148da9bf45aa19a6e940 *src/GLPK/jd.c 2911980ad08541e38c91f39542a120de *src/GLPK/jd.h a29f50fe94545405bdcc8e237574e1e9 *src/GLPK/keller.c c937fa5feec424e89f4f32c70fd8c4df *src/GLPK/keller.h aff4ee8f7320cadd85b4e9921081ff3a *src/GLPK/luf.c 6226fa3fa973de3c3e23f28ed6ffec22 *src/GLPK/luf.h 5d706d12c68bcc34bf54b9a342e65441 *src/GLPK/lufint.c 3cebebe1e1e2141d15377ccdb4a741fc *src/GLPK/lufint.h e7f4fc10007c71e4e92631ab70982cd6 *src/GLPK/mc13d.c e00cf19e28301ce76798b785aa1d8f4e *src/GLPK/mc13d.h 3d8358e67ef6c1569d5b833c3f5f28e7 *src/GLPK/mc21a.c b22a412b20dc7c6251a4f63e259c4540 *src/GLPK/mc21a.h b53c287db30d683f09f019de3e416c7e *src/GLPK/minisat/LICENSE 123024ae2b029c190414fdaba5fa80dd *src/GLPK/minisat/README b89317dace51f334238f501ba0d330ef *src/GLPK/minisat/minisat.c e89d6a8e40a79171fcbb79318f4f5116 *src/GLPK/minisat/minisat.h ea7bb674f2c7209752ef38f3cbc7c05a *src/GLPK/okalg.c eab9bc429a837834a05af89092e88237 *src/GLPK/okalg.h c0631d5b7dcefc8d712c5199defee029 *src/GLPK/proxy/main.c 64370e7bad4307d32d32b0b1f0a3384c *src/GLPK/proxy/proxy.c de3e1dac269f3fd4aa945c28fddbf93c *src/GLPK/proxy/proxy.h 8b3752e16a89b1bbbf28b6bc52f2b374 *src/GLPK/proxy/proxy1.c 605ec93cf4e92b44799ef55edf17ead8 *src/GLPK/qmd.c 033e69fbedbcb0f3e926c331ec3021ac *src/GLPK/qmd.h 2dc4c23b23bac116c54ebb5539d5b8b2 *src/GLPK/relax4.c 1921e63d1fdb2c3eb4e3f58da697f707 *src/GLPK/relax4.h c817962b9648aa71fdd49b222ed0b10e *src/GLPK/rng.c 6032a55b61035975f34e07273b943419 *src/GLPK/rng.h 87a853c070adeefcfd25cf28b750ba44 *src/GLPK/rng1.c 2ef9b2d7527af80e78041de689bfd302 *src/GLPK/sgf.c d669e1f9203e9a99db57f35ba3551e50 *src/GLPK/sgf.h 6bcf3bf7dc45ec8fcf0a18619297e79e *src/GLPK/stdc.h 1d473fdce95f2002e084815a8ccdc74b *src/GLPK/stdout.c 119e6b48c71123d993e85284e99d9131 *src/GLPK/sva.c 35764a8aba7ede8bde69333c32a37de6 *src/GLPK/sva.h b6abf7211d0dff1976183812554696af *src/GLPK/time.c 00ccce39405332d54c28c32ed77cdc0c *src/GLPK/tls.c 5960510bd9babda16f24b65d976f1921 *src/GLPK/triang.c 7d1058da4be626807b625cd45e748240 *src/GLPK/triang.h 05d3afac800969c87734226d212f9bba *src/GLPK/wclique.c 6d5596077999d449285f3bf8dc855c7f *src/GLPK/wclique.h 0003b9217528f5a835e78e975bc543fd *src/GLPK/wclique1.c d990cb5329763715ad3acc4cdee27a0d *src/GLPK/wclique1.h 2ce398124de9c874bc8d03e05a3ea42e *src/GLPK/zlib/README c4b246082dd2db9531253522d5c41701 *src/GLPK/zlib/adler32.c 80e21b784f835c2d8980b36bc8670351 *src/GLPK/zlib/compress.c 5c9e6c1581bd89f9647ac93918aac6fd *src/GLPK/zlib/crc32.c 96c40e27fbc28d268dc510aadde32324 *src/GLPK/zlib/crc32.h f13247ee9dbe59b564b2bfc7d3665a75 *src/GLPK/zlib/deflate.c c227feaad489655b3e95aede463ba1ce *src/GLPK/zlib/deflate.h 68637d73edb872c8b87e52fda50167f2 *src/GLPK/zlib/gzclose.c 16466c1025fa331acd9498ee7cf91cc5 *src/GLPK/zlib/gzguts.h d8c1f40771a7670dadb4addc34986b2f *src/GLPK/zlib/gzlib.c 9ed090d5b047c2c7b952c7c012442ee1 *src/GLPK/zlib/gzread.c 2d19c0cbb2627c2199f58f31965904e3 *src/GLPK/zlib/gzwrite.c 873a9aa6df696821291c0e56275046c6 *src/GLPK/zlib/inffast.c 60bacb988f60d1e1702088d460788fb9 *src/GLPK/zlib/inffast.h 7fa3e91804601b6618c915b76a8dc332 *src/GLPK/zlib/inffixed.h 16812ce7baeef0d03a76413dd28d29c9 *src/GLPK/zlib/inflate.c 6ca7240488ad7d2fff1112257944dc79 *src/GLPK/zlib/inflate.h 74c423054dea5785c9f4d207e3ce9478 *src/GLPK/zlib/inftrees.c abd96e23d5677e01a6076ea674b2612f *src/GLPK/zlib/inftrees.h 9790df927f2685faf1069be690829ee7 *src/GLPK/zlib/trees.c ad17f11bf1bcc0a31b5376f4850219c6 *src/GLPK/zlib/trees.h 566db3f965b2935c6dec22f78a96b3fa *src/GLPK/zlib/uncompr.c 8b210e964ccc13c69c9feb6bdcdce76e *src/GLPK/zlib/zconf.h 0b4dbd61193c1d3b93bd92bd3a802017 *src/GLPK/zlib/zio.c 61c6716fbdb109586681af6942be9aa2 *src/GLPK/zlib/zio.h 322ed4192d95475c87859da67384b95d *src/GLPK/zlib/zlib.h c678d09f44afaf417a20e7be4216246f *src/GLPK/zlib/zsymb.h e824aa455e77b4eb8763ffb7fc3ac807 *src/GLPK/zlib/zutil.c d7be80cbf817942820715376b4bf9549 *src/GLPK/zlib/zutil.h 16928375c376f342565f9f81b85aff65 *src/Makevars.in 3339336dae3f3d9994d5125808ee3771 *src/Makevars.win 251280352529c5efb066d41fa89e985e *src/Rglpk.h 5622e753d3d13b4bf264756073cbc667 *src/Rglpk_initialize.c f0c2674ec4184bca3eebbbeaadfb5cb2 *src/Rglpk_read_file.c f164da4accb871d477ffa870633bdfbc *src/Rglpk_solve.c Rglpk/DESCRIPTION0000644000176000001440000000255612245405147013103 0ustar ripleyusersPackage: Rglpk Version: 0.5-2 Title: R/GNU Linear Programming Kit Interface Description: R interface to the GNU Linear Programming Kit (GLPK version 4.52.1 is shipped with the source package). GLPK is open source software for solving large-scale linear programming (LP), mixed integer linear programming (MILP) and other related problems. Authors@R: c(person("Stefan", "Theussl", role = c("aut", "cre"), email = "Stefan.Theussl@R-project.org"), person("Kurt", "Hornik", role = "aut"), person("Christian", "Buchta", role = "ctb"), person("Andrew", "Makhorin", role = "cph"), person("Timothy A.", "Davis", role = "cph"), person("Niklas", "Sorensson", role = "cph"), person("Mark", "Adler", role = "cph"), person("Jean-loup", "Gailly", role = "cph")) Depends: slam (>= 0.1-9) SystemRequirements: GLPK library package (e.g., libglpk-dev on Debian/Ubuntu); sources are included for other OSes. License: GPL-2 URL: http://R-Forge.R-project.org/projects/rglp/, http://www.gnu.org/software/glpk/ Packaged: 2013-11-27 11:16:12 UTC; wucloud Author: Stefan Theussl [aut, cre], Kurt Hornik [aut], Christian Buchta [ctb], Andrew Makhorin [cph], Timothy A. Davis [cph], Niklas Sorensson [cph], Mark Adler [cph], Jean-loup Gailly [cph] Maintainer: Stefan Theussl NeedsCompilation: yes Repository: CRAN Date/Publication: 2013-11-27 16:06:15 Rglpk/configure0000755000176000001440000000262412245336313013276 0ustar ripleyusers#! /bin/sh ## For the time being, this is a simple shell script ... ## Test whether a complete GLPK library environment is available, ## e.g. ftp://ftp.gnu.org/gnu/glpk/ ## Find the R home directory. : ${R_HOME=`R RHOME`} if test -z "${R_HOME}"; then echo "Could not determine R_HOME." exit 1 fi R="${R_HOME}/bin/R" GLPK_LIBS="-lglpk" ## Test whether we can compile and link a minimal program. rm -f conftest.* cat > conftest.cc < int main () { glp_prob *lp; lp = glp_create_prob(); glp_delete_prob(lp); return 0; } EOF _R_SHLIB_BUILD_OBJECTS_SYMBOL_TABLES_=false \ "${R}" CMD SHLIB conftest.cc ${GLPK_LIBS} >/dev/null 2>&1 \ && "$R" --slave --vanilla -e 'dyn.load("conftest.so")' status=${?} if test ${status} -ne 0; then rm -f conftest.*o GLPK_LIBS="-lglpk -lgmp -lm" _R_SHLIB_BUILD_OBJECTS_SYMBOL_TABLES_=false \ "${R}" CMD SHLIB conftest.cc ${GLPK_LIBS} >/dev/null 2>&1 \ && "$R" --slave --vanilla -e 'dyn.load("conftest.so")' status=${?} fi rm -f conftest.* if test ${status} -eq 0; then GLPK_INCLUDE_PATH= GLPK_LIB_PATH= GLPK_TS= else GLPK_INCLUDE_PATH="-IGLPK" GLPK_LIB_PATH="-LGLPK" GLPK_LIBS="-lglpk" GLPK_TS="GLPK.ts" fi sed -e "s|@GLPK_INCLUDE_PATH@|${GLPK_INCLUDE_PATH}|" \ -e "s|@GLPK_LIB_PATH@|${GLPK_LIB_PATH}|" \ -e "s|@GLPK_LIBS@|${GLPK_LIBS}|" \ -e "s|@GLPK_TS@|${GLPK_TS}|" \ src/Makevars.in > src/Makevars Rglpk/man/0000755000176000001440000000000012245352174012141 5ustar ripleyusersRglpk/man/Rglpk_solve.Rd0000644000176000001440000001205512245336313014717 0ustar ripleyusers\name{Rglpk_solve_LP} \alias{Rglpk_solve_LP} \title{Linear and Mixed Integer Programming Solver Using GLPK} \description{ High level R interface to the GNU Linear Programming Kit (GLPK) for solving linear as well as mixed integer linear programming (MILP) problems. } \usage{ Rglpk_solve_LP(obj, mat, dir, rhs, bounds = NULL, types = NULL, max = FALSE, control = list(), \ldots) } \arguments{ \item{obj}{a numeric vector representing the objective coefficients.} \item{mat}{a numeric vector or a matrix of constraint coefficients.} \item{dir}{a character vector with the directions of the constraints. Each element must be one of \code{"<"}, \code{"<="}, \code{">"}, \code{">="}, or \code{"=="}.} \item{rhs}{the right hand side of the constraints.} \item{bounds}{\code{NULL} (default) or a list with elements \code{upper} and \code{lower} containing the indices and corresponding bounds of the objective variables. The default for each variable is a bound between 0 and \code{Inf}.} \item{types}{a character vector indicating the types of the objective variables. \code{types} can be either \code{"B"} for binary, \code{"C"} for continuous or \code{"I"} for integer. By default \code{NULL}, taken as all-continuous. Recycled as needed.} \item{max}{a logical giving the direction of the optimization. \code{TRUE} means that the objective is to maximize the objective function, \code{FALSE} (default) means to minimize it.} \item{control}{a list of parameters to the solver. Currently the only options are: \code{verbose}, a logical for turning on/off additional solver output; \code{canonicalize_status}, a logical indicating whether to canonicalize GLPK status codes or not. Defaults: \code{FALSE}; \code{TRUE}.} \item{\ldots}{a list of control parameters (overruling those specified in \code{control}).} } \details{ GLPK is open source. The current version can be found at \url{http://www.gnu.org/software/glpk/glpk.html}. Package \pkg{Rglpk} provides a high level solver function using the low level C interface of the GLPK solver. R interface packages which port all low level C routines of the GLPK API to R are also available. Consult the \sQuote{See Also} Section for references. } \value{ A list containing the optimal solution, with the following components. \item{solution}{the vector of optimal coefficients} \item{objval}{the value of the objective function at the optimum} \item{status}{an integer with status information about the solution returned. If the control parameter \code{canonicalize_status} is set (the default) then it will return 0 for the optimal solution being found, and non-zero otherwise. If the control parameter is set to \code{FALSE} it will return the GLPK status codes.} } \references{ GNU Linear Programming Kit (\url{http://www.gnu.org/software/glpk/glpk.html}). GLPK Interface to R (\url{http://cran.R-project.org/package=Rglpk}). } \author{Stefan Theussl and Kurt Hornik} \seealso{ \pkg{glpk} and \pkg{glpkAPI} for C API bindings; \code{\link[lpSolve]{lp}} in package \pkg{lpSolve}; \code{\link[ROI]{ROI_solve}} in package \pkg{ROI}; \code{\link[Rsymphony]{Rsymphony_solve_LP}} in package \pkg{Rsymphony}. } \examples{ ## Simple linear program. ## maximize: 2 x_1 + 4 x_2 + 3 x_3 ## subject to: 3 x_1 + 4 x_2 + 2 x_3 <= 60 ## 2 x_1 + x_2 + 2 x_3 <= 40 ## x_1 + 3 x_2 + 2 x_3 <= 80 ## x_1, x_2, x_3 are non-negative real numbers obj <- c(2, 4, 3) mat <- matrix(c(3, 2, 1, 4, 1, 3, 2, 2, 2), nrow = 3) dir <- c("<=", "<=", "<=") rhs <- c(60, 40, 80) max <- TRUE Rglpk_solve_LP(obj, mat, dir, rhs, max = max) ## Simple mixed integer linear program. ## maximize: 3 x_1 + 1 x_2 + 3 x_3 ## subject to: -1 x_1 + 2 x_2 + x_3 <= 4 ## 4 x_2 - 3 x_3 <= 2 ## x_1 - 3 x_2 + 2 x_3 <= 3 ## x_1, x_3 are non-negative integers ## x_2 is a non-negative real number obj <- c(3, 1, 3) mat <- matrix(c(-1, 0, 1, 2, 4, -3, 1, -3, 2), nrow = 3) dir <- c("<=", "<=", "<=") rhs <- c(4, 2, 3) types <- c("I", "C", "I") max <- TRUE Rglpk_solve_LP(obj, mat, dir, rhs, types = types, max = max) ## Same as before but with bounds replaced by ## -Inf < x_1 <= 4 ## 0 <= x_2 <= 100 ## 2 <= x_3 < Inf bounds <- list(lower = list(ind = c(1L, 3L), val = c(-Inf, 2)), upper = list(ind = c(1L, 2L), val = c(4, 100))) Rglpk_solve_LP(obj, mat, dir, rhs, bounds, types, max) ## Examples from the GLPK manual ## Solver output enabled ## 1.3.1 ## maximize: 10 x_1 + 6 x_2 + 4 x_3 ## subject to: x_1 + x_2 + x_3 <= 100 ## 10 x_1 + 4 x_2 + 5 x_3 <= 600 ## 2 x_1 + 2 x_2 + 6 x_3 <= 300 ## x_1, x_2, x_3 are non-negative real numbers obj <- c(10, 6, 4) mat <- matrix(c(1, 10, 2, 1, 4, 2, 1, 5, 6), nrow = 3) dir <- c("<=", "<=", "<=") rhs <- c(100, 600, 300) max <- TRUE Rglpk_solve_LP(obj, mat, dir, rhs, max = max, control = list("verbose" = TRUE, "canonicalize_status" = FALSE)) } \keyword{optimize} Rglpk/man/Rglpk_read_file.Rd0000644000176000001440000000674512245336313015512 0ustar ripleyusers\name{Rglpk_read_file} \alias{Rglpk_read_file} \alias{print.MP_data_from_file} \title{Interface to GLPK's file reader} \description{ High level R interface to the CPLEX\_LP, MATHPROG and MPS reader of the GNU Linear Programming Kit (GLPK). Example data from the GLPK release is included in the \code{'./examples/'} sub-directory. } \usage{ ## File reader for various formats Rglpk_read_file(file, type = c("MPS_fixed", "MPS_free", "CPLEX_LP", "MathProg"), ignore_first_row = FALSE, verbose = FALSE) ## print method \method{print}{MP_data_from_file}(x, \ldots) } \arguments{ \item{file}{a character string specifying the relative or absolute path to the model file.} \item{type}{a character string specifying the file format. This can be either \code{"MPS_fixed"}, \code{"MPS_free"}, \code{"CPLEX_LP"}, and GNU \code{"MathProg"}.} \item{ignore_first_row}{a logical indicating whether the first row of the model file should be ignored or not. Default: \code{FALSE}.} \item{verbose}{a logical for turning on/off additional solver output. Default: \code{FALSE}.} \item{x}{an object of class \code{"MP_data_from_file"}.} \item{\ldots}{further arguments passed on to the print method.} } \details{\code{Rglpk_read_file()} takes the path to a file as an argument and calls GLPK's file reader. The description of the linear or mixed integer linear program is returned as an object of class \code{"MP_data_from_file"}. } \value{ \code{Rglpk_read_file()} returns the specification of a (mixed integer) linear program defined in \code{file} as an object of class \code{"MP_data_from_file"}. The returned object is a list containing the following components. \item{objective}{a \code{"\link[slam]{simple_triplet_matrix}"} representing the coefficients to \eqn{x} in the objective function.} \item{constraints}{a list with three elements: a \code{"\link[slam]{simple_triplet_matrix}"} of coefficients, a character vector of constraint directions, and a numeric vector representing the right hand side.} \item{bounds}{a list containing two elements: \code{lower} and \code{upper}. Each of which contain a list specifying indices (\code{ind}) and corresponding bounds (\code{val}).} \item{types}{a character vector specifying whether the corresponding objective variable is of type binary (\code{"B"}), continuous (\code{"C"}), or integer (\code{"I"}).} \item{maximum}{a logical indicating whether a minimum or a maximum is sought.} Further meta data is provided as attributes to the object. } %%\references{} \author{Stefan Theussl} %%\seealso{} \examples{ ## read a CPLEX LP file x <- Rglpk_read_file( system.file(file.path("examples", "plan.lp"), package = "Rglpk"), type = "CPLEX_LP") x ## optimal solution: 296.2166 Rglpk_solve_LP(x$objective, x$constraints[[1]], x$constraints[[2]], x$constraints[[3]], x$bounds, x$types, x$maximum) ## read a MATHPROG file x <- Rglpk_read_file( system.file(file.path("examples", "assign.mod"), package = "Rglpk"), type = "MathProg") x ## optimal solution: 76 Rglpk_solve_LP(x$objective, x$constraints[[1]], x$constraints[[2]], x$constraints[[3]], x$bounds, x$types, x$maximum) ## read a MATHPROG file x <- Rglpk_read_file( system.file(file.path("examples", "plan.mps"), package = "Rglpk"), type = "MPS_fixed") x ## optimal solution: 296.2166 Rglpk_solve_LP(x$objective, x$constraints[[1]], x$constraints[[2]], x$constraints[[3]], x$bounds, x$types, x$maximum) } \keyword{IO} \keyword{utilities} Rglpk/configure.win0000644000176000001440000000000112245336313014052 0ustar ripleyusers Rglpk/cleanup0000755000176000001440000000027112245336313012740 0ustar ripleyusers#! /bin/sh (cd src/GLPK; if test -f Makefile; then make distclean || true make distclean SUBDIRS= || true fi) rm -f config.* autom4te.cache src/GLPK.ts src/Makevars exit 0