Add single-row cut generator

This commit is contained in:
2017-04-28 22:15:10 -04:00
parent 43894daa81
commit 85bddc4e87
168 changed files with 8370 additions and 12 deletions

View File

@@ -0,0 +1,141 @@
/*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CPLEX_HELPER_HPP_
#define CPLEX_HELPER_HPP_
#include <vector>
#include <set>
#include "single_row_cut_generator.hpp"
using std::set;
using std::vector;
struct CplexRow {
int nz;
double pi_zero;
double *pi;
int *indices;
int depth;
int head;
double dynamism;
bool operator<(const CplexRow &other) const;
double get_violation(double *x);
void print(double *x);
};
/**
* This class provides useful methods for dealing with CPLEX.
*/
class CplexHelper {
private:
const CPXENVptr env;
const CPXLPptr lp;
bool *is_integer;
int n_cuts;
public:
/**
* Constructs a helper associated with the provided environment and problem.
*
* @param env Pointer to the ILOG CPLEX environment.
* @param lp Pointer to a CPLEX LP problem object.
*/
CplexHelper(CPXENVptr env, CPXLPptr lp);
~CplexHelper();
/**
* Adds the specified constraints to the model.
*
* @param cuts Set of constraints to add.
*/
void add_cut(Constraint *cut);
/**
* For each fractional row of the current tableau, adds as many single row
* cuts as possible. The cuts are generated by the provided generator class.
*
* @tparam Generator Class used to generate the cuts.
* @returns The number of cuts added.
*/
template<class Generator>
int add_single_row_cuts();
/**
* Gets a single row from the current tableau.
*
* @param index Index of the row to fetch.
* @returns The selected tableau row.
*/
Row* get_tableau_row(int index);
void read_basis();
void read_columns();
/**
* Solves the current problem, and prints some solution information.
*
* @returns The solution status, as returned by CPXgetstat.
*/
int solve(bool save_stats = false);
void dump_constraint(const Constraint &c, const char *msg = "");
void print_basis();
void flush_cuts();
void eta_print();
void eta_reset();
CplexRow constraint_to_cplex_row(const Constraint &cut);
Constraint cplex_row_to_constraint(const CplexRow &cplex_row);
void print_solution(double *x);
void find_good_rows();
int n_rows;
int n_cols;
double *ub;
double *lb;
int *cstat;
CplexRow *cplex_rows;
int eta_count;
int eta_total;
time_t eta_start;
set<CplexRow> cut_buffer;
double *first_solution;
double *current_solution;
double *optimal_solution;
long total_cuts;
int current_round;
int n_good_rows;
int *good_rows;
};
#include "cplex_helper.tpp"
#endif /* CPLEX_HELPER_HPP_ */

View File

@@ -0,0 +1,104 @@
/*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CPLEX_HELPER_TPP_
#define CPLEX_HELPER_TPP_
#include <cmath>
#include <omp.h>
#include <ctime>
#include <thread>
#include <unistd.h>
#include <onerow/stats.hpp>
#include <onerow/cplex_helper.hpp>
#include <onerow/params.hpp>
using std::cout;
using std::endl;
#include <gperftools/heap-profiler.h>
#include <gperftools/malloc_extension.h>
template<class Generator>
int CplexHelper::add_single_row_cuts()
{
total_cuts = 0;
if(n_good_rows < 0)
find_good_rows();
eta_reset();
eta_count = 0;
eta_total = n_good_rows;
std::thread eta(&CplexHelper::eta_print, this);
Stats::start_timer();
#pragma omp parallel for schedule(dynamic)
for (int i = 0; i < n_good_rows; i++)
{
Row *row = get_tableau_row(good_rows[i]);
//Row *row = good_rows[i];
Generator generator(*row);
while (generator.has_next())
{
Constraint *cut = generator.next();
if (cut->pi.nz() == 0)
{
delete cut;
continue;
}
#ifdef PRETEND_TO_ADD_CUTS
delete(cut);
#else
#pragma omp critical(cplex)
{
add_cut(cut);
}
#endif
#ifdef ENABLE_EXTENDED_STATISTICS
Stats::add_generated_cut(current_round, cut->depth);
#endif
}
#pragma omp critical
{
eta_count++;
}
delete row;
}
Stats::end_timer();
eta.join();
flush_cuts();
time_printf("Added %d violated cuts...\n", total_cuts);
return 0;
}
#endif /* CPLEX_HELPER_TPP_ */

View File

@@ -0,0 +1,56 @@
/*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GEOMETRY_HPP_
#define GEOMETRY_HPP_
#include<qxx/rational.hpp>
#include<qxx/svec.hpp>
typedef q::mpq rational;
typedef q::svec svec;
/**
* Models a two-dimensional rational point (x,y).
*/
struct Point {
rational x;
rational y;
Point();
Point(rational x, rational y);
Point operator+(const Point& p) const;
Point operator-(const Point& p) const;
Point operator*(rational scale) const;
rational operator*(const Point& p) const;
};
/**
* Models a two-dimensional rational line, defined by a pair of points p1 and p2.
*/
struct Line {
Point p1;
Point p2;
Line();
Line(Point p1, Point p2);
Line(rational x1, rational y1, rational x2, rational y2);
};
std::ostream& operator<<(std::ostream& os, const Line &l);
std::ostream& operator<<(std::ostream& os, const Point &p);
#endif /* GEOMETRY_HPP_ */

View File

@@ -0,0 +1,37 @@
/*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GOMORY_CUT_GENERATOR_HPP_
#define GOMORY_CUT_GENERATOR_HPP_
#include "single_row_cut_generator.hpp"
/**
* This class can be used to generate classic (not fractional) Gomory cuts.
* The cuts are only valid for models with integral, non-negative variables.
*/
class GomoryCutGenerator: public SingleRowCutGenerator {
private:
bool finished;
public:
GomoryCutGenerator(Row &row);
~GomoryCutGenerator();
bool has_next();
Constraint* next();
};
#endif /* GOMORY_CUT_GENERATOR_HPP_ */

View File

@@ -0,0 +1,54 @@
#ifndef KNAPSACK_2_HPP_
#define KNAPSACK_2_HPP_
#include <vector>
#include <utility>
#include "qxx/rational.hpp"
#include "geometry.hpp"
using std::vector;
using std::pair;
// **************************************************************************
//
// **************************************************************************
#define KNAPSACK2_LEFT 0
#define KNAPSACK2_RIGHT 1
#define KNAPSACK2_BOTH 2
#define KNAPSACK2_RAY 3
class PairRational {
public:
size_t operator()(const pair<rational, rational> &k) const;
};
struct Knapsack2Vertex {
int side;
q::dvec lower, upper, opposed;
};
// **************************************************************************
//
// **************************************************************************
class Knapsack2 {
public:
Knapsack2();
Knapsack2(rational f, rational r1);
~Knapsack2();
void clear();
void eval(rational f, rational r1);
private:
void push(int side,
const q::dvec &l, const q::dvec &u, const q::dvec &o);
public:
vector<Knapsack2Vertex> list;
};
#endif

View File

@@ -0,0 +1,35 @@
/*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MIR_CUT_GENERATOR_HPP_
#define MIR_CUT_GENERATOR_HPP_
#include "single_row_cut_generator.hpp"
class MIRCutGenerator: public SingleRowCutGenerator {
private:
bool finished;
rational f(rational q1, rational q2);
rational h(rational q);
public:
MIRCutGenerator(Row &row);
~MIRCutGenerator();
bool has_next();
Constraint* next();
};
#endif /* MIR_CUT_GENERATOR_HPP_ */

View File

@@ -0,0 +1,41 @@
/*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PARAMS_HPP_
#define PARAMS_HPP_
const double ZERO_CUTOFF = 1e-8;
const double MAX_CUT_DYNAMISM = 1e6;
const double MIN_CUT_VIOLATION = 1e-6;
const long REDUCE_FACTOR_RHS = 1000000;
const long REDUCE_FACTOR_R1 = 1000;
const long REDUCE_FACTOR_COEFFICIENT = 1000000;
const int MAX_CUT_DEPTH = 200;
const int ETA_UPDATE_INTERVAL = 1;
const unsigned int MAX_CUT_BUFFER_SIZE = 100;
const double COEFFICIENT_SAFETY_MARGIN = 0.00001;
#define INTERSECTION_CUT_USE_DOUBLE
#define ENABLE_TRIVIAL_LIFTING
#define ENABLE_EXTENDED_STATISTICS
//#define PRETEND_TO_ADD_CUTS
#endif /* PARAMS_HPP_ */

View File

@@ -0,0 +1,107 @@
/*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SINGLE_ROW_CUT_GENERATOR_HPP_
#define SINGLE_ROW_CUT_GENERATOR_HPP_
#include <ilcplex/cplex.h>
#include <vector>
#include "geometry.hpp"
using std::vector;
/**
* Models a linear constraint.
*/
struct Constraint {
/**
* Vector that holds the coefficients of the variables.
*/
svec pi;
/**
* The right hand side of the constraint.
*/
rational pi_zero;
int depth;
/**
* Comparator used to sort the constraints.
*
* @returns bool True if this constraint should come before the given
* constraint when sorting.
*/
bool operator<(const Constraint &other) const;
bool operator==(const Constraint &other) const;
rational get_violation(const rational *x);
};
/**
* Models a single row from the simplex tableau.
*/
struct Row {
/**
* Constraint
*/
Constraint c;
/**
* Index of the basic variable this row corresponds to.
*/
int basic_var_index;
bool* is_integer;
};
/**
* A single row cut generator receives a row from the simplex tableau and generates one
* or more cuts that invalidate the current basic solution.
*/
class SingleRowCutGenerator {
protected:
const Row& row;
public:
/**
* Constructs a new generator that will generate cuts from the provided tableau row.
*/
SingleRowCutGenerator(Row &r);
/**
* Destructor.
*/
virtual ~SingleRowCutGenerator() {};
/**
* Returns true if more cuts can be generated from the tableau row.
*/
virtual bool has_next() = 0;
/**
* Retrieves a cut generated from the tableau row.
*
* @throws std::out_of_bounds if no more cuts can be generated from the current tableau row.
*/
virtual Constraint* next() = 0;
};
std::ostream& operator<<(std::ostream& os, const Constraint &c);
std::ostream& operator<<(std::ostream& os, const Row &r);
#endif

View File

@@ -0,0 +1,41 @@
/*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef STATS_HPP_
#define STATS_HPP_
#include <string>
using std::string;
namespace Stats {
void init();
void add_cut(int depth);
void add_generated_cut(int round, int depth);
void set_solution(int round, double sol, string status);
void set_input_filename(string n);
void add_trivial_lifting_m(unsigned long m);
void add_coefficient(bool integral);
void write_stats(string filename);
void start_timer();
void end_timer();
};
double get_current_time(void);
void time_printf(const char *fmt, ...);
#endif /* STATS_HPP_ */

View File

@@ -0,0 +1,132 @@
/*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WEDGE_CUT_GENERATOR_HPP_
#define WEDGE_CUT_GENERATOR_HPP_
#include "params.hpp"
#include "qxx/dmat.hpp"
#include "geometry.hpp"
#include "knapsack2.hpp"
#include "single_row_cut_generator.hpp"
/**
* Models a two-dimensional intersection cut, and its associated convex set.
* The convex set is given by
* \f[
* C = \{ x \in R^n : (d^i)^T(x-f) \leq 1 \},
* \f]
* where f is a point in the interior of C.
*/
class IntersectionCut {
public:
Point f;
Point *d;
const int n_faces;
/**
* Constructs a new intersection cut and its associated convex set from
* the data provided.
*
* @param f A fractional point in the interior of the convex set.
* @param n_faces The number of faces of the convex set.
* @param lines (Optional) Array of lines that support each face of the
* convex.
*/
IntersectionCut(Point f, int n_faces, const Line *lines = 0);
~IntersectionCut();
/**
* Sets the desired face of the convex set.
*
* @param index Index of the face.
* @param line Line that supports the face.
*/
void set_face(int index, Line line);
rational get_continuous_coefficient(rational rx, rational ry);
double get_trivial_lifting_coefficient_double(double rx, double ry);
rational get_trivial_lifting_coefficient(rational rx, rational ry);
void pre_lifting();
private:
double d_r0x, d_p, d_d0x, d_d0y, d_d1x, d_d1y;
rational p, r0x;
bool pre_lifting_ready;
};
/**
* Models an intersection cut associated with a wedge.
*/
class WedgeCut : public IntersectionCut {
public:
/**
* Constructs a wedge cut from the provided data.
*
* @param f A fractional point in the interior of the wedge.
* @param left A point on the left face of the wedge.
* @param apex The apex of the wedge.
* @param right A point on the right face of the wedge.
*/
WedgeCut(Point f, Point left, Point apex, Point right);
};
/**
* Models an intersection cut associated with a split.
*/
class SplitCut : public IntersectionCut {
public:
/**
* Constructs a split cut from the provided data.
*
* @param f A fractional point in the interior of the split
* @param left A point on the left face of the split
* @param right A poit on the right face of the split
* @param direction The direction in which the split in unbounded.
*/
SplitCut(Point f, Point left, Point right, Point direction);
};
/**
* This class can be used to generate wedge cuts.
*/
class WedgeCutGenerator: public SingleRowCutGenerator {
private:
bool finished;
q::dvec f, r1;
int r1_offset;
int cur_facet;
Knapsack2 knapsack;
static int max_depth;
int n_knapsacks;
private:
Constraint *cut;
void eval_next();
static q::dvec intersection(
q::dvec a, q::dvec b, q::dvec c, q::dvec d);
public:
WedgeCutGenerator(Row &row);
~WedgeCutGenerator();
bool has_next();
Constraint* next();
};
#endif /* WEDGE_CUT_GENERATOR_HPP_ */