Refactor infinity.c
This commit is contained in:
@@ -1,30 +1,25 @@
|
|||||||
[ 0.00] multirow (git-4d20687d04e75dc63c7bb84cbbfeb2261c6a6ab2)
|
[ 0.04] Reading problem instances/gt2.pre.mps.gz...
|
||||||
[ 0.00] mf-hpc-1-7.local 2017-03-11 22:40
|
[ 0.41] 28 rows, 201 cols
|
||||||
[ 0.00] Compile-time parameters:
|
[ 0.41] Storing column types...
|
||||||
[ 0.00] EPSILON: 1.000000e-08
|
[ 0.42] Relaxing integrality...
|
||||||
[ 0.00] GREEDY_BIG_E: 1.000000e+03
|
[ 0.43] Disabling presolve...
|
||||||
[ 0.00] GREEDY_MAX_GAP: 1.000000e-04
|
[ 0.43] Reading basis from file bases/gt2.pre.bas...
|
||||||
[ 0.00] Command line arguments:
|
[ 0.47] Optimizing...
|
||||||
[ 0.00] ../build/infinity.run --mir --greedy --problem instances/gt2.pre.mps.gz --basis bases/gt2.pre.bas --log 2row-cont/gt2.pre.log --stats 2row-cont/gt2.pre.yaml --solution solutions/gt2.pre.x
|
[ 0.74] opt = 20146.761297
|
||||||
[ 0.00] 28 rows, 201 cols
|
[ 0.74] Reading tableau rows...
|
||||||
[ 0.00] Storing column types...
|
[ 0.80] Reading solution from solutions/gt2.pre.x
|
||||||
[ 0.00] Relaxing integrality...
|
[ 0.83] Adding MIR cuts...
|
||||||
[ 0.00] Disabling presolve...
|
[ 1.09] opt = 20545.739873
|
||||||
[ 0.00] Optimizing...
|
[ 1.17] opt = 20565.114738
|
||||||
[ 0.00] opt = 20146.761297
|
[ 1.21] opt = 20628.064931
|
||||||
[ 0.00] Reading tableau rows...
|
[ 1.28] opt = 20756.821715
|
||||||
[ 0.00] Adding MIR cuts...
|
[ 1.28] Optimizing...
|
||||||
[ 0.00] opt = 20545.739873
|
[ 1.29] opt = 20756.821715
|
||||||
[ 0.00] opt = 20565.114738
|
[ 1.29] Adding greedy intersection cuts (2 rows)...
|
||||||
[ 0.00] opt = 20628.064931
|
[ 1.29] Finding combinations...
|
||||||
[ 0.00] opt = 20756.821715
|
[ 1.31] 249 combinations [0.05]
|
||||||
[ 0.00] Optimizing...
|
[ 1.75] opt = 20815.431583
|
||||||
[ 0.00] opt = 20756.821715
|
[ 3.27] opt = 21061.100847
|
||||||
[ 0.00] Adding greedy intersection cuts (2 rows)...
|
[ 7.74] Optimizing...
|
||||||
[ 0.00] Finding combinations...
|
[ 7.74] opt = 21061.100847
|
||||||
[ 0.00] 249 combinations [0.05]
|
[ 7.74] Writing stats to file 2row-cont/gt2.pre.yaml...
|
||||||
[ 0.00] opt = 20815.431583
|
|
||||||
[ 0.05] opt = 21061.100847
|
|
||||||
[ 0.26] Optimizing...
|
|
||||||
[ 0.26] opt = 21061.100847
|
|
||||||
[ 0.26] Writing stats to file 2row-cont/gt2.pre.yaml...
|
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ added-cuts:
|
|||||||
1: 7
|
1: 7
|
||||||
2: 2
|
2: 2
|
||||||
user-cpu-time:
|
user-cpu-time:
|
||||||
0: 0.000
|
0: 0.871
|
||||||
1: 0.000
|
1: 0.548
|
||||||
2: 0.267
|
2: 6.451
|
||||||
time-per-cut:
|
time-per-cut:
|
||||||
1: 0.000
|
1: 0.037
|
||||||
2: 0.001
|
2: 0.026
|
||||||
|
|||||||
@@ -1,40 +1,17 @@
|
|||||||
[ 0.00] multirow (git-4d20687d04e75dc63c7bb84cbbfeb2261c6a6ab2)
|
[ 0.00] Reading problem instances/harp2.pre.mps.gz...
|
||||||
[ 0.00] mf-hpc-1-7.local 2017-03-11 22:40
|
|
||||||
[ 0.00] Compile-time parameters:
|
|
||||||
[ 0.00] EPSILON: 1.000000e-08
|
|
||||||
[ 0.00] GREEDY_BIG_E: 1.000000e+03
|
|
||||||
[ 0.00] GREEDY_MAX_GAP: 1.000000e-04
|
|
||||||
[ 0.00] Command line arguments:
|
|
||||||
[ 0.00] ../build/infinity.run --mir --greedy --problem instances/harp2.pre.mps.gz --basis bases/harp2.pre.bas --log 2row-cont/harp2.pre.log --stats 2row-cont/harp2.pre.yaml --solution solutions/harp2.pre.x
|
|
||||||
[ 0.00] 92 rows, 1049 cols
|
[ 0.00] 92 rows, 1049 cols
|
||||||
[ 0.00] Storing column types...
|
[ 0.00] Storing column types...
|
||||||
[ 0.00] Relaxing integrality...
|
[ 0.00] Relaxing integrality...
|
||||||
[ 0.00] Disabling presolve...
|
[ 0.00] Disabling presolve...
|
||||||
[ 0.01] Optimizing...
|
[ 0.00] Reading basis from file bases/harp2.pre.bas...
|
||||||
[ 0.01] opt = -74325169.345138
|
[ 0.00] Optimizing...
|
||||||
[ 0.01] Reading tableau rows...
|
[ 0.00] opt = -74325169.345138
|
||||||
|
[ 0.00] Reading tableau rows...
|
||||||
|
[ 0.01] Reading solution from solutions/harp2.pre.x
|
||||||
[ 0.01] Adding MIR cuts...
|
[ 0.01] Adding MIR cuts...
|
||||||
[ 0.01] opt = -74315010.901620
|
[ 0.01] opt = -74315010.901620
|
||||||
[ 0.01] opt = -74314964.934360
|
|
||||||
[ 0.01] opt = -74313681.237627
|
|
||||||
[ 0.01] opt = -74313582.579756
|
|
||||||
[ 0.01] opt = -74293298.124331
|
[ 0.01] opt = -74293298.124331
|
||||||
[ 0.01] opt = -74292514.336406
|
[ 0.01] Cut cuts off known integral solution: -0.26968016 >= -0.42512401 (0) (/Users/axavier/.shared/research/multirow/multirow/src/cg.c:319)
|
||||||
[ 0.01] opt = -74281276.834560
|
[ 0.01] check_cut failed (1) (/Users/axavier/.shared/research/multirow/multirow/src/cg.c:339)
|
||||||
[ 0.01] opt = -74278931.707997
|
[ 0.01] add_cut failed (1) (/Users/axavier/.shared/research/multirow/multirow/src/cg.c:644)
|
||||||
[ 0.01] opt = -74274793.244156
|
[ 0.01] CG_add_single_row_cuts failed (1) (/Users/axavier/.shared/research/multirow/infinity/benchmark/src/main.c:397)
|
||||||
[ 0.01] opt = -74268371.376509
|
|
||||||
[ 0.01] opt = -74264893.739723
|
|
||||||
[ 0.01] opt = -74240861.206190
|
|
||||||
[ 0.01] opt = -74222594.677631
|
|
||||||
[ 0.01] Optimizing...
|
|
||||||
[ 0.01] opt = -74222594.677631
|
|
||||||
[ 0.01] Adding greedy intersection cuts (2 rows)...
|
|
||||||
[ 0.01] Finding combinations...
|
|
||||||
[ 0.02] 483 combinations [0.05]
|
|
||||||
[ 0.15] opt = -74222542.959159
|
|
||||||
[ 0.45] opt = -74222502.242291
|
|
||||||
[ 1.44] opt = -74222380.900680
|
|
||||||
[ 2.56] Optimizing...
|
|
||||||
[ 2.56] opt = -74222380.900680
|
|
||||||
[ 2.56] Writing stats to file 2row-cont/harp2.pre.yaml...
|
|
||||||
|
|||||||
@@ -25,14 +25,14 @@
|
|||||||
#include <multirow/stats.h>
|
#include <multirow/stats.h>
|
||||||
#include <multirow/util.h>
|
#include <multirow/util.h>
|
||||||
|
|
||||||
#include <infinity/greedy.h>
|
#include <infinity/infinity.h>
|
||||||
|
|
||||||
int ENABLE_LIFTING = 0;
|
int ENABLE_LIFTING = 0;
|
||||||
|
|
||||||
int MIN_N_ROWS = 2;
|
int MIN_N_ROWS = 2;
|
||||||
int MAX_N_ROWS = 2;
|
int MAX_N_ROWS = 2;
|
||||||
|
|
||||||
int DUMP_CUT = 0;
|
int SHOULD_DUMP_CUTS = 0;
|
||||||
int DUMP_CUT_N = 0;
|
int DUMP_CUT_N = 0;
|
||||||
|
|
||||||
int GENERATE_MIR = 0;
|
int GENERATE_MIR = 0;
|
||||||
@@ -415,8 +415,8 @@ int main(int argc,
|
|||||||
{
|
{
|
||||||
log_info("Adding greedy intersection cuts (%d rows)...\n", k);
|
log_info("Adding greedy intersection cuts (%d rows)...\n", k);
|
||||||
|
|
||||||
rval = CG_add_multirow_cuts(cg, k, (MultirowGeneratorCallback)
|
rval = CG_add_multirow_cuts(cg, k,
|
||||||
GREEDY_generate_cut);
|
(MultiRowGeneratorCallback) INFINITY_generate_cut);
|
||||||
abort_if(rval, "CG_add_multirow_cuts failed");
|
abort_if(rval, "CG_add_multirow_cuts failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,22 @@
|
|||||||
set(COMMON_SOURCES
|
set(COMMON_SOURCES
|
||||||
src/greedy-2d.c
|
src/infinity-2d.c
|
||||||
src/greedy-nd.c
|
src/greedy-nd.c
|
||||||
src/greedy-bsearch.c
|
src/greedy-bsearch.c
|
||||||
src/greedy.c
|
src/infinity.c
|
||||||
include/infinity/greedy-2d.h
|
include/infinity/infinity-2d.h
|
||||||
include/infinity/greedy-nd.h
|
include/infinity/greedy-nd.h
|
||||||
include/infinity/greedy-bsearch.h
|
include/infinity/greedy-bsearch.h
|
||||||
include/infinity/greedy.h)
|
include/infinity/infinity.h)
|
||||||
|
|
||||||
set(TEST_SOURCES
|
set(TEST_SOURCES
|
||||||
tests/greedy-2d-test.cpp
|
tests/infinity-2d-test.cpp
|
||||||
tests/greedy-nd-test.cpp)
|
tests/greedy-nd-test.cpp
|
||||||
|
tests/infinity-test.cpp)
|
||||||
|
|
||||||
add_library(infinity_static ${COMMON_SOURCES})
|
add_library(infinity_static ${COMMON_SOURCES})
|
||||||
set_target_properties(infinity_static PROPERTIES OUTPUT_NAME infinity)
|
set_target_properties(infinity_static PROPERTIES OUTPUT_NAME infinity)
|
||||||
target_include_directories (infinity_static PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories (infinity_static PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
add_executable(infinity-test.run ${COMMON_SOURCES} ${TEST_SOURCES})
|
add_executable(infinity-test.run ${COMMON_SOURCES} ${TEST_SOURCES})
|
||||||
|
target_compile_options(infinity-test.run PRIVATE "-fpermissive")
|
||||||
target_link_libraries(infinity-test.run gtest_main multirow_static lifting_static)
|
target_link_libraries(infinity-test.run gtest_main multirow_static lifting_static)
|
||||||
|
|||||||
@@ -13,19 +13,12 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#ifndef MULTIROW_GREEDY_H
|
|
||||||
#define MULTIROW_GREEDY_H
|
|
||||||
|
|
||||||
int GREEDY_write_sage_file(int nrows,
|
#ifndef MULTIROW_INFINITY_2D_H
|
||||||
int nrays,
|
#define MULTIROW_INFINITY_2D_H
|
||||||
const double *f,
|
|
||||||
const double *rays,
|
|
||||||
const double *bounds,
|
|
||||||
const char *filename);
|
|
||||||
|
|
||||||
int GREEDY_generate_cut(int nrows,
|
#include <multirow/cg.h>
|
||||||
struct Row **rows,
|
|
||||||
const char *column_types,
|
|
||||||
struct Row *cut);
|
|
||||||
|
|
||||||
#endif //MULTIROW_GREEDY_H
|
int INFINITY_2D_generate_cut(const struct MultiRowModel *model, double *bounds);
|
||||||
|
|
||||||
|
#endif //MULTIROW_INFINITY_2D_H
|
||||||
@@ -13,25 +13,12 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#ifndef MULTIROW_INFINITY_H
|
||||||
|
#define MULTIROW_INFINITY_H
|
||||||
|
|
||||||
#ifndef MULTIROW_GREEDY_2D_H
|
#include <multirow/cg.h>
|
||||||
#define MULTIROW_GREEDY_2D_H
|
#include <multirow/lp.h>
|
||||||
|
|
||||||
int GREEDY_2D_bound(const double *rays,
|
int INFINITY_generate_cut(struct Tableau *tableau, struct Row *cut);
|
||||||
const double *bounds,
|
|
||||||
int nrays,
|
|
||||||
const double *f,
|
|
||||||
const double *p,
|
|
||||||
double *epsilon,
|
|
||||||
double *v1,
|
|
||||||
double *v2,
|
|
||||||
int *index1,
|
|
||||||
int *index2);
|
|
||||||
|
|
||||||
int GREEDY_2D_generate_cut(const double *rays,
|
#endif //MULTIROW_INFINITY_H
|
||||||
int nrays,
|
|
||||||
const double *f,
|
|
||||||
double *bounds);
|
|
||||||
|
|
||||||
|
|
||||||
#endif //MULTIROW_GREEDY_2D_H
|
|
||||||
@@ -1,477 +0,0 @@
|
|||||||
/* Copyright (c) 2015 Alinson Xavier
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include <multirow/cg.h>
|
|
||||||
#include <multirow/double.h>
|
|
||||||
#include <multirow/util.h>
|
|
||||||
|
|
||||||
#include <infinity/greedy.h>
|
|
||||||
#include <infinity/greedy-2d.h>
|
|
||||||
#include <infinity/greedy-nd.h>
|
|
||||||
|
|
||||||
struct SortPair
|
|
||||||
{
|
|
||||||
int index;
|
|
||||||
void *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int _qsort_cmp_rays_angle(const void *p1,
|
|
||||||
const void *p2)
|
|
||||||
{
|
|
||||||
double *r1 = (double *) (((struct SortPair *) p1)->data);
|
|
||||||
double *r2 = (double *) (((struct SortPair *) p2)->data);
|
|
||||||
return sign(atan2(r1[0], r1[1]) - atan2(r2[0], r2[1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sort_rays_angle(double *rays,
|
|
||||||
int nrays,
|
|
||||||
double *beta)
|
|
||||||
{
|
|
||||||
int rval = 0;
|
|
||||||
|
|
||||||
int *map = 0;
|
|
||||||
double *rays_copy = 0;
|
|
||||||
double *beta_copy = 0;
|
|
||||||
struct SortPair *pairs = 0;
|
|
||||||
|
|
||||||
pairs = (struct SortPair *) malloc(nrays * sizeof(struct SortPair));
|
|
||||||
rays_copy = (double *) malloc(2 * nrays * sizeof(double));
|
|
||||||
beta_copy = (double*) malloc(nrays * sizeof(double));
|
|
||||||
abort_if(!pairs, "could not allocate pairs");
|
|
||||||
abort_if(!rays_copy, "could not allocate rays_copy");
|
|
||||||
abort_if(!beta_copy, "could not allocate beta_copy");
|
|
||||||
|
|
||||||
memcpy(rays_copy, rays, 2 * nrays * sizeof(double));
|
|
||||||
memcpy(beta_copy, beta, nrays * sizeof(double));
|
|
||||||
|
|
||||||
for (int i = 0; i < nrays; i++)
|
|
||||||
{
|
|
||||||
pairs[i].index = i;
|
|
||||||
pairs[i].data = &rays[2 * i];
|
|
||||||
}
|
|
||||||
|
|
||||||
qsort(pairs, nrays, sizeof(struct SortPair), _qsort_cmp_rays_angle);
|
|
||||||
|
|
||||||
for (int i = 0; i < nrays; i++)
|
|
||||||
{
|
|
||||||
beta[i] = beta_copy[pairs[i].index];
|
|
||||||
memcpy(&rays[2 * i], &rays_copy[2 * pairs[i].index], 2 *
|
|
||||||
sizeof(double));
|
|
||||||
}
|
|
||||||
|
|
||||||
CLEANUP:
|
|
||||||
if (pairs) free(pairs);
|
|
||||||
if (rays_copy) free(rays_copy);
|
|
||||||
if (beta_copy) free(beta_copy);
|
|
||||||
return rval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int scale_rays(double *rays,
|
|
||||||
int nrays,
|
|
||||||
double *scale)
|
|
||||||
{
|
|
||||||
int rval = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < nrays; i++)
|
|
||||||
{
|
|
||||||
rays[2*i] *= scale[i];
|
|
||||||
rays[2*i+1] *= scale[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
CLEANUP:
|
|
||||||
return rval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void print_row(const struct Row *row)
|
|
||||||
{
|
|
||||||
time_printf("Row:\n");
|
|
||||||
for (int i = 0; i < row->nz; i++)
|
|
||||||
time_printf(" %.4lfx%d\n", row->pi[i], row->indices[i]);
|
|
||||||
time_printf(" <= %.4lf [%d]\n", row->pi_zero, row->head);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_rays(const int *map,
|
|
||||||
const int *indices,
|
|
||||||
const double *f,
|
|
||||||
const double *rays,
|
|
||||||
const double *scale,
|
|
||||||
int nrays,
|
|
||||||
int nz,
|
|
||||||
int nrows)
|
|
||||||
{
|
|
||||||
time_printf("Mapping:\n");
|
|
||||||
for (int i = 0; i < nz; i++)
|
|
||||||
time_printf(" %4d: %4d x%-4d (scale=%.4lf)\n", i, map[i], indices[i],
|
|
||||||
scale[i]);
|
|
||||||
|
|
||||||
time_printf("Origin:\n");
|
|
||||||
for (int i = 0; i < nrows; i++)
|
|
||||||
time_printf(" %20.12lf\n", f[i]);
|
|
||||||
|
|
||||||
time_printf("Rays:\n");
|
|
||||||
for (int i = 0; i < nrays; i++)
|
|
||||||
{
|
|
||||||
time_printf(" ");
|
|
||||||
|
|
||||||
for (int j = 0; j < nrows; j++)
|
|
||||||
printf("%20.12lf ", rays[i * nrows + j]);
|
|
||||||
|
|
||||||
printf("angle=%.4lf ", atan2(rays[i * nrows], rays[i * nrows + 1]));
|
|
||||||
printf("norm=%.4lf ", fabs(rays[i * nrows]) + fabs(rays[i * nrows + 1]));
|
|
||||||
|
|
||||||
printf("[ ");
|
|
||||||
for (int j = 0; j < nz; j++)
|
|
||||||
if (map[j] == i) printf("%d ", indices[j]);
|
|
||||||
printf("]\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_cut(const struct Row *cut)
|
|
||||||
{
|
|
||||||
time_printf("Generated cut:\n");
|
|
||||||
for (int i = 0; i < cut->nz; i++)
|
|
||||||
time_printf(" %.4lfx%d\n", cut->pi[i], cut->indices[i]);
|
|
||||||
time_printf(" <= %.4lf\n", cut->pi_zero);
|
|
||||||
}
|
|
||||||
|
|
||||||
int GREEDY_write_sage_file(int nrows,
|
|
||||||
int nrays,
|
|
||||||
const double *f,
|
|
||||||
const double *rays,
|
|
||||||
const double *beta,
|
|
||||||
const char *filename)
|
|
||||||
{
|
|
||||||
int rval = 0;
|
|
||||||
|
|
||||||
FILE *fsage = fopen(filename, "w");
|
|
||||||
abort_iff(!fsage, "could not open %s", filename);
|
|
||||||
|
|
||||||
fprintf(fsage, "f=vector([");
|
|
||||||
for (int i = 0; i < nrows; i++)
|
|
||||||
fprintf(fsage, "%.20lf,", f[i]);
|
|
||||||
fprintf(fsage, "])\n");
|
|
||||||
|
|
||||||
fprintf(fsage, "R=matrix([\n");
|
|
||||||
for (int i = 0; i < nrays; i++)
|
|
||||||
{
|
|
||||||
fprintf(fsage, " [");
|
|
||||||
for (int j = 0; j < nrows; j++)
|
|
||||||
{
|
|
||||||
fprintf(fsage, "%.20lf,", rays[i * nrows + j]);
|
|
||||||
}
|
|
||||||
fprintf(fsage, "],\n");
|
|
||||||
}
|
|
||||||
fprintf(fsage, "])\n");
|
|
||||||
|
|
||||||
fprintf(fsage, "pi=vector([\n");
|
|
||||||
for (int k = 0; k < nrays; k++)
|
|
||||||
fprintf(fsage, " %.12lf,\n", 1 / beta[k]);
|
|
||||||
fprintf(fsage, "])\n");
|
|
||||||
|
|
||||||
CLEANUP:
|
|
||||||
fclose(fsage);
|
|
||||||
return rval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int create_cut(const int nrows,
|
|
||||||
const char *column_types,
|
|
||||||
const int nrays,
|
|
||||||
const double *f,
|
|
||||||
const int lfree_nrays,
|
|
||||||
const double *lfree_rays,
|
|
||||||
const double *beta,
|
|
||||||
const double *extracted_rays,
|
|
||||||
const int nvars,
|
|
||||||
const int *variable_to_ray,
|
|
||||||
const int *indices,
|
|
||||||
const double *scale,
|
|
||||||
struct Row *cut)
|
|
||||||
{
|
|
||||||
int rval = 0;
|
|
||||||
|
|
||||||
cut->nz = nvars;
|
|
||||||
cut->pi = (double *) malloc(nvars * sizeof(double));
|
|
||||||
cut->indices = (int *) malloc(nvars * sizeof(int));
|
|
||||||
abort_if(!cut->pi, "could not allocate cut->pi");
|
|
||||||
abort_if(!cut->indices, "could not allocate cut->indices");
|
|
||||||
|
|
||||||
struct LP lp;
|
|
||||||
|
|
||||||
rval = LP_open(&lp);
|
|
||||||
abort_if(rval, "LP_open failed");
|
|
||||||
|
|
||||||
rval = GREEDY_create_psi_lp(nrows, lfree_nrays, f, lfree_rays, beta, &lp);
|
|
||||||
abort_if(rval, "create_psi_lp failed");
|
|
||||||
|
|
||||||
for (int i = 0; i < nvars; i++)
|
|
||||||
{
|
|
||||||
double value;
|
|
||||||
const double *q = &extracted_rays[variable_to_ray[i] * nrows];
|
|
||||||
|
|
||||||
if(ENABLE_LIFTING && column_types[indices[i]] == MILP_INTEGER)
|
|
||||||
{
|
|
||||||
rval = GREEDY_ND_pi(nrows, lfree_nrays, f, lfree_rays, beta, q,
|
|
||||||
scale[i], &lp, &value);
|
|
||||||
abort_if(rval, "GREEDY_ND_pi failed");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rval = GREEDY_ND_psi(nrows, lfree_nrays, f, lfree_rays, beta, q,
|
|
||||||
scale[i], &lp, &value);
|
|
||||||
abort_if(rval, "GREEDY_ND_psi failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
log_verbose(" psi[%4d] = %20.12lf %d\n", indices[i], value);
|
|
||||||
|
|
||||||
value *= 1.0001;
|
|
||||||
value = DOUBLE_max(value, 0.0001);
|
|
||||||
|
|
||||||
cut->indices[i] = indices[i];
|
|
||||||
cut->pi[i] = - value;
|
|
||||||
}
|
|
||||||
|
|
||||||
cut->pi_zero = -1.0;
|
|
||||||
|
|
||||||
CLEANUP:
|
|
||||||
LP_free(&lp);
|
|
||||||
return rval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef TEST_SOURCE
|
|
||||||
int GREEDY_generate_cut(int nrows,
|
|
||||||
struct Row **rows,
|
|
||||||
const char *column_types,
|
|
||||||
struct Row *cut)
|
|
||||||
{
|
|
||||||
int rval = 0;
|
|
||||||
double *f = 0;
|
|
||||||
long max_nrays = 0;
|
|
||||||
|
|
||||||
f = (double *) malloc(nrows * sizeof(double));
|
|
||||||
abort_if(!f, "could not allocate f");
|
|
||||||
|
|
||||||
for (int i = 0; i < nrows; i++)
|
|
||||||
{
|
|
||||||
f[i] = frac(rows[i]->pi_zero);
|
|
||||||
if (DOUBLE_eq(f[i], 1.0)) f[i] = 0.0;
|
|
||||||
|
|
||||||
max_nrays += rows[i]->nz;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nz;
|
|
||||||
int nrays;
|
|
||||||
int *variable_to_ray = 0;
|
|
||||||
int *indices = 0;
|
|
||||||
double *extracted_rays = 0;
|
|
||||||
double *scale = 0;
|
|
||||||
|
|
||||||
double *beta = 0;
|
|
||||||
double *scaled_rays = 0;
|
|
||||||
|
|
||||||
int lfree_nrays = 0;
|
|
||||||
double *lfree_rays = 0;
|
|
||||||
|
|
||||||
variable_to_ray = (int *) malloc(max_nrays * sizeof(int));
|
|
||||||
indices = (int *) malloc(max_nrays * sizeof(int));
|
|
||||||
scale = (double *) malloc(max_nrays * sizeof(double));
|
|
||||||
extracted_rays = (double *) malloc(nrows * max_nrays * sizeof(double));
|
|
||||||
abort_if(!variable_to_ray, "could not allocate variable_to_ray");
|
|
||||||
abort_if(!indices, "could not allocate indices");
|
|
||||||
abort_if(!scale, "could not allocate scale");
|
|
||||||
abort_if(!extracted_rays, "could not allocate extracted_rays");
|
|
||||||
|
|
||||||
lfree_rays = (double*) malloc(nrows * (max_nrays + 100) * sizeof(double));
|
|
||||||
abort_if(!lfree_rays, "could not allocate lfree_rays");
|
|
||||||
|
|
||||||
rval = CG_extract_rays_from_rows(nrows, rows, extracted_rays, &nrays,
|
|
||||||
variable_to_ray, scale, indices, &nz);
|
|
||||||
abort_if(rval, "CG_extract_rays_from_rows failed");
|
|
||||||
|
|
||||||
for (double norm_cutoff = 0.00; norm_cutoff <= 5.0; norm_cutoff+= 0.1)
|
|
||||||
{
|
|
||||||
lfree_nrays = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < nrays; i++)
|
|
||||||
{
|
|
||||||
int keep = 1;
|
|
||||||
double *r = &extracted_rays[nrows * i];
|
|
||||||
|
|
||||||
for (int j = 0; j < lfree_nrays; j++)
|
|
||||||
{
|
|
||||||
double *q = &extracted_rays[nrows * j];
|
|
||||||
double norm = 0;
|
|
||||||
|
|
||||||
for(int k = 0; k < nrows; k++)
|
|
||||||
norm += fabs(r[k] - q[k]);
|
|
||||||
|
|
||||||
if(norm <= norm_cutoff)
|
|
||||||
{
|
|
||||||
keep = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(keep)
|
|
||||||
{
|
|
||||||
memcpy(&lfree_rays[nrows * lfree_nrays], r, nrows * sizeof(double));
|
|
||||||
lfree_nrays++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug(" norm_cutoff=%8.2lf nrays=%8d\n", norm_cutoff, lfree_nrays);
|
|
||||||
|
|
||||||
if(lfree_nrays < MAX_N_RAYS) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ENABLE_LIFTING)
|
|
||||||
{
|
|
||||||
abort_if(nrows > 3, "not implemented");
|
|
||||||
|
|
||||||
int n_extra_rays;
|
|
||||||
double extra_rays[100];
|
|
||||||
|
|
||||||
if(nrows == 2)
|
|
||||||
{
|
|
||||||
extra_rays[0] = 0.0001;
|
|
||||||
extra_rays[1] = 0.0000;
|
|
||||||
|
|
||||||
extra_rays[2] = -0.0001;
|
|
||||||
extra_rays[3] = 0.0001;
|
|
||||||
|
|
||||||
extra_rays[4] = -0.0001;
|
|
||||||
extra_rays[5] = -0.0001;
|
|
||||||
|
|
||||||
n_extra_rays = 3;
|
|
||||||
}
|
|
||||||
else if(nrows == 3)
|
|
||||||
{
|
|
||||||
extra_rays[0] = 0.0000;
|
|
||||||
extra_rays[1] = 0.0000;
|
|
||||||
extra_rays[2] = 0.0001;
|
|
||||||
|
|
||||||
extra_rays[3] = 0.0001;
|
|
||||||
extra_rays[4] = 0.0000;
|
|
||||||
extra_rays[5] = -0.0001;
|
|
||||||
|
|
||||||
extra_rays[6] = -0.0001;
|
|
||||||
extra_rays[7] = 0.0000;
|
|
||||||
extra_rays[8] = -0.0001;
|
|
||||||
|
|
||||||
extra_rays[ 9] = -0.0001;
|
|
||||||
extra_rays[10] = -0.0001;
|
|
||||||
extra_rays[11] = -0.0001;
|
|
||||||
|
|
||||||
n_extra_rays = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for(int i = 0; i < n_extra_rays; i++)
|
|
||||||
{
|
|
||||||
double *r = &extra_rays[nrows * i];
|
|
||||||
|
|
||||||
double scale;
|
|
||||||
int found, index;
|
|
||||||
|
|
||||||
rval = CG_find_ray(nrows, lfree_rays, lfree_nrays, r, &found,
|
|
||||||
&scale, &index);
|
|
||||||
abort_if(rval, "CG_find_ray failed");
|
|
||||||
|
|
||||||
if(!found) {
|
|
||||||
memcpy(&lfree_rays[nrows * lfree_nrays], r, nrows *
|
|
||||||
sizeof(double));
|
|
||||||
lfree_nrays++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(lfree_nrays < 3)
|
|
||||||
{
|
|
||||||
rval = ERR_NO_CUT;
|
|
||||||
cut->pi = 0;
|
|
||||||
cut->indices = 0;
|
|
||||||
goto CLEANUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug("Extracted %d rays\n", lfree_nrays);
|
|
||||||
if_verbose_level
|
|
||||||
{
|
|
||||||
print_rays(variable_to_ray, indices, f, extracted_rays, scale, nrays,
|
|
||||||
nz, nrows);
|
|
||||||
}
|
|
||||||
|
|
||||||
beta = (double *) malloc((lfree_nrays) * sizeof(double));
|
|
||||||
abort_if(!beta, "could not allocate beta");
|
|
||||||
|
|
||||||
log_verbose("Computing lattice-free set...\n");
|
|
||||||
|
|
||||||
if(nrows == 2)
|
|
||||||
{
|
|
||||||
rval = sort_rays_angle(lfree_rays, lfree_nrays, beta);
|
|
||||||
abort_if(rval, "sort_rays_angle failed");
|
|
||||||
|
|
||||||
rval = GREEDY_2D_generate_cut(lfree_rays, lfree_nrays, f, beta);
|
|
||||||
if(rval)
|
|
||||||
{
|
|
||||||
rval = ERR_NO_CUT;
|
|
||||||
goto CLEANUP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rval = GREEDY_ND_generate_cut(nrows, lfree_nrays, f, lfree_rays, beta);
|
|
||||||
if(rval)
|
|
||||||
{
|
|
||||||
rval = ERR_NO_CUT;
|
|
||||||
goto CLEANUP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(DUMP_CUT)
|
|
||||||
{
|
|
||||||
char filename[100];
|
|
||||||
sprintf(filename, "cut-%03d.sage", DUMP_CUT_N++);
|
|
||||||
|
|
||||||
time_printf("Writing %s...\n", filename);
|
|
||||||
rval = GREEDY_write_sage_file(nrows, lfree_nrays, f, lfree_rays, beta,
|
|
||||||
filename);
|
|
||||||
abort_if(rval, "GREEDY_write_sage_file failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
rval = create_cut(nrows, column_types, nrays, f, lfree_nrays, lfree_rays,
|
|
||||||
beta, extracted_rays, nz, variable_to_ray, indices, scale, cut);
|
|
||||||
abort_if(rval, "create_cut failed");
|
|
||||||
|
|
||||||
if_verbose_level print_cut(cut);
|
|
||||||
|
|
||||||
CLEANUP:
|
|
||||||
if (f) free(f);
|
|
||||||
if (variable_to_ray) free(variable_to_ray);
|
|
||||||
if (beta) free(beta);
|
|
||||||
if (indices) free(indices);
|
|
||||||
if (scale) free(scale);
|
|
||||||
if (scaled_rays) free(scaled_rays);
|
|
||||||
if (lfree_rays) free(lfree_rays);
|
|
||||||
return rval;
|
|
||||||
}
|
|
||||||
#endif // TEST_SOURCE
|
|
||||||
@@ -21,9 +21,9 @@
|
|||||||
#include <multirow/geometry.h>
|
#include <multirow/geometry.h>
|
||||||
#include <multirow/double.h>
|
#include <multirow/double.h>
|
||||||
#include <multirow/util.h>
|
#include <multirow/util.h>
|
||||||
#include <multirow/rational.h>
|
#include <multirow/cg.h>
|
||||||
|
|
||||||
#include <infinity/greedy-2d.h>
|
#include <infinity/infinity-2d.h>
|
||||||
|
|
||||||
static int get_bounding_box(int nrows,
|
static int get_bounding_box(int nrows,
|
||||||
int nrays,
|
int nrays,
|
||||||
@@ -390,18 +390,16 @@ CLEANUP:
|
|||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TEST_SOURCE
|
static int bound(const double *rays,
|
||||||
|
const double *bounds,
|
||||||
int GREEDY_2D_bound(const double *rays,
|
int nrays,
|
||||||
const double *bounds,
|
const double *f,
|
||||||
int nrays,
|
const double *p,
|
||||||
const double *f,
|
double *epsilon,
|
||||||
const double *p,
|
double *v1,
|
||||||
double *epsilon,
|
double *v2,
|
||||||
double *v1,
|
int *index1,
|
||||||
double *v2,
|
int *index2)
|
||||||
int *index1,
|
|
||||||
int *index2)
|
|
||||||
{
|
{
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
|
|
||||||
@@ -518,19 +516,21 @@ int GREEDY_2D_bound(const double *rays,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CLEANUP:
|
CLEANUP:
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int GREEDY_2D_generate_cut(const double *original_rays,
|
#ifndef TEST_SOURCE
|
||||||
const int nrays,
|
|
||||||
const double *f,
|
|
||||||
double *bounds)
|
int INFINITY_2D_generate_cut(const struct MultiRowModel *model, double *bounds)
|
||||||
{
|
{
|
||||||
log_verbose("GREEDY_2D_generate_cut\n");
|
log_verbose("INFINITY_2D_generate_cut\n");
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
int nrays = model->nrays;
|
||||||
|
double *f = model->f;
|
||||||
|
|
||||||
double *scale = 0;
|
double *scale = 0;
|
||||||
double *rays = 0;
|
double *rays = 0;
|
||||||
@@ -545,7 +545,7 @@ int GREEDY_2D_generate_cut(const double *original_rays,
|
|||||||
abort_if(!rays, "could not allocate rays");
|
abort_if(!rays, "could not allocate rays");
|
||||||
abort_if(!scale, "could not allocate scale");
|
abort_if(!scale, "could not allocate scale");
|
||||||
|
|
||||||
memcpy(rays, original_rays, 2 * nrays * sizeof(double));
|
memcpy(rays, model->rays, 2 * nrays * sizeof(double));
|
||||||
|
|
||||||
rval = scale_to_chull(rays, nrays, scale);
|
rval = scale_to_chull(rays, nrays, scale);
|
||||||
abort_if(rval, "scale_to_chull failed");
|
abort_if(rval, "scale_to_chull failed");
|
||||||
@@ -581,9 +581,8 @@ int GREEDY_2D_generate_cut(const double *original_rays,
|
|||||||
|
|
||||||
log_verbose(" p=%.2lf %.2lf\n", p[0], p[1]);
|
log_verbose(" p=%.2lf %.2lf\n", p[0], p[1]);
|
||||||
|
|
||||||
rval = GREEDY_2D_bound(rays, bounds, nrays, f, p, &epsilon, v1, v2,
|
rval = bound(rays, bounds, nrays, f, p, &epsilon, v1, v2, &i1, &i2);
|
||||||
&i1, &i2);
|
abort_if(rval, "bound failed");
|
||||||
abort_if(rval, "GREEDY_2D_bound failed");
|
|
||||||
|
|
||||||
log_verbose(" epsilon=%.2lf\n", epsilon);
|
log_verbose(" epsilon=%.2lf\n", epsilon);
|
||||||
|
|
||||||
@@ -720,8 +719,6 @@ int GREEDY_2D_generate_cut(const double *original_rays,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(is_split) break;
|
if(is_split) break;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i=0; i<nrays; i++)
|
for(int i=0; i<nrays; i++)
|
||||||
481
infinity/library/src/infinity.c
Normal file
481
infinity/library/src/infinity.c
Normal file
@@ -0,0 +1,481 @@
|
|||||||
|
/* Copyright (c) 2015 Alinson Xavier
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <multirow/cg.h>
|
||||||
|
#include <multirow/double.h>
|
||||||
|
#include <multirow/util.h>
|
||||||
|
|
||||||
|
#include <infinity/infinity.h>
|
||||||
|
#include <infinity/infinity-2d.h>
|
||||||
|
#include <infinity/greedy-nd.h>
|
||||||
|
|
||||||
|
struct SortPair
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two rays according to their angles.
|
||||||
|
*
|
||||||
|
* The input are two SortPairs, where the data points to a double[2]. If the
|
||||||
|
* two rays are pointing to exactly opposite direction, returns 1.
|
||||||
|
*
|
||||||
|
* @param p1 a pointer to a SortPair containing the first ray.
|
||||||
|
* @param p2 a pointer to a SortPair containing the second ray.
|
||||||
|
* @return -1, 1 or 0, if the second ray is in clockwise, counter-clockwise
|
||||||
|
* or aligned, respectively, to the first ray.
|
||||||
|
*/
|
||||||
|
static int _qsort_cmp_rays_angle(const void *p1, const void *p2)
|
||||||
|
{
|
||||||
|
double *r1 = (double *) (((struct SortPair *) p1)->data);
|
||||||
|
double *r2 = (double *) (((struct SortPair *) p2)->data);
|
||||||
|
return sign(atan2(r1[0], r1[1]) - atan2(r2[0], r2[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sorts a list of rays according to their angle.
|
||||||
|
*
|
||||||
|
* @param rays the rays to be sorted
|
||||||
|
* @param nrays the number of rays in the list
|
||||||
|
* @param beta a list of doubles, to be sorted together with the rays
|
||||||
|
*
|
||||||
|
* @return zero if successful, non-zero otherwise
|
||||||
|
*/
|
||||||
|
static int sort_rays_angle(double *rays, int nrays, double *beta)
|
||||||
|
{
|
||||||
|
int rval = 0;
|
||||||
|
|
||||||
|
double *rays_copy = 0;
|
||||||
|
double *beta_copy = 0;
|
||||||
|
struct SortPair *pairs = 0;
|
||||||
|
|
||||||
|
pairs = (struct SortPair *) malloc(nrays * sizeof(struct SortPair));
|
||||||
|
rays_copy = (double *) malloc(2 * nrays * sizeof(double));
|
||||||
|
beta_copy = (double *) malloc(nrays * sizeof(double));
|
||||||
|
abort_if(!pairs, "could not allocate pairs");
|
||||||
|
abort_if(!rays_copy, "could not allocate rays_copy");
|
||||||
|
abort_if(!beta_copy, "could not allocate beta_copy");
|
||||||
|
|
||||||
|
memcpy(rays_copy, rays, 2 * nrays * sizeof(double));
|
||||||
|
memcpy(beta_copy, beta, nrays * sizeof(double));
|
||||||
|
|
||||||
|
for (int i = 0; i < nrays; i++)
|
||||||
|
{
|
||||||
|
pairs[i].index = i;
|
||||||
|
pairs[i].data = &rays[2 * i];
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(pairs, (size_t) nrays, sizeof(struct SortPair),
|
||||||
|
_qsort_cmp_rays_angle);
|
||||||
|
|
||||||
|
for (int i = 0; i < nrays; i++)
|
||||||
|
{
|
||||||
|
beta[i] = beta_copy[pairs[i].index];
|
||||||
|
memcpy(&rays[2 * i], &rays_copy[2 * pairs[i].index],
|
||||||
|
2 * sizeof(double));
|
||||||
|
}
|
||||||
|
|
||||||
|
CLEANUP:
|
||||||
|
if (pairs) free(pairs);
|
||||||
|
if (rays_copy) free(rays_copy);
|
||||||
|
if (beta_copy) free(beta_copy);
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_row(const struct Row *row)
|
||||||
|
{
|
||||||
|
time_printf("Row:\n");
|
||||||
|
for (int i = 0; i < row->nz; i++)
|
||||||
|
time_printf(" %.4lfx%d\n", row->pi[i], row->indices[i]);
|
||||||
|
time_printf(" <= %.4lf [%d]\n", row->pi_zero, row->head);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_rays(const struct Tableau *tableau,
|
||||||
|
const struct RayMap *map,
|
||||||
|
const double *f,
|
||||||
|
const double *rays,
|
||||||
|
int nrays)
|
||||||
|
{
|
||||||
|
int nrows = tableau->nrows;
|
||||||
|
|
||||||
|
time_printf("Ray map:\n");
|
||||||
|
for (int i = 0; i < map->nvars; i++)
|
||||||
|
time_printf(" %4d: %4d x%-4d (scale=%.4lf)\n", i,
|
||||||
|
map->variable_to_ray[i], map->indices[i], map->ray_scale[i]);
|
||||||
|
|
||||||
|
time_printf("Origin:\n");
|
||||||
|
for (int i = 0; i < nrows; i++)
|
||||||
|
time_printf(" %20.12lf\n", f[i]);
|
||||||
|
|
||||||
|
time_printf("Rays:\n");
|
||||||
|
for (int i = 0; i < nrays; i++)
|
||||||
|
{
|
||||||
|
time_printf(" ");
|
||||||
|
|
||||||
|
for (int j = 0; j < nrows; j++)
|
||||||
|
printf("%20.12lf ", rays[i * nrows + j]);
|
||||||
|
|
||||||
|
printf("angle=%.4lf ", atan2(rays[i * nrows], rays[i * nrows + 1]));
|
||||||
|
printf("norm=%.4lf ",
|
||||||
|
fabs(rays[i * nrows]) + fabs(rays[i * nrows + 1]));
|
||||||
|
|
||||||
|
printf("[ ");
|
||||||
|
for (int j = 0; j < map->nvars; j++)
|
||||||
|
if (map->variable_to_ray[j] == i)
|
||||||
|
printf("%d ", map->indices[j]);
|
||||||
|
printf("]\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_cut(const struct Row *cut)
|
||||||
|
{
|
||||||
|
time_printf("Generated cut:\n");
|
||||||
|
for (int i = 0; i < cut->nz; i++)
|
||||||
|
time_printf(" %.4lfx%d\n", cut->pi[i], cut->indices[i]);
|
||||||
|
time_printf(" <= %.4lf\n", cut->pi_zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int create_cut(const struct Tableau *tableau,
|
||||||
|
const struct RayMap *map,
|
||||||
|
const double *f,
|
||||||
|
const int lfree_nrays,
|
||||||
|
const double *lfree_rays,
|
||||||
|
const double *beta,
|
||||||
|
struct Row *cut)
|
||||||
|
{
|
||||||
|
int rval = 0;
|
||||||
|
int nvars = map->nvars;
|
||||||
|
int nrows = tableau->nrows;
|
||||||
|
|
||||||
|
cut->nz = nvars;
|
||||||
|
cut->pi = (double *) malloc(nvars * sizeof(double));
|
||||||
|
cut->indices = (int *) malloc(nvars * sizeof(int));
|
||||||
|
abort_if(!cut->pi, "could not allocate cut->pi");
|
||||||
|
abort_if(!cut->indices, "could not allocate cut->indices");
|
||||||
|
|
||||||
|
struct LP lp;
|
||||||
|
|
||||||
|
rval = LP_open(&lp);
|
||||||
|
abort_if(rval, "LP_open failed");
|
||||||
|
|
||||||
|
rval = GREEDY_create_psi_lp(nrows, lfree_nrays, f, lfree_rays, beta, &lp);
|
||||||
|
abort_if(rval, "create_psi_lp failed");
|
||||||
|
|
||||||
|
for (int i = 0; i < nvars; i++)
|
||||||
|
{
|
||||||
|
double value;
|
||||||
|
const double *q = &map->rays[map->variable_to_ray[i] * nrows];
|
||||||
|
|
||||||
|
if (ENABLE_LIFTING &&
|
||||||
|
tableau->column_types[map->indices[i]] == MILP_INTEGER)
|
||||||
|
{
|
||||||
|
rval = GREEDY_ND_pi(nrows, lfree_nrays, f, lfree_rays, beta, q,
|
||||||
|
map->ray_scale[i], &lp, &value);
|
||||||
|
abort_if(rval, "GREEDY_ND_pi failed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rval = GREEDY_ND_psi(nrows, lfree_nrays, f, lfree_rays, beta, q,
|
||||||
|
map->ray_scale[i], &lp, &value);
|
||||||
|
abort_if(rval, "GREEDY_ND_psi failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
log_verbose(" psi[%4d] = %20.12lf %d\n", map->indices[i], value);
|
||||||
|
|
||||||
|
value *= 1.0001;
|
||||||
|
value = DOUBLE_max(value, 0.0001);
|
||||||
|
|
||||||
|
cut->indices[i] = map->indices[i];
|
||||||
|
cut->pi[i] = -value;
|
||||||
|
}
|
||||||
|
|
||||||
|
cut->pi_zero = -1.0;
|
||||||
|
|
||||||
|
CLEANUP:
|
||||||
|
LP_free(&lp);
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int select_rays(const struct RayMap map,
|
||||||
|
const struct Tableau *tableau,
|
||||||
|
struct MultiRowModel *model)
|
||||||
|
{
|
||||||
|
int rval = 0;
|
||||||
|
int nrows = tableau->nrows;
|
||||||
|
|
||||||
|
for (double norm_cutoff = 0.00; norm_cutoff <= 5.0; norm_cutoff += 0.1)
|
||||||
|
{
|
||||||
|
model->nrays = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < map.nrays; i++)
|
||||||
|
{
|
||||||
|
int keep = 1;
|
||||||
|
double *r = &map.rays[tableau->nrows * i];
|
||||||
|
|
||||||
|
for (int j = 0; j < (model->nrays); j++)
|
||||||
|
{
|
||||||
|
double *q = &map.rays[tableau->nrows * j];
|
||||||
|
double norm = 0;
|
||||||
|
|
||||||
|
for (int k = 0; k < nrows; k++)
|
||||||
|
norm += fabs(r[k] - q[k]);
|
||||||
|
|
||||||
|
if (norm <= norm_cutoff)
|
||||||
|
{
|
||||||
|
keep = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keep)
|
||||||
|
{
|
||||||
|
memcpy(&model->rays[nrows * (model->nrays)], r,
|
||||||
|
nrows * sizeof(double));
|
||||||
|
model->nrays++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug(" norm_cutoff=%8.2lf nrays=%8d\n", norm_cutoff,
|
||||||
|
model->nrays);
|
||||||
|
|
||||||
|
if (model->nrays < MAX_N_RAYS) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CLEANUP:
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
append_extra_rays(const struct Tableau *tableau, double *rays, int *nrays)
|
||||||
|
{
|
||||||
|
int rval = 0;
|
||||||
|
int nrows = tableau->nrows;
|
||||||
|
int n_extra_rays = 0;
|
||||||
|
double extra_rays[100];
|
||||||
|
|
||||||
|
abort_if(nrows > 3, "not implemented");
|
||||||
|
|
||||||
|
if (nrows == 2)
|
||||||
|
{
|
||||||
|
extra_rays[0] = 0.0001;
|
||||||
|
extra_rays[1] = 0.0000;
|
||||||
|
|
||||||
|
extra_rays[2] = -0.0001;
|
||||||
|
extra_rays[3] = 0.0001;
|
||||||
|
|
||||||
|
extra_rays[4] = -0.0001;
|
||||||
|
extra_rays[5] = -0.0001;
|
||||||
|
|
||||||
|
n_extra_rays = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nrows == 3)
|
||||||
|
{
|
||||||
|
extra_rays[0] = 0.0000;
|
||||||
|
extra_rays[1] = 0.0000;
|
||||||
|
extra_rays[2] = 0.0001;
|
||||||
|
|
||||||
|
extra_rays[3] = 0.0001;
|
||||||
|
extra_rays[4] = 0.0000;
|
||||||
|
extra_rays[5] = -0.0001;
|
||||||
|
|
||||||
|
extra_rays[6] = -0.0001;
|
||||||
|
extra_rays[7] = 0.0000;
|
||||||
|
extra_rays[8] = -0.0001;
|
||||||
|
|
||||||
|
extra_rays[9] = -0.0001;
|
||||||
|
extra_rays[10] = -0.0001;
|
||||||
|
extra_rays[11] = -0.0001;
|
||||||
|
|
||||||
|
n_extra_rays = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < n_extra_rays; i++)
|
||||||
|
{
|
||||||
|
double *r = &extra_rays[nrows * i];
|
||||||
|
|
||||||
|
double scale;
|
||||||
|
int found, index;
|
||||||
|
rval = CG_find_ray(nrows, rays, *nrays, r, &found, &scale, &index);
|
||||||
|
abort_if(rval, "CG_find_ray failed");
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
memcpy(&rays[nrows * (*nrays)], r, nrows *
|
||||||
|
sizeof(double));
|
||||||
|
(*nrays)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CLEANUP:
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_sage_file(int nrows,
|
||||||
|
int nrays,
|
||||||
|
const double *f,
|
||||||
|
const double *rays,
|
||||||
|
const double *beta,
|
||||||
|
const char *filename)
|
||||||
|
{
|
||||||
|
int rval = 0;
|
||||||
|
|
||||||
|
FILE *fsage = fopen(filename, "w");
|
||||||
|
abort_iff(!fsage, "could not open %s", filename);
|
||||||
|
|
||||||
|
fprintf(fsage, "f=vector([");
|
||||||
|
for (int i = 0; i < nrows; i++)
|
||||||
|
fprintf(fsage, "%.20lf,", f[i]);
|
||||||
|
fprintf(fsage, "])\n");
|
||||||
|
|
||||||
|
fprintf(fsage, "R=matrix([\n");
|
||||||
|
for (int i = 0; i < nrays; i++)
|
||||||
|
{
|
||||||
|
fprintf(fsage, " [");
|
||||||
|
for (int j = 0; j < nrows; j++)
|
||||||
|
{
|
||||||
|
fprintf(fsage, "%.20lf,", rays[i * nrows + j]);
|
||||||
|
}
|
||||||
|
fprintf(fsage, "],\n");
|
||||||
|
}
|
||||||
|
fprintf(fsage, "])\n");
|
||||||
|
|
||||||
|
fprintf(fsage, "pi=vector([\n");
|
||||||
|
for (int k = 0; k < nrays; k++)
|
||||||
|
fprintf(fsage, " %.12lf,\n", 1 / beta[k]);
|
||||||
|
fprintf(fsage, "])\n");
|
||||||
|
|
||||||
|
CLEANUP:
|
||||||
|
fclose(fsage);
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dump_cut(const struct Tableau *tableau,
|
||||||
|
const double *rays,
|
||||||
|
int nrays,
|
||||||
|
const double *f,
|
||||||
|
const double *beta)
|
||||||
|
{
|
||||||
|
int rval = 0;
|
||||||
|
|
||||||
|
char filename[100];
|
||||||
|
sprintf(filename, "cut-%03d.sage", DUMP_CUT_N++);
|
||||||
|
|
||||||
|
time_printf("Writing %s...\n", filename);
|
||||||
|
rval = write_sage_file(tableau->nrows, nrays, f, rays, beta, filename);
|
||||||
|
abort_if(rval, "write_sage_file failed");
|
||||||
|
|
||||||
|
CLEANUP:
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef TEST_SOURCE
|
||||||
|
|
||||||
|
int INFINITY_generate_cut(struct Tableau *tableau, struct Row *cut)
|
||||||
|
{
|
||||||
|
int rval = 0;
|
||||||
|
int max_nrays = 0;
|
||||||
|
int nrows = tableau->nrows;
|
||||||
|
double *beta = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < tableau->nrows; i++)
|
||||||
|
max_nrays += tableau->rows[i]->nz;
|
||||||
|
|
||||||
|
struct MultiRowModel model;
|
||||||
|
rval = CG_init_model(&model, nrows, max_nrays + 100);
|
||||||
|
abort_if(rval, "CG_init_model failed");
|
||||||
|
|
||||||
|
rval = CG_extract_f_from_tableau(tableau, model.f);
|
||||||
|
abort_if(rval, "CG_extract_f_from_tableau failed");
|
||||||
|
|
||||||
|
struct RayMap map;
|
||||||
|
rval = CG_init_ray_map(&map, max_nrays, nrows);
|
||||||
|
abort_if(rval, "CG_init_ray_map failed");
|
||||||
|
|
||||||
|
rval = CG_extract_rays_from_tableau(tableau, &map);
|
||||||
|
abort_if(rval, "CG_extract_rays_from_rows failed");
|
||||||
|
|
||||||
|
rval = select_rays(map, tableau, &model);
|
||||||
|
abort_if(rval, "select_rays failed");
|
||||||
|
|
||||||
|
if (ENABLE_LIFTING)
|
||||||
|
{
|
||||||
|
rval = append_extra_rays(tableau, model.rays, &model.nrays);
|
||||||
|
abort_if(rval, "append_extra_rays failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
beta = (double *) malloc(model.nrays * sizeof(double));
|
||||||
|
abort_if(!beta, "could not allocate beta");
|
||||||
|
|
||||||
|
if (model.nrays < 3)
|
||||||
|
{
|
||||||
|
rval = ERR_NO_CUT;
|
||||||
|
cut->pi = 0;
|
||||||
|
cut->indices = 0;
|
||||||
|
goto CLEANUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug("Selected %d rays\n", nrays);
|
||||||
|
if_verbose_level print_rays(tableau, &map, model.f, map.rays, map.nrays);
|
||||||
|
|
||||||
|
log_verbose("Computing lattice-free set...\n");
|
||||||
|
if (nrows == 2)
|
||||||
|
{
|
||||||
|
rval = sort_rays_angle(model.rays, model.nrays, beta);
|
||||||
|
abort_if(rval, "sort_rays_angle failed");
|
||||||
|
|
||||||
|
rval = INFINITY_2D_generate_cut(&model, beta);
|
||||||
|
if (rval)
|
||||||
|
{
|
||||||
|
rval = ERR_NO_CUT;
|
||||||
|
goto CLEANUP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rval = GREEDY_ND_generate_cut(nrows, model.nrays, model.f, model.rays,
|
||||||
|
beta);
|
||||||
|
if (rval)
|
||||||
|
{
|
||||||
|
rval = ERR_NO_CUT;
|
||||||
|
goto CLEANUP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SHOULD_DUMP_CUTS)
|
||||||
|
{
|
||||||
|
rval = dump_cut(tableau, model.rays, model.nrays, model.f, beta);
|
||||||
|
abort_if(rval, "dump_cut failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
rval = create_cut(tableau, &map, model.f, model.nrays, model.rays, beta,
|
||||||
|
cut);
|
||||||
|
abort_if(rval, "create_cut failed");
|
||||||
|
|
||||||
|
if_verbose_level print_cut(cut);
|
||||||
|
|
||||||
|
CLEANUP:
|
||||||
|
if (beta) free(beta);
|
||||||
|
CG_free_model(&model);
|
||||||
|
CG_free_ray_map(&map);
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // TEST_SOURCE
|
||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#define TEST_SOURCE
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <multirow/lp.h>
|
#include <multirow/lp.h>
|
||||||
@@ -26,7 +28,7 @@ extern "C" {
|
|||||||
int ENABLE_LIFTING = 0;
|
int ENABLE_LIFTING = 0;
|
||||||
int MIN_N_ROWS = 2;
|
int MIN_N_ROWS = 2;
|
||||||
int MAX_N_ROWS = 2;
|
int MAX_N_ROWS = 2;
|
||||||
int DUMP_CUT = 0;
|
int SHOULD_DUMP_CUTS = 0;
|
||||||
int DUMP_CUT_N = 0;
|
int DUMP_CUT_N = 0;
|
||||||
|
|
||||||
TEST(GreedyNDTest, find_violated_cone_test)
|
TEST(GreedyNDTest, find_violated_cone_test)
|
||||||
|
|||||||
@@ -21,22 +21,30 @@ using namespace std;
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <multirow/util.h>
|
#include <multirow/util.h>
|
||||||
#include <infinity/greedy-2d.h>
|
#include <infinity/infinity-2d.h>
|
||||||
#include "../src/greedy-2d.c"
|
#include "../src/infinity-2d.c"
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BOUNDS_EPSILON 0.01
|
#define BOUNDS_EPSILON 0.01
|
||||||
|
|
||||||
TEST(Greedy2DTest, test_generate_cut_1)
|
TEST(Infinity2DTest, test_generate_cut_1)
|
||||||
{
|
{
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
double bounds[100];
|
double bounds[100];
|
||||||
double f[] = {1 / 4.0, 3 / 4.0};
|
|
||||||
double rays[] = {-2 / 5.0, 5 / 7.0, 0.0, 1.0, 1.0, 1.0, 4 / 5.0, -2 / 3.0,
|
|
||||||
-1.0, 0.0};
|
|
||||||
|
|
||||||
rval = GREEDY_2D_generate_cut(rays, 5, f, bounds);
|
double f[] = {1 / 4.0, 3 / 4.0};
|
||||||
abort_if(rval, "GREEDY_2D_generate_cut failed");
|
double rays[] = {
|
||||||
|
-2 / 5.0, 5 / 7.0,
|
||||||
|
0.0, 1.0,
|
||||||
|
1.0, 1.0,
|
||||||
|
4 / 5.0, -2 / 3.0,
|
||||||
|
-1.0, 0.0
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct MultiRowModel model = {f , rays, 5, 2};
|
||||||
|
|
||||||
|
rval = INFINITY_2D_generate_cut(&model, bounds);
|
||||||
|
abort_if(rval, "INFINITY_2D_generate_cut failed");
|
||||||
|
|
||||||
EXPECT_NEAR(23 / 50.0, bounds[0], BOUNDS_EPSILON);
|
EXPECT_NEAR(23 / 50.0, bounds[0], BOUNDS_EPSILON);
|
||||||
EXPECT_NEAR(23 / 42.0, bounds[1], BOUNDS_EPSILON);
|
EXPECT_NEAR(23 / 42.0, bounds[1], BOUNDS_EPSILON);
|
||||||
@@ -48,7 +56,7 @@ TEST(Greedy2DTest, test_generate_cut_1)
|
|||||||
if (rval) FAIL();
|
if (rval) FAIL();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Greedy2DTest, test_generate_cut_2)
|
TEST(Infinity2DTest, test_generate_cut_2)
|
||||||
{
|
{
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
double bounds[100];
|
double bounds[100];
|
||||||
@@ -61,8 +69,10 @@ TEST(Greedy2DTest, test_generate_cut_2)
|
|||||||
1.0, -1.0
|
1.0, -1.0
|
||||||
};
|
};
|
||||||
|
|
||||||
rval = GREEDY_2D_generate_cut(rays, 5, f, bounds);
|
const struct MultiRowModel model = {f , rays, 5, 2};
|
||||||
abort_if(rval, "GREEDY_2D_generate_cut failed");
|
|
||||||
|
rval = INFINITY_2D_generate_cut(&model, bounds);
|
||||||
|
abort_if(rval, "INFINITY_2D_generate_cut failed");
|
||||||
|
|
||||||
EXPECT_NEAR(0.5, bounds[0], BOUNDS_EPSILON);
|
EXPECT_NEAR(0.5, bounds[0], BOUNDS_EPSILON);
|
||||||
EXPECT_NEAR(0.5, bounds[1], BOUNDS_EPSILON);
|
EXPECT_NEAR(0.5, bounds[1], BOUNDS_EPSILON);
|
||||||
@@ -74,15 +84,17 @@ TEST(Greedy2DTest, test_generate_cut_2)
|
|||||||
if (rval) FAIL();
|
if (rval) FAIL();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Greedy2DTest, test_generate_cut_3)
|
TEST(Infinity2DTest, test_generate_cut_3)
|
||||||
{
|
{
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
double bounds[100];
|
double bounds[100];
|
||||||
double f[] = {5 / 22.0, 0.0};
|
double f[] = {5 / 22.0, 0.0};
|
||||||
double rays[] = {-1 / 22.0, 0.0, 0.0, 1 / 18.0, 1 / 22.0, 0.0};
|
double rays[] = {-1 / 22.0, 0.0, 0.0, 1 / 18.0, 1 / 22.0, 0.0};
|
||||||
|
|
||||||
rval = GREEDY_2D_generate_cut(rays, 3, f, bounds);
|
const struct MultiRowModel model = {f , rays, 3, 2};
|
||||||
abort_if(rval, "GREEDY_2D_generate_cut failed");
|
|
||||||
|
rval = INFINITY_2D_generate_cut(&model, bounds);
|
||||||
|
abort_if(rval, "INFINITY_2D_generate_cut failed");
|
||||||
|
|
||||||
EXPECT_NEAR(5.0, bounds[0], BOUNDS_EPSILON);
|
EXPECT_NEAR(5.0, bounds[0], BOUNDS_EPSILON);
|
||||||
EXPECT_NEAR(17.0, bounds[2], BOUNDS_EPSILON);
|
EXPECT_NEAR(17.0, bounds[2], BOUNDS_EPSILON);
|
||||||
@@ -92,7 +104,7 @@ TEST(Greedy2DTest, test_generate_cut_3)
|
|||||||
if (rval) FAIL();
|
if (rval) FAIL();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Greedy2DTest, scale_to_chull_test)
|
TEST(Infinity2DTest, scale_to_chull_test)
|
||||||
{
|
{
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
|
|
||||||
@@ -140,7 +152,7 @@ CLEANUP:
|
|||||||
if(rval) FAIL();
|
if(rval) FAIL();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Greedy2DTest, scale_to_chull_test_2)
|
TEST(Infinity2DTest, scale_to_chull_test_2)
|
||||||
{
|
{
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
|
|
||||||
@@ -173,7 +185,7 @@ TEST(Greedy2DTest, scale_to_chull_test_2)
|
|||||||
if(rval) FAIL();
|
if(rval) FAIL();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Greedy2DTest, find_containing_cone_test)
|
TEST(Infinity2DTest, find_containing_cone_test)
|
||||||
{
|
{
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
|
|
||||||
@@ -213,7 +225,7 @@ TEST(Greedy2DTest, find_containing_cone_test)
|
|||||||
if(rval) FAIL();
|
if(rval) FAIL();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Greedy2DTest, find_containing_cone_test_2)
|
TEST(Infinity2DTest, find_containing_cone_test_2)
|
||||||
{
|
{
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
|
|
||||||
@@ -232,7 +244,7 @@ TEST(Greedy2DTest, find_containing_cone_test_2)
|
|||||||
if(rval) FAIL();
|
if(rval) FAIL();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Greedy2DTest, find_containing_cone_test_3)
|
TEST(Infinity2DTest, find_containing_cone_test_3)
|
||||||
{
|
{
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
|
|
||||||
@@ -257,7 +269,7 @@ TEST(Greedy2DTest, find_containing_cone_test_3)
|
|||||||
if(rval) FAIL();
|
if(rval) FAIL();
|
||||||
}
|
}
|
||||||
|
|
||||||
//TEST(Greedy2DTest, test_generate_cut_4)
|
//TEST(Infinity2DTest, test_generate_cut_4)
|
||||||
//{
|
//{
|
||||||
// int rval = 0;
|
// int rval = 0;
|
||||||
// double bounds[100];
|
// double bounds[100];
|
||||||
@@ -265,8 +277,8 @@ TEST(Greedy2DTest, find_containing_cone_test_3)
|
|||||||
// double rays[] = {0, -1 / 38.0, -1 / 22.0, -1 / 38.0, 0, 1 / 38.0, -1 / 22.0,
|
// double rays[] = {0, -1 / 38.0, -1 / 22.0, -1 / 38.0, 0, 1 / 38.0, -1 / 22.0,
|
||||||
// 0, 1 / 22.0, 0, 1 / 22.0, 1 / 38.0};
|
// 0, 1 / 22.0, 0, 1 / 22.0, 1 / 38.0};
|
||||||
//
|
//
|
||||||
// rval = GREEDY_2D_generate_cut(rays, 6, f, bounds);
|
// rval = INFINITY_2D_generate_cut(rays, 6, f, bounds);
|
||||||
// abort_if(rval, "GREEDY_2D_generate_cut failed");
|
// abort_if(rval, "INFINITY_2D_generate_cut failed");
|
||||||
//
|
//
|
||||||
// EXPECT_NEAR(20.0, bounds[0], BOUNDS_EPSILON);
|
// EXPECT_NEAR(20.0, bounds[0], BOUNDS_EPSILON);
|
||||||
// EXPECT_NEAR(20.0, bounds[1], BOUNDS_EPSILON);
|
// EXPECT_NEAR(20.0, bounds[1], BOUNDS_EPSILON);
|
||||||
@@ -279,7 +291,7 @@ TEST(Greedy2DTest, find_containing_cone_test_3)
|
|||||||
// if (rval) FAIL();
|
// if (rval) FAIL();
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//TEST(Greedy2DTest, test_generate_cut_5)
|
//TEST(Infinity2DTest, test_generate_cut_5)
|
||||||
//{
|
//{
|
||||||
// int rval = 0;
|
// int rval = 0;
|
||||||
// double bounds[100];
|
// double bounds[100];
|
||||||
@@ -291,8 +303,8 @@ TEST(Greedy2DTest, find_containing_cone_test_3)
|
|||||||
// 0.04545454545454545581, 0.00000000000000000000,
|
// 0.04545454545454545581, 0.00000000000000000000,
|
||||||
// 0.04545454545454545581, 0.02631578947368420907};
|
// 0.04545454545454545581, 0.02631578947368420907};
|
||||||
//
|
//
|
||||||
// rval = GREEDY_2D_generate_cut(rays, 6, f, bounds);
|
// rval = INFINITY_2D_generate_cut(rays, 6, f, bounds);
|
||||||
// abort_if(rval, "GREEDY_2D_generate_cut failed");
|
// abort_if(rval, "INFINITY_2D_generate_cut failed");
|
||||||
//
|
//
|
||||||
// EXPECT_NEAR(20.0, bounds[0], BOUNDS_EPSILON);
|
// EXPECT_NEAR(20.0, bounds[0], BOUNDS_EPSILON);
|
||||||
// EXPECT_NEAR(20.0, bounds[1], BOUNDS_EPSILON);
|
// EXPECT_NEAR(20.0, bounds[1], BOUNDS_EPSILON);
|
||||||
@@ -307,7 +319,7 @@ TEST(Greedy2DTest, find_containing_cone_test_3)
|
|||||||
//
|
//
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
//TEST(Greedy2DTest, get_peak_ray_test_1)
|
//TEST(Infinity2DTest, get_peak_ray_test_1)
|
||||||
//{
|
//{
|
||||||
// int rval = 0;
|
// int rval = 0;
|
||||||
//
|
//
|
||||||
@@ -340,7 +352,7 @@ TEST(Greedy2DTest, find_containing_cone_test_3)
|
|||||||
// if(rval) FAIL();
|
// if(rval) FAIL();
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//TEST(Greedy2DTest, get_peak_ray_test_2)
|
//TEST(Infinity2DTest, get_peak_ray_test_2)
|
||||||
//{
|
//{
|
||||||
// int rval = 0;
|
// int rval = 0;
|
||||||
//
|
//
|
||||||
@@ -383,7 +395,7 @@ TEST(Greedy2DTest, find_containing_cone_test_3)
|
|||||||
// if(rval) FAIL();
|
// if(rval) FAIL();
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//TEST(Greedy2DTest, get_peak_ray_test_3)
|
//TEST(Infinity2DTest, get_peak_ray_test_3)
|
||||||
//{
|
//{
|
||||||
// int rval = 0;
|
// int rval = 0;
|
||||||
//
|
//
|
||||||
@@ -401,7 +413,7 @@ TEST(Greedy2DTest, find_containing_cone_test_3)
|
|||||||
// if(rval) FAIL();
|
// if(rval) FAIL();
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//TEST(Greedy2DTest, nearest_lattice_point_test_1)
|
//TEST(Infinity2DTest, nearest_lattice_point_test_1)
|
||||||
//{
|
//{
|
||||||
// int rval = 0;
|
// int rval = 0;
|
||||||
//
|
//
|
||||||
@@ -440,7 +452,7 @@ TEST(Greedy2DTest, find_containing_cone_test_3)
|
|||||||
// if(rval) FAIL();
|
// if(rval) FAIL();
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//TEST(Greedy2DTest, nearest_lattice_point_test_2)
|
//TEST(Infinity2DTest, nearest_lattice_point_test_2)
|
||||||
//{
|
//{
|
||||||
// int rval = 0;
|
// int rval = 0;
|
||||||
//
|
//
|
||||||
@@ -460,7 +472,7 @@ TEST(Greedy2DTest, find_containing_cone_test_3)
|
|||||||
// if(rval) FAIL();
|
// if(rval) FAIL();
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//TEST(Greedy2DTest, find_normal_test)
|
//TEST(Infinity2DTest, find_normal_test)
|
||||||
//{
|
//{
|
||||||
// int rval = 0;
|
// int rval = 0;
|
||||||
//
|
//
|
||||||
@@ -496,7 +508,7 @@ TEST(Greedy2DTest, find_containing_cone_test_3)
|
|||||||
// if(rval) FAIL();
|
// if(rval) FAIL();
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//TEST(Greedy2DTest, check_rays_parallel)
|
//TEST(Infinity2DTest, check_rays_parallel)
|
||||||
//{
|
//{
|
||||||
// double r1[] = {1.0, 2.0};
|
// double r1[] = {1.0, 2.0};
|
||||||
// double r2[] = {2.0, 4.0};
|
// double r2[] = {2.0, 4.0};
|
||||||
@@ -521,7 +533,7 @@ TEST(Greedy2DTest, find_containing_cone_test_3)
|
|||||||
// EXPECT_FALSE(match);
|
// EXPECT_FALSE(match);
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//TEST(Greedy2DTest, find_ray)
|
//TEST(Infinity2DTest, find_ray)
|
||||||
//{
|
//{
|
||||||
// double rays[] = {1.0, 2.0, -1.0, 0.0, -5.0, -5.0};
|
// double rays[] = {1.0, 2.0, -1.0, 0.0, -5.0, -5.0};
|
||||||
// int nrays = 3;
|
// int nrays = 3;
|
||||||
@@ -557,7 +569,7 @@ TEST(Greedy2DTest, find_containing_cone_test_3)
|
|||||||
// EXPECT_FALSE(found);
|
// EXPECT_FALSE(found);
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//TEST(Greedy2DTest, extract_rays_from_two_sparse_rows_test)
|
//TEST(Infinity2DTest, extract_rays_from_two_sparse_rows_test)
|
||||||
//{
|
//{
|
||||||
// int rval = 0;
|
// int rval = 0;
|
||||||
//
|
//
|
||||||
91
infinity/library/tests/infinity-test.cpp
Normal file
91
infinity/library/tests/infinity-test.cpp
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/* Copyright (c) 2015-2017 Alinson Xavier
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#define TEST_SOURCE
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "../src/infinity.c"
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(InfinityTest, cmp_ray_angle_test)
|
||||||
|
{
|
||||||
|
double r0[] = { 1.0, 0.0 };
|
||||||
|
double r1[] = { 2.0, 0.0 };
|
||||||
|
double r2[] = { 1.0, 1.0 };
|
||||||
|
double r3[] = { -1.0, 0.0 };
|
||||||
|
double r4[] = { 1.0, -1.0 };
|
||||||
|
|
||||||
|
SortPair sp0 = { 0, &r0 };
|
||||||
|
SortPair sp1 = { 1, &r1 };
|
||||||
|
SortPair sp2 = { 2, &r2 };
|
||||||
|
SortPair sp3 = { 3, &r3 };
|
||||||
|
SortPair sp4 = { 4, &r4 };
|
||||||
|
|
||||||
|
EXPECT_EQ(_qsort_cmp_rays_angle(&sp0, &sp1), 0);
|
||||||
|
EXPECT_EQ(_qsort_cmp_rays_angle(&sp0, &sp2), 1);
|
||||||
|
EXPECT_EQ(_qsort_cmp_rays_angle(&sp0, &sp3), 1);
|
||||||
|
EXPECT_EQ(_qsort_cmp_rays_angle(&sp0, &sp4), -1);
|
||||||
|
|
||||||
|
EXPECT_EQ(_qsort_cmp_rays_angle(&sp2, &sp0), -1);
|
||||||
|
EXPECT_EQ(_qsort_cmp_rays_angle(&sp2, &sp1), -1);
|
||||||
|
EXPECT_EQ(_qsort_cmp_rays_angle(&sp2, &sp3), 1);
|
||||||
|
EXPECT_EQ(_qsort_cmp_rays_angle(&sp2, &sp4), -1);
|
||||||
|
|
||||||
|
EXPECT_EQ(_qsort_cmp_rays_angle(&sp3, &sp0), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(InfinityTest, sort_rays_angle_test)
|
||||||
|
{
|
||||||
|
int rval = 0;
|
||||||
|
|
||||||
|
int n_rays = 5;
|
||||||
|
double beta[] = {0, 1, 2, 3, 4};
|
||||||
|
SortPair sp0, sp1, sp2, sp3, sp4;
|
||||||
|
|
||||||
|
double rays[] = {
|
||||||
|
1.0, 1.0,
|
||||||
|
1.0, 0.0,
|
||||||
|
1.0, -1.0,
|
||||||
|
-1.0, 0.0,
|
||||||
|
2.0, 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
rval = sort_rays_angle(rays, n_rays, beta);
|
||||||
|
abort_if(rval, "sort_rays_angle failed");
|
||||||
|
|
||||||
|
sp0 = { 0, &rays[0] };
|
||||||
|
sp1 = { 1, &rays[2] };
|
||||||
|
sp2 = { 2, &rays[4] };
|
||||||
|
sp3 = { 3, &rays[6] };
|
||||||
|
sp4 = { 4, &rays[8] };
|
||||||
|
|
||||||
|
EXPECT_LE(_qsort_cmp_rays_angle(&sp0, &sp1), 0);
|
||||||
|
EXPECT_LE(_qsort_cmp_rays_angle(&sp1, &sp2), 0);
|
||||||
|
EXPECT_LE(_qsort_cmp_rays_angle(&sp2, &sp3), 0);
|
||||||
|
EXPECT_LE(_qsort_cmp_rays_angle(&sp3, &sp4), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(beta[0], 3);
|
||||||
|
EXPECT_EQ(beta[1], 0);
|
||||||
|
EXPECT_TRUE(beta[2] == 1 || beta[2] == 4);
|
||||||
|
EXPECT_TRUE(beta[3] == 1 || beta[3] == 4);
|
||||||
|
EXPECT_TRUE(beta[2] != beta[3]);
|
||||||
|
EXPECT_EQ(beta[4], 2);
|
||||||
|
|
||||||
|
CLEANUP:
|
||||||
|
if (rval) FAIL();
|
||||||
|
}
|
||||||
@@ -38,42 +38,54 @@ struct CG
|
|||||||
double *current_solution;
|
double *current_solution;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Tableau
|
||||||
|
{
|
||||||
|
int nrows;
|
||||||
|
struct Row **rows;
|
||||||
|
char *column_types;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RayMap
|
||||||
|
{
|
||||||
|
int nrays;
|
||||||
|
double *rays;
|
||||||
|
int *variable_to_ray;
|
||||||
|
double *ray_scale;
|
||||||
|
int *indices;
|
||||||
|
int nvars;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MultiRowModel
|
||||||
|
{
|
||||||
|
double *f;
|
||||||
|
double *rays;
|
||||||
|
int nrays;
|
||||||
|
int nrows;
|
||||||
|
};
|
||||||
|
|
||||||
typedef int (*SingleRowGeneratorCallback)(const struct Row *row,
|
typedef int (*SingleRowGeneratorCallback)(const struct Row *row,
|
||||||
char *column_types,
|
char *column_types,
|
||||||
struct Row *cut);
|
struct Row *cut);
|
||||||
|
|
||||||
typedef int (*MultirowGeneratorCallback)(int nrows,
|
typedef int (*MultiRowGeneratorCallback)(const struct Tableau *tableau,
|
||||||
struct Row **rows,
|
|
||||||
char *column_types,
|
|
||||||
struct Row *cut);
|
struct Row *cut);
|
||||||
|
|
||||||
int CG_init(struct LP *lp,
|
int CG_init(struct LP *lp, char *column_types, struct CG *cg);
|
||||||
char *column_types,
|
|
||||||
struct CG *cg);
|
|
||||||
|
|
||||||
void CG_free(struct CG *cg);
|
void CG_free(struct CG *cg);
|
||||||
|
|
||||||
int CG_add_single_row_cuts(struct CG *cg,
|
int CG_add_single_row_cuts(struct CG *cg, SingleRowGeneratorCallback generate);
|
||||||
SingleRowGeneratorCallback generate);
|
|
||||||
|
|
||||||
int CG_add_multirow_cuts(struct CG *cg,
|
int CG_add_multirow_cuts(struct CG *cg,
|
||||||
int nrows,
|
int nrows,
|
||||||
MultirowGeneratorCallback generate);
|
MultiRowGeneratorCallback generate);
|
||||||
|
|
||||||
int CG_set_integral_solution(struct CG *cg,
|
int CG_set_integral_solution(struct CG *cg, double *valid_solution);
|
||||||
double *valid_solution);
|
|
||||||
|
|
||||||
int CG_set_basic_solution(struct CG *cg,
|
int CG_set_basic_solution(struct CG *cg, double *basic_solution);
|
||||||
double *basic_solution);
|
|
||||||
|
|
||||||
int CG_extract_rays_from_rows(int nrows,
|
int CG_extract_rays_from_tableau(const struct Tableau *tableau,
|
||||||
struct Row **rows,
|
struct RayMap *map);
|
||||||
double *rays,
|
|
||||||
int *nrays,
|
|
||||||
int *variable_to_ray,
|
|
||||||
double *ray_scale,
|
|
||||||
int *indices,
|
|
||||||
int *nz);
|
|
||||||
|
|
||||||
int CG_boost_variable(int var,
|
int CG_boost_variable(int var,
|
||||||
double factor,
|
double factor,
|
||||||
@@ -92,4 +104,14 @@ int CG_find_ray(int dim,
|
|||||||
double *scale,
|
double *scale,
|
||||||
int *index);
|
int *index);
|
||||||
|
|
||||||
|
int CG_init_ray_map(struct RayMap *map, int max_nrays, int nrows);
|
||||||
|
|
||||||
|
void CG_free_ray_map(struct RayMap *map);
|
||||||
|
|
||||||
|
int CG_extract_f_from_tableau(const struct Tableau *tableau, double *f);
|
||||||
|
|
||||||
|
int CG_init_model(struct MultiRowModel *model, int nrows, int max_nrays);
|
||||||
|
|
||||||
|
void CG_free_model(struct MultiRowModel *model);
|
||||||
|
|
||||||
#endif //MULTIROW_CG_H
|
#endif //MULTIROW_CG_H
|
||||||
|
|||||||
@@ -77,7 +77,7 @@
|
|||||||
|
|
||||||
extern int BOOST_VAR;
|
extern int BOOST_VAR;
|
||||||
extern double BOOST_FACTOR;
|
extern double BOOST_FACTOR;
|
||||||
extern int DUMP_CUT;
|
extern int SHOULD_DUMP_CUTS;
|
||||||
extern int DUMP_CUT_N;
|
extern int DUMP_CUT_N;
|
||||||
|
|
||||||
extern int ENABLE_LIFTING;
|
extern int ENABLE_LIFTING;
|
||||||
|
|||||||
@@ -31,27 +31,27 @@ static int select_rows(struct CG *cg, int *row_selected)
|
|||||||
|
|
||||||
long histogram[100] = {0};
|
long histogram[100] = {0};
|
||||||
|
|
||||||
for(int i = 0; i < cg->nrows; i++)
|
for (int i = 0; i < cg->nrows; i++)
|
||||||
{
|
{
|
||||||
row_selected[i] = 1;
|
row_selected[i] = 1;
|
||||||
struct Row *r1 = cg->tableau_rows[i];
|
struct Row *r1 = cg->tableau_rows[i];
|
||||||
|
|
||||||
if(r1->head < 0 || cg->column_types[r1->head] != MILP_INTEGER)
|
if (r1->head < 0 || cg->column_types[r1->head] != MILP_INTEGER)
|
||||||
{
|
{
|
||||||
row_selected[i] = 0;
|
row_selected[i] = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
double dist = fabs(0.5 - frac(r1->pi_zero));
|
double dist = fabs(0.5 - frac(r1->pi_zero));
|
||||||
for(int k = 0; k < 100; k++)
|
for (int k = 0; k < 100; k++)
|
||||||
if(dist <= (k / 100.0))
|
if (dist <= (k / 100.0))
|
||||||
histogram[k]++;
|
histogram[k]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
double dist_cutoff = 0.5;
|
double dist_cutoff = 0.5;
|
||||||
for(int k = 0; k < 100; k++)
|
for (int k = 0; k < 100; k++)
|
||||||
{
|
{
|
||||||
if(histogram[k] > MAX_SELECTED_ROWS)
|
if (histogram[k] > MAX_SELECTED_ROWS)
|
||||||
{
|
{
|
||||||
dist_cutoff = k / 100.0;
|
dist_cutoff = k / 100.0;
|
||||||
break;
|
break;
|
||||||
@@ -59,14 +59,14 @@ static int select_rows(struct CG *cg, int *row_selected)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int selected_count = 0;
|
int selected_count = 0;
|
||||||
for(int i = 0; i < cg->nrows; i++)
|
for (int i = 0; i < cg->nrows; i++)
|
||||||
{
|
{
|
||||||
if(!row_selected[i]) continue;
|
if (!row_selected[i]) continue;
|
||||||
|
|
||||||
struct Row *r1 = cg->tableau_rows[i];
|
struct Row *r1 = cg->tableau_rows[i];
|
||||||
double dist = fabs(0.5 - frac(r1->pi_zero));
|
double dist = fabs(0.5 - frac(r1->pi_zero));
|
||||||
|
|
||||||
if(dist > dist_cutoff || selected_count >= MAX_SELECTED_ROWS)
|
if (dist > dist_cutoff || selected_count >= MAX_SELECTED_ROWS)
|
||||||
{
|
{
|
||||||
row_selected[i] = 0;
|
row_selected[i] = 0;
|
||||||
continue;
|
continue;
|
||||||
@@ -79,11 +79,8 @@ CLEANUP:
|
|||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int next_combination(int n,
|
static int
|
||||||
int k,
|
next_combination(int n, int k, int *array, int inc_index, int *finished)
|
||||||
int *array,
|
|
||||||
int inc_index,
|
|
||||||
int *finished)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
@@ -91,13 +88,13 @@ static int next_combination(int n,
|
|||||||
array[inc_index]++;
|
array[inc_index]++;
|
||||||
*finished = 0;
|
*finished = 0;
|
||||||
|
|
||||||
for(i = inc_index; i < k; i++)
|
for (i = inc_index; i < k; i++)
|
||||||
{
|
{
|
||||||
if(array[i] < n - i)
|
if (array[i] < n - i)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if(i+1 < k)
|
if (i + 1 < k)
|
||||||
array[i+1]++;
|
array[i + 1]++;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*finished = 1;
|
*finished = 1;
|
||||||
@@ -105,26 +102,22 @@ static int next_combination(int n,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int j = 1; j <= i; j++)
|
for (int j = 1; j <= i; j++)
|
||||||
array[i - j] = array[i] + j;
|
array[i - j] = array[i] + j;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ray_norm(int dim, const double *ray, double *norm)
|
||||||
static int ray_norm(int dim,
|
|
||||||
const double *ray,
|
|
||||||
double *norm)
|
|
||||||
{
|
{
|
||||||
*norm = 0;
|
*norm = 0;
|
||||||
|
|
||||||
for(int i = 0; i < dim; i++)
|
for (int i = 0; i < dim; i++)
|
||||||
*norm += fabs(ray[i]);
|
*norm += fabs(ray[i]);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Checks whether two rays are parallel. Also returns the scaling factor,
|
* Checks whether two rays are parallel. Also returns the scaling factor,
|
||||||
* in case they are.
|
* in case they are.
|
||||||
@@ -157,16 +150,17 @@ static int check_rays_parallel(int dim,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for(int i = 0; i < dim; i++)
|
for (int i = 0; i < dim; i++)
|
||||||
{
|
{
|
||||||
if(DOUBLE_sgn(r1[i]) != DOUBLE_sgn(r2[i]) ||
|
if (DOUBLE_sgn(r1[i]) != DOUBLE_sgn(r2[i]) ||
|
||||||
DOUBLE_neq(r1[i] * r2_norm, r2[i] * r1_norm))
|
DOUBLE_neq(r1[i] * r2_norm, r2[i] * r1_norm))
|
||||||
{
|
{
|
||||||
*match = 0;
|
*match = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_verbose(" %.12lf equals %.12lf\n", r1[i] * r2_norm, r2[i] * r1_norm);
|
log_verbose(" %.12lf equals %.12lf\n", r1[i] * r2_norm,
|
||||||
|
r2[i] * r1_norm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,9 +170,7 @@ CLEANUP:
|
|||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_row(const struct CG *cg, const struct Row *row)
|
||||||
static void print_row(const struct CG *cg,
|
|
||||||
const struct Row *row)
|
|
||||||
{
|
{
|
||||||
double *x = cg->integral_solution;
|
double *x = cg->integral_solution;
|
||||||
double *y = cg->basic_solution;
|
double *y = cg->basic_solution;
|
||||||
@@ -195,10 +187,8 @@ static void print_row(const struct CG *cg,
|
|||||||
time_printf(" <= %20.6lf [%d]\n", row->pi_zero, row->head);
|
time_printf(" <= %20.6lf [%d]\n", row->pi_zero, row->head);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
static int evaluate_row_pair(const struct Row *row1,
|
evaluate_row_pair(const struct Row *row1, const struct Row *row2, double *score)
|
||||||
const struct Row *row2,
|
|
||||||
double *score)
|
|
||||||
{
|
{
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
|
|
||||||
@@ -217,7 +207,7 @@ static int evaluate_row_pair(const struct Row *row1,
|
|||||||
if (i2 < row2->nz)
|
if (i2 < row2->nz)
|
||||||
idx2 = row2->indices[i2];
|
idx2 = row2->indices[i2];
|
||||||
|
|
||||||
if(idx1 == idx2) hit++;
|
if (idx1 == idx2) hit++;
|
||||||
|
|
||||||
int idx_min = min(idx1, idx2);
|
int idx_min = min(idx1, idx2);
|
||||||
|
|
||||||
@@ -230,14 +220,12 @@ static int evaluate_row_pair(const struct Row *row1,
|
|||||||
|
|
||||||
*score = (hit * 2.0) / (row1->nz + row2->nz);
|
*score = (hit * 2.0) / (row1->nz + row2->nz);
|
||||||
|
|
||||||
CLEANUP:
|
CLEANUP:
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static double replace_x(const double *pi,
|
static double
|
||||||
const int *indices,
|
replace_x(const double *pi, const int *indices, int nz, const double *x)
|
||||||
int nz,
|
|
||||||
const double *x)
|
|
||||||
{
|
{
|
||||||
double lhs = 0;
|
double lhs = 0;
|
||||||
|
|
||||||
@@ -247,7 +235,7 @@ static double replace_x(const double *pi,
|
|||||||
int idx = indices[i];
|
int idx = indices[i];
|
||||||
|
|
||||||
if (!DOUBLE_iszero(pii) && !DOUBLE_iszero(x[idx]))
|
if (!DOUBLE_iszero(pii) && !DOUBLE_iszero(x[idx]))
|
||||||
log_verbose(" %12.8lf * %12.8lf (x%d)\n", pii, x[idx], idx);
|
log_verbose(" %12.8lf * %12.8lf (x%d)\n", pii, x[idx], idx);
|
||||||
|
|
||||||
lhs += pii * x[idx];
|
lhs += pii * x[idx];
|
||||||
}
|
}
|
||||||
@@ -255,10 +243,7 @@ static double replace_x(const double *pi,
|
|||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int copy_solution(struct CG *cg, double *from, double **to)
|
||||||
static int copy_solution(struct CG *cg,
|
|
||||||
double *from,
|
|
||||||
double **to)
|
|
||||||
{
|
{
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
int ncols = LP_get_num_cols(cg->lp);
|
int ncols = LP_get_num_cols(cg->lp);
|
||||||
@@ -275,9 +260,7 @@ CLEANUP:
|
|||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int check_cut(struct CG *cg, struct Row *cut)
|
||||||
static int check_cut(struct CG *cg,
|
|
||||||
struct Row *cut)
|
|
||||||
{
|
{
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
|
|
||||||
@@ -286,7 +269,7 @@ static int check_cut(struct CG *cg,
|
|||||||
time_printf("Checking cut:\n");
|
time_printf("Checking cut:\n");
|
||||||
for (int i = 0; i < cut->nz; i++)
|
for (int i = 0; i < cut->nz; i++)
|
||||||
{
|
{
|
||||||
if(DOUBLE_iszero(cg->integral_solution[cut->indices[i]])) continue;
|
if (DOUBLE_iszero(cg->integral_solution[cut->indices[i]])) continue;
|
||||||
time_printf(" %12.8lf x%d", cut->pi[i], cut->indices[i]);
|
time_printf(" %12.8lf x%d", cut->pi[i], cut->indices[i]);
|
||||||
if (cg->integral_solution)
|
if (cg->integral_solution)
|
||||||
printf(" (=%12.8lf)", cg->integral_solution[cut->indices[i]]);
|
printf(" (=%12.8lf)", cg->integral_solution[cut->indices[i]]);
|
||||||
@@ -300,11 +283,11 @@ static int check_cut(struct CG *cg,
|
|||||||
log_verbose("Basic solution check:\n");
|
log_verbose("Basic solution check:\n");
|
||||||
|
|
||||||
double lhs = replace_x(cut->pi, cut->indices, cut->nz,
|
double lhs = replace_x(cut->pi, cut->indices, cut->nz,
|
||||||
cg->basic_solution);
|
cg->basic_solution);
|
||||||
|
|
||||||
log_verbose(" %.8lf > %.8lf\n", lhs, cut->pi_zero);
|
log_verbose(" %.8lf > %.8lf\n", lhs, cut->pi_zero);
|
||||||
abort_iff(!DOUBLE_geq(lhs, cut->pi_zero), "Cut fails to cut "
|
abort_iff(!DOUBLE_geq(lhs, cut->pi_zero), "Cut fails to cut "
|
||||||
"basic solution: %12.8lf < %12.8lf", lhs, cut->pi_zero);
|
"basic solution: %12.8lf < %12.8lf", lhs, cut->pi_zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cg->integral_solution)
|
if (cg->integral_solution)
|
||||||
@@ -312,7 +295,7 @@ static int check_cut(struct CG *cg,
|
|||||||
log_verbose("Integral solution check:\n");
|
log_verbose("Integral solution check:\n");
|
||||||
|
|
||||||
double lhs = replace_x(cut->pi, cut->indices, cut->nz,
|
double lhs = replace_x(cut->pi, cut->indices, cut->nz,
|
||||||
cg->integral_solution);
|
cg->integral_solution);
|
||||||
|
|
||||||
log_verbose(" %.8lf <= %.8lf\n", lhs, cut->pi_zero);
|
log_verbose(" %.8lf <= %.8lf\n", lhs, cut->pi_zero);
|
||||||
abort_iff(!DOUBLE_leq(lhs, cut->pi_zero), "Cut cuts off known integral "
|
abort_iff(!DOUBLE_leq(lhs, cut->pi_zero), "Cut cuts off known integral "
|
||||||
@@ -323,10 +306,7 @@ CLEANUP:
|
|||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int add_cut(struct CG *cg, struct Row *cut, int *ignored)
|
||||||
static int add_cut(struct CG *cg,
|
|
||||||
struct Row *cut,
|
|
||||||
int *ignored)
|
|
||||||
{
|
{
|
||||||
int rval;
|
int rval;
|
||||||
double *x = 0;
|
double *x = 0;
|
||||||
@@ -338,13 +318,12 @@ static int add_cut(struct CG *cg,
|
|||||||
rval = check_cut(cg, cut);
|
rval = check_cut(cg, cut);
|
||||||
abort_if(rval, "check_cut failed");
|
abort_if(rval, "check_cut failed");
|
||||||
|
|
||||||
lhs = replace_x(cut->pi, cut->indices, cut->nz,
|
lhs = replace_x(cut->pi, cut->indices, cut->nz, cg->current_solution);
|
||||||
cg->current_solution);
|
|
||||||
|
|
||||||
*ignored = 0;
|
*ignored = 0;
|
||||||
STATS_increment_generated_cuts();
|
STATS_increment_generated_cuts();
|
||||||
|
|
||||||
if(DOUBLE_leq(lhs, cut->pi_zero))
|
if (DOUBLE_leq(lhs, cut->pi_zero))
|
||||||
{
|
{
|
||||||
log_verbose("Ignoring cut (%12.8lf <= %12.8lf)\n", lhs, cut->pi_zero);
|
log_verbose("Ignoring cut (%12.8lf <= %12.8lf)\n", lhs, cut->pi_zero);
|
||||||
*ignored = 1;
|
*ignored = 1;
|
||||||
@@ -363,12 +342,12 @@ static int add_cut(struct CG *cg,
|
|||||||
rval = LP_get_obj_val(cg->lp, &obj);
|
rval = LP_get_obj_val(cg->lp, &obj);
|
||||||
abort_if(rval, "LP_get_obj_val failed");
|
abort_if(rval, "LP_get_obj_val failed");
|
||||||
|
|
||||||
if(DOUBLE_neq(obj, cg->last_obj_value))
|
if (DOUBLE_neq(obj, cg->last_obj_value))
|
||||||
log_info(" opt = %lf\n", obj);
|
log_info(" opt = %lf\n", obj);
|
||||||
|
|
||||||
cg->last_obj_value = obj;
|
cg->last_obj_value = obj;
|
||||||
|
|
||||||
x = (double*) malloc(cg->ncols * sizeof(double));
|
x = (double *) malloc(cg->ncols * sizeof(double));
|
||||||
abort_if(!x, "could not allocate x");
|
abort_if(!x, "could not allocate x");
|
||||||
|
|
||||||
rval = LP_get_x(cg->lp, x);
|
rval = LP_get_x(cg->lp, x);
|
||||||
@@ -381,7 +360,7 @@ static int add_cut(struct CG *cg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
CLEANUP:
|
CLEANUP:
|
||||||
if(x) free(x);
|
if (x) free(x);
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,43 +398,40 @@ CLEANUP:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CG_extract_rays_from_rows(int nrows,
|
int CG_extract_rays_from_tableau(const struct Tableau *tableau,
|
||||||
struct Row **rows,
|
struct RayMap *map)
|
||||||
double *rays,
|
|
||||||
int *nrays,
|
|
||||||
int *variable_to_ray,
|
|
||||||
double *ray_scale,
|
|
||||||
int *indices,
|
|
||||||
int *nz)
|
|
||||||
{
|
{
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
|
|
||||||
(*nz) = 0;
|
int nrows = tableau->nrows;
|
||||||
(*nrays) = 0;
|
double *rays = map->rays;
|
||||||
|
struct Row **rows = tableau->rows;
|
||||||
|
|
||||||
|
map->nvars = 0;
|
||||||
|
map->nrays = 0;
|
||||||
|
|
||||||
int *i = 0;
|
int *i = 0;
|
||||||
int *idx = 0;
|
int *idx = 0;
|
||||||
|
|
||||||
|
i = (int *) malloc(nrows * sizeof(int));
|
||||||
i = (int*) malloc(nrows * sizeof(int));
|
idx = (int *) malloc(nrows * sizeof(int));
|
||||||
idx = (int*) malloc(nrows * sizeof(int));
|
|
||||||
abort_if(!i, "could not allocate i");
|
abort_if(!i, "could not allocate i");
|
||||||
abort_if(!idx, "could not allocate idx");
|
abort_if(!idx, "could not allocate idx");
|
||||||
|
|
||||||
for(int j = 0; j < nrows; j++)
|
for (int j = 0; j < nrows; j++)
|
||||||
i[j] = 0;
|
i[j] = 0;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
double *r = &rays[nrows * (*nrays)];
|
double *r = &rays[nrows * (map->nrays)];
|
||||||
|
|
||||||
int idx_min = INT_MAX;
|
int idx_min = INT_MAX;
|
||||||
|
|
||||||
for(int j = 0; j < nrows; j++)
|
for (int j = 0; j < nrows; j++)
|
||||||
{
|
{
|
||||||
r[j] = 0.0;
|
r[j] = 0.0;
|
||||||
|
|
||||||
if(i[j] < rows[j]->nz)
|
if (i[j] < rows[j]->nz)
|
||||||
idx[j] = rows[j]->indices[i[j]];
|
idx[j] = rows[j]->indices[i[j]];
|
||||||
else
|
else
|
||||||
idx[j] = INT_MAX;
|
idx[j] = INT_MAX;
|
||||||
@@ -463,18 +439,18 @@ int CG_extract_rays_from_rows(int nrows,
|
|||||||
idx_min = min(idx_min, idx[j]);
|
idx_min = min(idx_min, idx[j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(idx_min == INT_MAX)
|
if (idx_min == INT_MAX)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
for(int j = 0; j < nrows; j++)
|
for (int j = 0; j < nrows; j++)
|
||||||
{
|
{
|
||||||
if(idx[j] > idx_min) continue;
|
if (idx[j] > idx_min) continue;
|
||||||
r[j] = -rows[j]->pi[i[j]];
|
r[j] = -rows[j]->pi[i[j]];
|
||||||
i[j]++;
|
i[j]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int j = 0; j < nrows; j++)
|
for (int j = 0; j < nrows; j++)
|
||||||
if(idx_min == rows[j]->head)
|
if (idx_min == rows[j]->head)
|
||||||
goto NEXT_RAY;
|
goto NEXT_RAY;
|
||||||
|
|
||||||
int found;
|
int found;
|
||||||
@@ -483,67 +459,65 @@ int CG_extract_rays_from_rows(int nrows,
|
|||||||
|
|
||||||
|
|
||||||
log_verbose(" extracted ray (%d):\n", idx_min);
|
log_verbose(" extracted ray (%d):\n", idx_min);
|
||||||
for(int j=0; j < nrows; j++)
|
for (int j = 0; j < nrows; j++)
|
||||||
log_verbose(" r[%d] = %.12lf\n", j, r[j]);
|
log_verbose(" r[%d] = %.12lf\n", j, r[j]);
|
||||||
|
|
||||||
rval = CG_find_ray(nrows, rays, *nrays, r, &found, &scale, &ray_index);
|
rval = CG_find_ray(nrows, rays, map->nrays, r, &found, &scale,
|
||||||
|
&ray_index);
|
||||||
abort_if(rval, "CG_find_ray failed");
|
abort_if(rval, "CG_find_ray failed");
|
||||||
|
|
||||||
if (!found)
|
if (!found)
|
||||||
{
|
{
|
||||||
log_verbose(" ray is new\n");
|
log_verbose(" ray is new\n");
|
||||||
scale = 1.0;
|
scale = 1.0;
|
||||||
ray_index = (*nrays)++;
|
ray_index = (map->nrays)++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log_verbose(" ray equals:\n");
|
log_verbose(" ray equals:\n");
|
||||||
double *q = &rays[ray_index * nrows];
|
double *q = &rays[ray_index * nrows];
|
||||||
for(int j=0; j < nrows; j++)
|
for (int j = 0; j < nrows; j++)
|
||||||
log_verbose(" r[%d] = %.12lf\n", j, q[j]);
|
log_verbose(" r[%d] = %.12lf\n", j, q[j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ray_scale[(*nz)] = scale;
|
map->ray_scale[map->nvars] = scale;
|
||||||
indices[(*nz)] = idx_min;
|
map->indices[map->nvars] = idx_min;
|
||||||
variable_to_ray[(*nz)] = ray_index;
|
map->variable_to_ray[map->nvars] = ray_index;
|
||||||
(*nz)++;
|
map->nvars++;
|
||||||
|
|
||||||
NEXT_RAY:
|
NEXT_RAY:;
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int j = 0; j < *nrays; j++)
|
for (int j = 0; j < map->nrays; j++)
|
||||||
{
|
{
|
||||||
double *r = &rays[nrows * j];
|
double *r = &rays[nrows * j];
|
||||||
|
|
||||||
double max_scale = 0.0;
|
double max_scale = 0.0;
|
||||||
|
|
||||||
for(int k = 0; k < *nz; k++)
|
for (int k = 0; k < map->nvars; k++)
|
||||||
{
|
{
|
||||||
if(variable_to_ray[k] != j) continue;
|
if (map->variable_to_ray[k] != j) continue;
|
||||||
if(ray_scale[k] < max_scale) continue;
|
if (map->ray_scale[k] < max_scale) continue;
|
||||||
max_scale = ray_scale[k];
|
max_scale = map->ray_scale[k];
|
||||||
}
|
}
|
||||||
|
|
||||||
abort_if(max_scale == 0.0, "max_scale is zero");
|
abort_if(max_scale == 0.0, "max_scale is zero");
|
||||||
|
|
||||||
for(int k = 0; k < *nz; k++)
|
for (int k = 0; k < map->nvars; k++)
|
||||||
if(variable_to_ray[k] == j) ray_scale[k] /= max_scale;
|
if (map->variable_to_ray[k] == j)
|
||||||
|
map->ray_scale[k] /= max_scale;
|
||||||
|
|
||||||
for(int k = 0; k < nrows; k++)
|
for (int k = 0; k < nrows; k++)
|
||||||
r[k] *= max_scale;
|
r[k] *= max_scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
CLEANUP:
|
CLEANUP:
|
||||||
if(idx) free(idx);
|
if (idx) free(idx);
|
||||||
if(i) free(i);
|
if (i) free(i);
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CG_init(struct LP *lp, char *column_types, struct CG *cg)
|
||||||
int CG_init(struct LP *lp,
|
|
||||||
char *column_types,
|
|
||||||
struct CG *cg)
|
|
||||||
{
|
{
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
|
|
||||||
@@ -581,7 +555,7 @@ int CG_init(struct LP *lp,
|
|||||||
abort_if(!cg->tableau_rows, "could not allocate cg->tableau_rows");
|
abort_if(!cg->tableau_rows, "could not allocate cg->tableau_rows");
|
||||||
|
|
||||||
rval = LP_get_tableau(lp, cg->tableau_rows, cg->cstat, cg->rstat, cg->ub,
|
rval = LP_get_tableau(lp, cg->tableau_rows, cg->cstat, cg->rstat, cg->ub,
|
||||||
cg->lb);
|
cg->lb);
|
||||||
abort_if(rval, "LP_get_tableau failed");
|
abort_if(rval, "LP_get_tableau failed");
|
||||||
|
|
||||||
cg_initial_time = get_user_time();
|
cg_initial_time = get_user_time();
|
||||||
@@ -590,7 +564,6 @@ CLEANUP:
|
|||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CG_free(struct CG *cg)
|
void CG_free(struct CG *cg)
|
||||||
{
|
{
|
||||||
if (!cg) return;
|
if (!cg) return;
|
||||||
@@ -613,9 +586,7 @@ void CG_free(struct CG *cg)
|
|||||||
free(cg);
|
free(cg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CG_add_single_row_cuts(struct CG *cg, SingleRowGeneratorCallback generate)
|
||||||
int CG_add_single_row_cuts(struct CG *cg,
|
|
||||||
SingleRowGeneratorCallback generate)
|
|
||||||
{
|
{
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
|
|
||||||
@@ -663,80 +634,79 @@ int estimate_multirow_cut_count(struct CG *cg,
|
|||||||
|
|
||||||
*total_count = 0;
|
*total_count = 0;
|
||||||
|
|
||||||
row_indices = (int*) malloc(nrows * sizeof(int));
|
row_indices = (int *) malloc(nrows * sizeof(int));
|
||||||
abort_if(!row_indices, "could not allocate row_indices");
|
abort_if(!row_indices, "could not allocate row_indices");
|
||||||
|
|
||||||
for(int i = 0; i < nrows; i++)
|
for (int i = 0; i < nrows; i++)
|
||||||
row_indices[i] = nrows - i - 1;
|
row_indices[i] = nrows - i - 1;
|
||||||
|
|
||||||
for(int i = 0; i < cg->nrows * cg->nrows; i++)
|
for (int i = 0; i < cg->nrows * cg->nrows; i++)
|
||||||
row_affinity[i] = -1;
|
row_affinity[i] = -1;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
int inc_index = 0;
|
int inc_index = 0;
|
||||||
int is_rhs_integer = 1;
|
int is_rhs_integer = 1;
|
||||||
int valid_combination = 1;
|
int valid_combination = 1;
|
||||||
|
|
||||||
for(int i = 0; i < nrows; i++)
|
for (int i = 0; i < nrows; i++)
|
||||||
{
|
{
|
||||||
struct Row *r = cg->tableau_rows[row_indices[i]];
|
struct Row *r = cg->tableau_rows[row_indices[i]];
|
||||||
|
|
||||||
if(!row_selected[row_indices[i]])
|
if (!row_selected[row_indices[i]])
|
||||||
{
|
{
|
||||||
valid_combination = 0;
|
valid_combination = 0;
|
||||||
inc_index = i;
|
inc_index = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
double df = fabs(frac(r->pi_zero) - 0.5);
|
double df = fabs(frac(r->pi_zero) - 0.5);
|
||||||
if(df < INTEGRALITY_THRESHOLD) is_rhs_integer = 0;
|
if (df < INTEGRALITY_THRESHOLD) is_rhs_integer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_rhs_integer) valid_combination = 0;
|
if (is_rhs_integer) valid_combination = 0;
|
||||||
|
|
||||||
for(int i = 0; valid_combination && i < nrows; i++)
|
for (int i = 0; valid_combination && i < nrows; i++)
|
||||||
{
|
{
|
||||||
for(int j = i+1; valid_combination && j < nrows; j++)
|
for (int j = i + 1; valid_combination && j < nrows; j++)
|
||||||
{
|
{
|
||||||
int i1 = row_indices[i];
|
int i1 = row_indices[i];
|
||||||
int i2 = row_indices[j];
|
int i2 = row_indices[j];
|
||||||
if(i2 < i1) swap(i1, i2, int);
|
if (i2 < i1) swap(i1, i2, int);
|
||||||
|
|
||||||
int k = cg->nrows * i1 + i2;
|
int k = cg->nrows * i1 + i2;
|
||||||
|
|
||||||
if(row_affinity[k] < 0)
|
if (row_affinity[k] < 0)
|
||||||
{
|
{
|
||||||
struct Row *row1 = cg->tableau_rows[i1];
|
struct Row *row1 = cg->tableau_rows[i1];
|
||||||
struct Row *row2 = cg->tableau_rows[i2];
|
struct Row *row2 = cg->tableau_rows[i2];
|
||||||
double score;
|
double score;
|
||||||
|
|
||||||
rval = evaluate_row_pair(row1, row2, &score);
|
rval = evaluate_row_pair(row1, row2, &score);
|
||||||
abort_if(rval, "evaluate_row_pair failed");
|
abort_if(rval, "evaluate_row_pair failed");
|
||||||
|
|
||||||
row_affinity[k] = 1;
|
row_affinity[k] = 1;
|
||||||
if(score < score_cutoff) row_affinity[k] = 0;
|
if (score < score_cutoff) row_affinity[k] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!row_affinity[k])
|
if (!row_affinity[k])
|
||||||
{
|
{
|
||||||
valid_combination = 0;
|
valid_combination = 0;
|
||||||
goto NEXT_COMBINATION;
|
goto NEXT_COMBINATION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(valid_combination)
|
if (valid_combination)
|
||||||
{
|
{
|
||||||
(*total_count)++;
|
(*total_count)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
NEXT_COMBINATION:
|
NEXT_COMBINATION:
|
||||||
next_combination(cg->nrows, nrows, row_indices, inc_index, &finished);
|
next_combination(cg->nrows, nrows, row_indices, inc_index, &finished);
|
||||||
}
|
} while (!finished);
|
||||||
while(!finished);
|
|
||||||
|
|
||||||
CLEANUP:
|
CLEANUP:
|
||||||
if(row_indices) free(row_indices);
|
if (row_indices) free(row_indices);
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -756,10 +726,9 @@ int cut_dynamism(struct Row *cut, double *dynamism)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int CG_add_multirow_cuts(struct CG *cg,
|
int CG_add_multirow_cuts(struct CG *cg,
|
||||||
int nrows,
|
int nrows,
|
||||||
MultirowGeneratorCallback generate)
|
MultiRowGeneratorCallback generate)
|
||||||
{
|
{
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
int *row_indices = 0;
|
int *row_indices = 0;
|
||||||
@@ -771,10 +740,10 @@ int CG_add_multirow_cuts(struct CG *cg,
|
|||||||
long count = 0;
|
long count = 0;
|
||||||
long total_count = 0;
|
long total_count = 0;
|
||||||
|
|
||||||
row_indices = (int*) malloc(nrows * sizeof(int));
|
row_indices = (int *) malloc(nrows * sizeof(int));
|
||||||
rows = (struct Row **) malloc(nrows * sizeof(struct Row *));
|
rows = (struct Row **) malloc(nrows * sizeof(struct Row *));
|
||||||
row_affinity = (int*) malloc((cg->nrows * cg->nrows) * sizeof(int));
|
row_affinity = (int *) malloc((cg->nrows * cg->nrows) * sizeof(int));
|
||||||
row_selected = (int*) malloc(cg->nrows * sizeof(int));
|
row_selected = (int *) malloc(cg->nrows * sizeof(int));
|
||||||
|
|
||||||
abort_if(!row_indices, "could not allocate row_indices");
|
abort_if(!row_indices, "could not allocate row_indices");
|
||||||
abort_if(!rows, "could not allocate rows");
|
abort_if(!rows, "could not allocate rows");
|
||||||
@@ -785,24 +754,25 @@ int CG_add_multirow_cuts(struct CG *cg,
|
|||||||
abort_if(rval, "select_rows failed");
|
abort_if(rval, "select_rows failed");
|
||||||
|
|
||||||
log_info(" Finding combinations...\n");
|
log_info(" Finding combinations...\n");
|
||||||
for(double cutoff = 0.05; cutoff <= 1.0; cutoff += 0.05)
|
for (double cutoff = 0.05; cutoff <= 1.0; cutoff += 0.05)
|
||||||
{
|
{
|
||||||
double cg_current_time = get_user_time() - cg_initial_time;
|
double cg_current_time = get_user_time() - cg_initial_time;
|
||||||
if(cg_current_time > CG_TIMEOUT) break;
|
if (cg_current_time > CG_TIMEOUT) break;
|
||||||
|
|
||||||
rval = estimate_multirow_cut_count(cg, nrows, row_selected, row_affinity, &total_count, cutoff);
|
rval = estimate_multirow_cut_count(cg, nrows, row_selected,
|
||||||
|
row_affinity, &total_count, cutoff);
|
||||||
abort_if(rval, "estimate_two_row_cuts_count failed");
|
abort_if(rval, "estimate_two_row_cuts_count failed");
|
||||||
|
|
||||||
log_debug(" %8d combinations [%.2lf]\n", total_count, cutoff);
|
log_debug(" %8d combinations [%.2lf]\n", total_count, cutoff);
|
||||||
|
|
||||||
if(total_count < MAX_SELECTED_COMBINATIONS)
|
if (total_count < MAX_SELECTED_COMBINATIONS)
|
||||||
{
|
{
|
||||||
log_info(" %8d combinations [%.2lf]\n", total_count, cutoff);
|
log_info(" %8d combinations [%.2lf]\n", total_count, cutoff);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < nrows; i++)
|
for (int i = 0; i < nrows; i++)
|
||||||
row_indices[i] = nrows - i - 1;
|
row_indices[i] = nrows - i - 1;
|
||||||
|
|
||||||
total_count = min(total_count, MAX_SELECTED_COMBINATIONS);
|
total_count = min(total_count, MAX_SELECTED_COMBINATIONS);
|
||||||
@@ -813,95 +783,96 @@ int CG_add_multirow_cuts(struct CG *cg,
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
double cg_current_time = get_user_time() - cg_initial_time;
|
double cg_current_time = get_user_time() - cg_initial_time;
|
||||||
if(cg_current_time > CG_TIMEOUT) break;
|
if (cg_current_time > CG_TIMEOUT) break;
|
||||||
|
|
||||||
int inc_index = 0;
|
int inc_index = 0;
|
||||||
int is_rhs_integer = 1;
|
int is_rhs_integer = 1;
|
||||||
int valid_combination = 1;
|
int valid_combination = 1;
|
||||||
|
|
||||||
for(int i = 0; i < nrows; i++)
|
for (int i = 0; i < nrows; i++)
|
||||||
{
|
{
|
||||||
rows[i] = cg->tableau_rows[row_indices[i]];
|
rows[i] = cg->tableau_rows[row_indices[i]];
|
||||||
|
|
||||||
if(!row_selected[row_indices[i]])
|
if (!row_selected[row_indices[i]])
|
||||||
{
|
{
|
||||||
valid_combination = 0;
|
valid_combination = 0;
|
||||||
inc_index = i;
|
inc_index = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
double df = fabs(frac(rows[i]->pi_zero) - 0.5);
|
double df = fabs(frac(rows[i]->pi_zero) - 0.5);
|
||||||
if(df < INTEGRALITY_THRESHOLD) is_rhs_integer = 0;
|
if (df < INTEGRALITY_THRESHOLD) is_rhs_integer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_rhs_integer) valid_combination = 0;
|
if (is_rhs_integer) valid_combination = 0;
|
||||||
|
|
||||||
for(int i = 0; valid_combination && i < nrows; i++)
|
for (int i = 0; valid_combination && i < nrows; i++)
|
||||||
{
|
{
|
||||||
|
|
||||||
for(int j = i+1; valid_combination && j < nrows; j++)
|
for (int j = i + 1; valid_combination && j < nrows; j++)
|
||||||
{
|
{
|
||||||
int i1 = row_indices[i];
|
int i1 = row_indices[i];
|
||||||
int i2 = row_indices[j];
|
int i2 = row_indices[j];
|
||||||
if(i2 < i1) swap(i1, i2, int);
|
if (i2 < i1) swap(i1, i2, int);
|
||||||
|
|
||||||
int k = cg->nrows * i1 + i2;
|
int k = cg->nrows * i1 + i2;
|
||||||
|
|
||||||
abort_if(row_affinity[k] < 0, "row_affinity not computed");
|
abort_if(row_affinity[k] < 0, "row_affinity not computed");
|
||||||
if(!row_affinity[k]) valid_combination = 0;
|
if (!row_affinity[k]) valid_combination = 0;
|
||||||
|
|
||||||
if_verbose_level
|
if_verbose_level
|
||||||
{
|
{
|
||||||
struct Row *row1 = cg->tableau_rows[i1];
|
struct Row *row1 = cg->tableau_rows[i1];
|
||||||
struct Row *row2 = cg->tableau_rows[i2];
|
struct Row *row2 = cg->tableau_rows[i2];
|
||||||
double score;
|
double score;
|
||||||
|
|
||||||
rval = evaluate_row_pair(row1, row2, &score);
|
rval = evaluate_row_pair(row1, row2, &score);
|
||||||
abort_if(rval, "evaluate_row_pair failed");
|
abort_if(rval, "evaluate_row_pair failed");
|
||||||
|
|
||||||
log_verbose("%4d %4d %.2lf\n", i1, i2, score);
|
log_verbose("%4d %4d %.2lf\n", i1, i2, score);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(valid_combination)
|
if (valid_combination)
|
||||||
{
|
{
|
||||||
count++;
|
count++;
|
||||||
if(count > MAX_SELECTED_COMBINATIONS)
|
if (count > MAX_SELECTED_COMBINATIONS)
|
||||||
{
|
{
|
||||||
log_info(" maximum number of combinations reached. stopping.\n");
|
log_info(
|
||||||
|
" maximum number of combinations reached. stopping.\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if_debug_level
|
if_debug_level if (ONLY_CUT > 0 && count != ONLY_CUT)
|
||||||
if(ONLY_CUT > 0 && count != ONLY_CUT)
|
|
||||||
goto NEXT_COMBINATION;
|
goto NEXT_COMBINATION;
|
||||||
|
|
||||||
if_debug_level
|
if_debug_level
|
||||||
{
|
{
|
||||||
time_printf("Generating cut %d from [ ", count);
|
time_printf("Generating cut %d from [ ", count);
|
||||||
for(int i = 0; i < nrows; i++)
|
for (int i = 0; i < nrows; i++)
|
||||||
printf("%d ", row_indices[i]);
|
printf("%d ", row_indices[i]);
|
||||||
printf("]...\n");
|
printf("]...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(LOG_LEVEL == LOG_LEVEL_INFO)
|
if (LOG_LEVEL == LOG_LEVEL_INFO)
|
||||||
{
|
{
|
||||||
progress_print();
|
progress_print();
|
||||||
progress_increment();
|
progress_increment();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Row *cut = 0;
|
struct Row *cut = 0;
|
||||||
|
|
||||||
cut = (struct Row*) malloc(sizeof(struct Row));
|
cut = (struct Row *) malloc(sizeof(struct Row));
|
||||||
abort_if(!cut, "could not allocate cut");
|
abort_if(!cut, "could not allocate cut");
|
||||||
|
|
||||||
cut->pi = 0;
|
cut->pi = 0;
|
||||||
cut->indices = 0;
|
cut->indices = 0;
|
||||||
|
|
||||||
double initial_time = get_user_time();
|
double initial_time = get_user_time();
|
||||||
|
struct Tableau tableau = {nrows, rows, cg->column_types};
|
||||||
|
|
||||||
rval = generate(nrows, rows, cg->column_types, cut);
|
rval = generate(&tableau, cut);
|
||||||
if(rval == ERR_NO_CUT)
|
if (rval == ERR_NO_CUT)
|
||||||
{
|
{
|
||||||
rval = 0;
|
rval = 0;
|
||||||
log_verbose("combination does not yield cut\n");
|
log_verbose("combination does not yield cut\n");
|
||||||
@@ -917,7 +888,7 @@ int CG_add_multirow_cuts(struct CG *cg,
|
|||||||
rval = cut_dynamism(cut, &dynamism);
|
rval = cut_dynamism(cut, &dynamism);
|
||||||
abort_if(rval, "cut_dynamism failed");
|
abort_if(rval, "cut_dynamism failed");
|
||||||
|
|
||||||
if(dynamism > MAX_CUT_DYNAMISM)
|
if (dynamism > MAX_CUT_DYNAMISM)
|
||||||
{
|
{
|
||||||
log_debug("Discarding cut (dynamism=%.2lf)\n", dynamism);
|
log_debug("Discarding cut (dynamism=%.2lf)\n", dynamism);
|
||||||
LP_free_row(cut);
|
LP_free_row(cut);
|
||||||
@@ -926,7 +897,7 @@ int CG_add_multirow_cuts(struct CG *cg,
|
|||||||
|
|
||||||
int ignored;
|
int ignored;
|
||||||
rval = add_cut(cg, cut, &ignored);
|
rval = add_cut(cg, cut, &ignored);
|
||||||
if(rval)
|
if (rval)
|
||||||
{
|
{
|
||||||
log_warn("invalid cut skipped (cut %d)\n", count);
|
log_warn("invalid cut skipped (cut %d)\n", count);
|
||||||
rval = 0;
|
rval = 0;
|
||||||
@@ -936,39 +907,34 @@ int CG_add_multirow_cuts(struct CG *cg,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if_debug_level if(!ignored)
|
if_debug_level if (!ignored)
|
||||||
{
|
{
|
||||||
DUMP_CUT = 1;
|
SHOULD_DUMP_CUTS = 1;
|
||||||
generate(nrows, rows, cg->column_types, cut);
|
generate(&tableau, cut);
|
||||||
DUMP_CUT = 0;
|
SHOULD_DUMP_CUTS = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LP_free_row(cut);
|
LP_free_row(cut);
|
||||||
}
|
}
|
||||||
|
|
||||||
NEXT_COMBINATION:
|
NEXT_COMBINATION:
|
||||||
next_combination(cg->nrows, nrows, row_indices, inc_index, &finished);
|
next_combination(cg->nrows, nrows, row_indices, inc_index, &finished);
|
||||||
}
|
} while (!finished);
|
||||||
while(!finished);
|
|
||||||
|
|
||||||
CLEANUP:
|
CLEANUP:
|
||||||
if(row_selected) free(row_selected);
|
if (row_selected) free(row_selected);
|
||||||
if(row_affinity) free(row_affinity);
|
if (row_affinity) free(row_affinity);
|
||||||
if(row_indices) free(row_indices);
|
if (row_indices) free(row_indices);
|
||||||
if(rows) free(rows);
|
if (rows) free(rows);
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CG_set_integral_solution(struct CG *cg, double *valid_solution)
|
||||||
int CG_set_integral_solution(struct CG *cg,
|
|
||||||
double *valid_solution)
|
|
||||||
{
|
{
|
||||||
return copy_solution(cg, valid_solution, &cg->integral_solution);
|
return copy_solution(cg, valid_solution, &cg->integral_solution);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CG_set_basic_solution(struct CG *cg, double *basic_solution)
|
||||||
int CG_set_basic_solution(struct CG *cg,
|
|
||||||
double *basic_solution)
|
|
||||||
{
|
{
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
|
|
||||||
@@ -994,28 +960,88 @@ int CG_boost_variable(int var,
|
|||||||
int rval = 0;
|
int rval = 0;
|
||||||
|
|
||||||
int selected_ray = -1;
|
int selected_ray = -1;
|
||||||
for(int j = 0; j < nz; j++)
|
for (int j = 0; j < nz; j++)
|
||||||
{
|
{
|
||||||
if(indices[j] == var)
|
if (indices[j] == var)
|
||||||
{
|
{
|
||||||
selected_ray = variable_to_ray[j];
|
selected_ray = variable_to_ray[j];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(selected_ray < 0) goto CLEANUP;
|
if (selected_ray < 0) goto CLEANUP;
|
||||||
|
|
||||||
double *r = &rays[nrows * selected_ray];
|
double *r = &rays[nrows * selected_ray];
|
||||||
for(int k = 0; k < nrows; k++)
|
for (int k = 0; k < nrows; k++)
|
||||||
r[k] *= factor;
|
r[k] *= factor;
|
||||||
|
|
||||||
for(int j = 0; j < nz; j++)
|
for (int j = 0; j < nz; j++)
|
||||||
{
|
{
|
||||||
if(variable_to_ray[j] == selected_ray)
|
if (variable_to_ray[j] == selected_ray)
|
||||||
ray_scale[j] /= factor;
|
ray_scale[j] /= factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
CLEANUP:
|
CLEANUP:
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CG_init_ray_map(struct RayMap *map, int max_nrays, int nrows)
|
||||||
|
{
|
||||||
|
int rval = 0;
|
||||||
|
|
||||||
|
map->variable_to_ray = (int *) malloc(max_nrays * sizeof(int));
|
||||||
|
map->indices = (int *) malloc(max_nrays * sizeof(int));
|
||||||
|
map->ray_scale = (double *) malloc(max_nrays * sizeof(double));
|
||||||
|
map->rays = (double *) malloc(nrows * max_nrays * sizeof(double));
|
||||||
|
abort_if(!map->variable_to_ray, "could not allocate variable_to_ray");
|
||||||
|
abort_if(!map->indices, "could not allocate indices");
|
||||||
|
abort_if(!map->ray_scale, "could not allocate ray_scale");
|
||||||
|
abort_if(!map->rays, "could not allocate rays");
|
||||||
|
|
||||||
|
CLEANUP:
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CG_free_ray_map(struct RayMap *map)
|
||||||
|
{
|
||||||
|
if(!map) return;
|
||||||
|
free(map->variable_to_ray);
|
||||||
|
free(map->indices);
|
||||||
|
free(map->ray_scale);
|
||||||
|
free(map->rays);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CG_extract_f_from_tableau(const struct Tableau *tableau, double *f)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < tableau->nrows; i++)
|
||||||
|
{
|
||||||
|
f[i] = frac(tableau->rows[i]->pi_zero);
|
||||||
|
if (DOUBLE_eq(f[i], 1.0)) f[i] = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CG_init_model(struct MultiRowModel *model, int nrows, int max_nrays)
|
||||||
|
{
|
||||||
|
int rval = 0;
|
||||||
|
|
||||||
|
model->nrays = 0;
|
||||||
|
model->nrows = nrows;
|
||||||
|
model->f = (double*) malloc(nrows * sizeof(double));
|
||||||
|
model->rays = (double*) malloc(max_nrays * sizeof(double));
|
||||||
|
abort_if(!model->f, "could not allocate f");
|
||||||
|
abort_if(!model->rays, "could not allocate rays");
|
||||||
|
|
||||||
|
CLEANUP:
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CG_free_model(struct MultiRowModel *model)
|
||||||
|
{
|
||||||
|
if(!model) return;
|
||||||
|
free(model->rays);
|
||||||
|
free(model->f);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // TEST_SOURCE
|
#endif // TEST_SOURCE
|
||||||
|
|||||||
@@ -151,8 +151,8 @@ TEST(CGTest, extract_rays_from_rows_test)
|
|||||||
double rays[1000];
|
double rays[1000];
|
||||||
double ray_scale[1000];
|
double ray_scale[1000];
|
||||||
|
|
||||||
rval = CG_extract_rays_from_rows(3, rows, rays, &nrays, variable_to_ray,
|
rval = CG_extract_rays_from_tableau(3, rows, rays, &nrays, variable_to_ray,
|
||||||
ray_scale, indices, &nz);
|
ray_scale, indices, &nz);
|
||||||
abort_if(rval, "CG_extract_rays_from_rows failed");
|
abort_if(rval, "CG_extract_rays_from_rows failed");
|
||||||
|
|
||||||
EXPECT_EQ(nrays, 4);
|
EXPECT_EQ(nrays, 4);
|
||||||
|
|||||||
Reference in New Issue
Block a user