/* * 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 . */ #include #include #include #include #include #include #include #include #include using std::cout; using std::endl; using std::min; static bool debug = false; IntersectionCut::IntersectionCut(Point _f, int _n, const Line *l) : f(_f), n_faces(_n), pre_lifting_ready(false) { d = new Point[n_faces]; if (l != 0) for (int i = 0; i < n_faces; i++) set_face(i, l[i]); } IntersectionCut::~IntersectionCut() { delete[] d; } void IntersectionCut::set_face(int index, Line line) { if (index < 0 || index >= n_faces) throw std::out_of_range(""); rational x1 = line.p1.x; rational y1 = line.p1.y; rational x2 = line.p2.x; rational y2 = line.p2.y; rational h[3] = { -y2 + y1, x2 - x1, x1 * y2 - x2 * y1 }; rational rhs = -(h[2] + h[0] * f.x + h[1] * f.y); if (rhs == rational(0)) throw std::invalid_argument(""); d[index].x = h[0] / rhs; d[index].y = h[1] / rhs; } rational IntersectionCut::get_continuous_coefficient(rational rx, rational ry) { #ifdef ENABLE_EXTENDED_STATISTICS Stats::add_coefficient(false); #endif rational max_coeff(-100000, 1); for (int i = 0; i < n_faces; i++) { rational coeff = rx * d[i].x + ry * d[i].y; if (coeff > max_coeff) max_coeff = coeff; } return max_coeff; } void IntersectionCut::pre_lifting() { rational r0y; rational fx = f.x, fy = f.y; rational d0x = d[0].x, d0y = d[0].y; rational d1x = d[1].x, d1y = d[1].y; rational apex_x, apex_y; rational w1 = rational(1) + (d0x * fx + d0y * fy); rational w2 = rational(1) + (d1x * fx + d1y * fy); rational m = (d0x*d1y-d0y*d1x); if (m == 0) { r0x = -d0y/d0x; r0y = 1; } else { apex_x = (d1y * w1 - d0y * w2) / m; apex_y = (-d1x * w1 + d0x * w2) / m; r0x = apex_x - fx; r0y = apex_y - fy; r0x /= r0y; r0y = 1; } assert(d0x < 0); assert(d1x > 0); p = r0x*d0x + r0y*d0y; assert(p == r0x*d1x + r0y*d1y); assert(p >= 0); this->d_p = p.get_double(); this->d_d1x = d1x.get_double(); this->d_d1y = d1y.get_double(); this->d_d0x = d0x.get_double(); this->d_d0y = d0y.get_double(); this->d_r0x = r0x.get_double(); pre_lifting_ready = true; } double IntersectionCut::get_trivial_lifting_coefficient_double(double rx, double ry) { if(!pre_lifting_ready) pre_lifting(); #ifdef ENABLE_EXTENDED_STATISTICS Stats::add_coefficient(true); #endif double a = 100000; unsigned long k2 = 0; unsigned long M = 10000; while (k2 < M) { double b = (k2*d_r0x-rx); double a1 = d_d1x * (rx + ceil(b)) + d_d1y * k2; double a2 = d_d0x * (rx + floor(b)) + d_d0y * k2; assert(rx + ceil(b) + 0.0001 >= d_r0x*k2); assert(rx + floor(b) - 0.0001 <= d_r0x*k2); assert(a1 >= 0); assert(a2 >= 0); if(a1 < a) a = a1; if(a2 < a) a = a2; if(fabs(d_p) < ZERO_CUTOFF) break; M = ceil(a/d_p); k2++; } #ifdef ENABLE_EXTENDED_STATISTICS Stats::add_trivial_lifting_m(k2); #endif assert(a >= 0); return a; } rational IntersectionCut::get_trivial_lifting_coefficient(rational rx, rational ry) { if(!pre_lifting_ready) pre_lifting(); #ifdef ENABLE_EXTENDED_STATISTICS Stats::add_coefficient(true); #endif rational a = rational(100000, 1); unsigned long k2 = 0; unsigned long M = 10000; rational b = -rx; while (k2 < M) { rational r_k2((signed) k2); rational a1 = d[1].x*(rx + b.ceil()) + d[1].y * r_k2; rational a2 = d[0].x*(rx + b.floor()) + d[0].y * r_k2; assert(rx + b.ceil() >= r0x*r_k2); assert(rx + b.floor() <= r0x*r_k2); assert(a1 >= 0); assert(a2 >= 0); if(a1 < a) a = a1; if(a2 < a) a = a2; if(p == 0) break; M = (a/p).ceil().get_double(); k2++; b += r0x; } return a; } WedgeCut::WedgeCut(Point _f, Point left, Point apex, Point right) : IntersectionCut(_f, 2) { set_face(0, Line(left, apex)); set_face(1, Line(apex, right)); } SplitCut::SplitCut(Point _f, Point left, Point right, Point direction) : IntersectionCut(_f, 2) { set_face(0, Line(left, left + direction)); set_face(1, Line(right, right + direction)); } WedgeCutGenerator::WedgeCutGenerator(Row &r) : SingleRowCutGenerator(r), finished(false), f(2), r1(2), r1_offset(-1), cur_facet(-1), n_knapsacks(0) { f[0] = r.c.pi_zero.frac(); f[1] = 0; cut = new Constraint; eval_next(); } WedgeCutGenerator::~WedgeCutGenerator() { delete cut; } bool WedgeCutGenerator::has_next() { return !finished; } Constraint* WedgeCutGenerator::next() { if (!has_next()) throw std::out_of_range(""); Constraint *old_cut = cut; cut = new Constraint; eval_next(); return(old_cut); } q::dvec WedgeCutGenerator::intersection( q::dvec a, q::dvec b, q::dvec c, q::dvec d) { q::dmat g(2,2); g.set_col(0, b - a); g.set_col(1, c - d); q::dvec mult = g.inv() * (c - a); q::dvec x = a + (b - a) * mult[0]; assert(x == c + (d - c) * mult[1]); return(x); } void WedgeCutGenerator::eval_next() { while (true) { if (0 <= cur_facet && cur_facet < (int) knapsack.list.size() && cur_facet <= MAX_CUT_DEPTH) break; r1_offset++; if (r1_offset >= row.c.pi.nz()) { finished = true; return; } int r1_index = row.c.pi.index(r1_offset); if(row.reduced_costs[r1_index] < row.cost_cutoff) continue; r1[0] = -row.c.pi.value(r1_offset).reduce(REDUCE_FACTOR_R1); r1[1] = 1; if (r1_index == row.basic_var_index) continue; if (!row.is_integer[r1_index]) continue; if (r1[0] == 0) continue; knapsack.clear(); knapsack.eval(f[0], r1[0]); n_knapsacks++; cur_facet = 0; } Line lines[2]; int side = knapsack.list[cur_facet].side; q::dvec &a1 = knapsack.list[cur_facet].lower; q::dvec &a2 = knapsack.list[cur_facet].upper; q::dvec &o = knapsack.list[cur_facet].opposed; if (side == KNAPSACK2_RAY) { a2 = o; q::dvec b1 = a1 + r1; q::dvec b2 = a2 + r1; lines[0] = Line(a1[0], a1[1], b1[0], b1[1]); lines[1] = Line(a2[0], a2[1], b2[0], b2[1]); } else { q::dvec apex = intersection(a1, a2, f, f + r1); if(side == KNAPSACK2_RIGHT) { lines[1] = Line(a1[0], a1[1], a2[0], a2[1]); lines[0] = Line(o[0], o[1], apex[0], apex[1]); } else { lines[0] = Line(a1[0], a1[1], a2[0], a2[1]); lines[1] = Line(o[0], o[1], apex[0], apex[1]); } } if(debug) cout << endl << lines[0] << " " << lines[1] << endl; cur_facet++; IntersectionCut ic(Point(f[0], f[1]), 2, lines); cut->pi.clear(); cut->pi_zero = -1; cut->pi.resize(row.c.pi.size()); cut->depth = cur_facet-1; Point ray; rational alpha, rx, ry; for (int l = 0; l < row.c.pi.nz(); l++) { int j = row.c.pi.index(l); if (j == row.basic_var_index) continue; rx = -row.c.pi.value(l); ry = (l == r1_offset ? 1 : 0); if (row.is_integer[j] && l != r1_offset) { #ifdef INTERSECTION_CUT_USE_DOUBLE cut->pi.push(j, -ic.get_trivial_lifting_coefficient_double( rx.get_double(), ry.get_double())); #else cut->pi.push(j, -ic.get_trivial_lifting_coefficient(rx, ry)); #endif } else { cut->pi.push(j, -ic.get_continuous_coefficient(rx, ry)); } if(debug) cout << "r" << j << ": (" << rx << ", " << ry << ") " << cut->pi[j] << endl; } }