00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "stdlib.h"
00012 #include "stdio.h"
00013 #include "math.h"
00014
00015 #include "CoinTime.hpp"
00016 #include "CoinHelperFunctions.hpp"
00017
00018 #include "operators/CouenneExprMul.hpp"
00019 #include "CouenneSdpCuts.hpp"
00020
00021 #include "dsyevx_wrapper.hpp"
00022
00023 #ifdef _WIN32
00024 #define drand48() ((double) (rand () * (RAND_MAX + 1) + rand ()) / (RAND_MAX + 1) * (RAND_MAX + 1))
00025 #endif
00026
00027
00028
00029 const bool WISE_SPARSIFY = true;
00030
00031 #define SPARSIFY_MAX_CARD 10000
00032 #define WISE_SPARSIFY_GAP 0.0001
00033
00034 #define SPARSIFY_OLD_DELTA 0.50
00035 #define SPARSIFY_NEW_DELTA 0.50
00036
00037 #define SPARSIFY_OLD_NZ_THRESHOLD 0.50
00038 #define SPARSIFY_NEW_NZ_THRESHOLD 0.70
00039
00040 #define EV_TOL 1e-13
00041
00042 using namespace Couenne;
00043
00044
00045 void CouenneSdpCuts::sparsify2 (const int n,
00046 const double *A, double **sparse_v_mat,
00047 int *card_v_mat, int min_nz, int *evdec_num) const {
00048
00049 bool *del_idx = NULL;
00050
00051 int
00052 running_n = n,
00053 best_idx,
00054 rnsq = (running_n - 1) * (running_n - 1),
00055 card_ev_best = running_n - 1;
00056
00057 double
00058
00059 *matrix = CoinCopyOfArray (A, n*n),
00060
00061 best_val,
00062
00063 *matrixCopy = CoinCopyOfArray (matrix, running_n * running_n),
00064
00065 *T = new double [rnsq],
00066 *Tcopy = new double [rnsq],
00067 *Tbest = new double [rnsq],
00068
00069 *wbest = new double [running_n - 1],
00070 *zbest = new double [rnsq],
00071
00072 *w = NULL,
00073 *z = NULL;
00074
00075
00076
00077 while (running_n > 1) {
00078
00079 rnsq = (running_n - 1) * (running_n - 1);
00080
00081 best_val = 0.;
00082 best_idx = -1;
00083
00084 for (int k=0; k < running_n; ++k) {
00085
00087
00088 for (int i=0, ii=0; i<running_n; i++) {
00089
00090 if (i==k) continue;
00091
00092 for (int j=0, jj=0; j<running_n; j++) {
00093
00094 if (j==k) continue;
00095
00096 int
00097 idx1 = (running_n - 1) * ii + jj,
00098 idx2 = (running_n - 1) * jj + ii;
00099
00100 double val2 = matrixCopy [running_n*i + j];
00101
00102 T [idx1] =
00103 T [idx2] =
00104 Tcopy [idx1] =
00105 Tcopy [idx2] = val2;
00106
00107 ++jj;
00108 }
00109
00110 ++ii;
00111 }
00112
00113 int card_ev;
00114
00115 (*evdec_num)++;
00116
00117
00118 dsyevx_interface (running_n - 1, T, card_ev, w, z, EV_TOL, -COIN_DBL_MAX, 0., 1, (running_n - 1 == min_nz) ? (running_n - 1) : 1);
00119
00120
00121 double val = w [0];
00122
00123 if (val < best_val) {
00124
00125 best_val = val;
00126 best_idx = k;
00127
00128 std::memcpy (Tbest, Tcopy, rnsq * sizeof (double));
00129 std::memcpy (zbest, z, rnsq * sizeof (double));
00130 std::memcpy (wbest, w, (running_n - 1) * sizeof (double));
00131
00132 card_ev_best = card_ev;
00133 }
00134
00135 delete [] w;
00136 delete [] z;
00137
00138 w = z = NULL;
00139 }
00140
00141
00142
00143
00144 if (best_idx >= 0) {
00145
00146 if (del_idx == NULL) {
00147 del_idx = new bool[n];
00148 CoinFillN (del_idx, n, false);
00149 }
00150
00151 int cnt_idx_orig = 0;
00152 int cnt_idx_minor = 0;
00153
00154 while (cnt_idx_minor < running_n) {
00155 if (del_idx [cnt_idx_orig] == false) {
00156 if (cnt_idx_minor == best_idx) {
00157 del_idx [cnt_idx_orig] = true;
00158 break;
00159 }
00160
00161 cnt_idx_minor++;
00162 }
00163
00164 cnt_idx_orig++;
00165 }
00166
00167 if (running_n - 1 == min_nz) {
00168
00169 for (int i=0; i < card_ev_best && wbest [i] < 0; i++) {
00170
00171 CoinFillN (sparse_v_mat [i], n, 0.);
00172
00173 double *curr_ev = zbest + i * (running_n - 1);
00174
00175 for (int idx_orig = 0, idx_minor = 0; idx_orig < n; ++idx_orig)
00176
00177 if (!(del_idx [idx_orig]))
00178 sparse_v_mat [i] [idx_orig] = curr_ev [idx_minor++];
00179
00180 ++ *card_v_mat;
00181 }
00182
00183 break;
00184 }
00185 }
00186
00187 CoinCopyN (Tbest, (n-1) * (n-1), matrixCopy);
00188
00189 --running_n;
00190
00191 }
00192
00193 delete [] del_idx;
00194
00195 delete [] z;
00196 delete [] w;
00197
00198 delete [] T;
00199 delete [] Tcopy;
00200 delete [] matrixCopy;
00201
00202 delete [] Tbest;
00203 delete [] zbest;
00204 delete [] wbest;
00205
00206 delete [] matrix;
00207 }
00208
00209
00210
00211
00212
00213
00214 void CouenneSdpCuts::additionalSDPcuts (const OsiSolverInterface &si,
00215 OsiCuts &cs,
00216 CouenneExprMatrix *minor,
00217 int n,
00218 const double *A,
00219 const double *vector,
00220 int **indA) const {
00221 int
00222 *indices = new int [n],
00223 cnt = 0;
00224
00225 double threshold = 1 / (10 * sqrt ((double) n));
00226
00227 for (int i=0; i < n; i++)
00228 indices [i] = ((fabs (vector [i]) > threshold) ? (cnt++) : -1);
00229
00230 double *subA = new double [cnt*cnt];
00231
00232 for (register int i=0, k=0; i<n; i++)
00233
00234 if (indices [i] >= 0) {
00235
00236 for (register int j=0, k2 = 0; j<n; j++)
00237
00238 if (indices [j] >= 0) {
00239 subA [cnt * k + k2] =
00240 subA [cnt * k2 + k ] = A [n*i + j];
00241 ++k2;
00242 }
00243
00244 ++k;
00245 }
00246
00247 double *w = NULL, *z = NULL;
00248 int m;
00249
00250
00251
00253 dsyevx_interface (cnt, subA, m, w, z, EV_TOL, -COIN_DBL_MAX, onlyNegEV_ ? 0. : COIN_DBL_MAX, 1, cnt);
00255
00256 double
00257 *v = new double [n],
00258 *newv = new double [n];
00259
00260 for (int k=0; k<m; k++) {
00261
00262 if (onlyNegEV_ && (w [k] >= 0.))
00263 break;
00264
00265 double *zbase = z + k * cnt;
00266
00267 for (int j=0; j<cnt; j++)
00268 v [j] = *zbase++;
00269
00270 for(int j=0; j<n; j++)
00271 newv [j] = (indices [j] >= 0) ? v [indices [j]] : 0.;
00272
00273 genSDPcut (si, cs, minor, newv, newv, indA);
00274 }
00275
00276 delete [] v;
00277 delete [] newv;
00278
00279 delete [] w;
00280 delete [] z;
00281
00282 delete [] subA;
00283 delete [] indices;
00284 }
00285
00286
00287
00288 void CouenneSdpCuts::update_sparsify_structures (const int n, double *v,
00289 double* margin, double* A, double *lhs,
00290 const int *zeroed, int evidx, bool decompose,
00291 int *evdec_num) const {
00292
00293 int minor_n = n;
00294
00295 if (zeroed != NULL) {
00296 for (int i=0; i<n; i++)
00297 if (zeroed [i] == 0)
00298 --minor_n;
00299 }
00300
00301 if (decompose && (minor_n > 2)) {
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313 (*evdec_num)++;
00314
00315 double *minor_A = new double [n*n];
00316 double *minor_w = new double [n];
00317 double *minor_z = new double [n*n];
00318
00319
00320
00321 int
00322 ii = 0,
00323 jj = 0;
00324
00325 for (int i=0;i<n;i++) {
00326 if (zeroed[i] == 0)
00327 continue;
00328
00329 jj = 0;
00330
00331 for (int j=0;j<n;j++) {
00332 if (zeroed [j] == 0)
00333 continue;
00334 minor_A [minor_n*ii + jj] = A [n * i + j];
00335 jj++;
00336 }
00337
00338 ii++;
00339 }
00340
00341 int m;
00342
00343
00344
00345
00346 dsyevx_interface (minor_n, minor_A, m, minor_w, minor_z, EV_TOL, -COIN_DBL_MAX, 0., 1, 1);
00347
00348
00349
00350 ii = 0;
00351 for (int i=0;i<n;i++) {
00352 v[i] = 0;
00353 if (zeroed[i] == 0)
00354 continue;
00355 v[i] = minor_z[ii];
00356 ii++;
00357 }
00358
00359 delete [] minor_A;
00360 delete [] minor_w;
00361 delete [] minor_z;
00362 }
00363
00364 for (int i=0; i<n; ++i)
00365 for (int j=0; j<n; ++j) {
00366 A [i*n + j] =
00367 A [j*n + i] *= v[i] * v[j];
00368 if ((zeroed != NULL) && (zeroed [j] == 0))
00369 A [i*n + j] = A [j*n + i] = 0;
00370 }
00371
00372 *lhs = 0.;
00373
00374 for (int i=0; i<n; i++) {
00375
00376 margin[i] = 0;
00377
00378 for(int j=0; j<n; j++)
00379 margin[i] += A [i*n + j];
00380
00381 *lhs += margin[i];
00382 }
00383 }
00384
00385
00386
00387 void CouenneSdpCuts::zero_comp (const int ind_i,
00388 const double delta,
00389 const int n,
00390 const int *selected,
00391 int *loc_selected,
00392 int *ploc_card_selected,
00393 int *ploc_card_new_selected,
00394 double *ploc_lhs,
00395 double *locmargin,
00396 double *locmat,
00397 double *locv,
00398 const int evidx,
00399 bool wise,
00400 int *evdec_num,
00401 double *recomp_gap,
00402 double *threshold) const {
00403
00404
00405 static int zerocount;
00406 bool local_wise = false;
00407 if (wise && (*ploc_lhs - delta > *threshold)) {
00408 (*threshold) = (*ploc_lhs)-delta + (*recomp_gap);
00409 local_wise = true;
00410 }
00411
00412 zerocount++;
00413
00414 loc_selected[ind_i] = 0;
00415 (*ploc_card_selected)--;
00416
00417 if (selected [ind_i] != 1)
00418 (*ploc_card_new_selected)--;
00419
00420 (*ploc_lhs) -= delta;
00421
00422 update_sparsify_structures (n,locv, locmargin, locmat, ploc_lhs, loc_selected, evidx, local_wise, evdec_num);
00423
00424 }
00425
00426
00427
00428 void CouenneSdpCuts::zero_unified (enum zero_type type,
00429 const int n,
00430 const int *order,
00431 const int *selected,
00432 const int min_card_new_selected,
00433 const double min_delta,
00434 const int start_point,
00435 const int curr_i,
00436 int *loc_selected,
00437 int *ploc_card_selected,
00438 int *ploc_card_new_selected,
00439 double *ploc_lhs,
00440 double *locmargin,
00441 double *locmat,
00442 int *pnchanged,
00443 double *locv,
00444 const int evidx,
00445 bool wise,
00446 double *recomp_gap,
00447 double *threshold,
00448 int *evdec_num) const {
00449
00450 int curr_ind = curr_i;
00451
00452 *pnchanged = 0;
00453 for (int i=0; i<n; i++) {
00454
00455 if (++curr_ind == n)
00456 curr_ind = 0;
00457
00458 int ind_i = order[curr_ind];
00459
00460 if (((type == POS_DELTA || type == VALID_DELTA) &&
00461 ((((selected [ind_i] == 0) && (min_card_new_selected >= *ploc_card_new_selected)) ||
00462 (curr_ind == start_point) ||
00463 (loc_selected[ind_i] == 0))))
00464 ||
00465 ((type == SELECTED) &&
00466 ((selected[ind_i] == 0) || (loc_selected[ind_i] == 0))))
00467 continue;
00468
00469 double delta = 2 * locmargin [ind_i] - locmat [ind_i * n + ind_i];
00470 if (((type == VALID_DELTA || type == SELECTED) && (*ploc_lhs - delta < min_delta)) ||
00471 ((type == POS_DELTA) && (delta > 0))) {
00472
00473 zero_comp (ind_i, delta, n, selected, loc_selected,
00474 ploc_card_selected, ploc_card_new_selected,
00475 ploc_lhs, locmargin, locmat, locv, evidx, wise, evdec_num, recomp_gap, threshold);
00476 (*pnchanged)++;
00477 }
00478 }
00479 }
00480
00481
00482
00483 void CouenneSdpCuts::add_v_cut(const int n,
00484 const int *loc_selected,
00485 const int loc_card_selected,
00486 const double *locv,
00487 const int init_card_selected, int *has_init_vect,
00488 int *selected, int *pcard_selected,
00489 int *pnew_selected,
00490 double **sparse_v_mat,
00491 int *pcard_v_mat) const {
00492
00493 *pnew_selected = 0;
00494
00495 for (int i=0; i<n; i++) {
00496 if (loc_selected[i]) {
00497 sparse_v_mat [*pcard_v_mat] [i] = locv [i];
00498 if(selected[i] == 0) {
00499 selected[i] = 1;
00500 (*pcard_selected)++;
00501 (*pnew_selected)++;
00502 }
00503 }
00504 else
00505 sparse_v_mat [*pcard_v_mat][i] = 0;
00506 }
00507
00508 #ifdef NORMALIZE_SPARSE_CUTS
00509
00510 double curr_norm = 0.0;
00511 for (int i=0;i<n;i++) {
00512 curr_norm += fabs(sparse_v_mat[*pcard_v_mat][i]);
00513 }
00514 for (int i=0;i<n;i++) {
00515 if (sparse_v_mat[*pcard_v_mat][i] != 0.0)
00516 sparse_v_mat[*pcard_v_mat][i] /= curr_norm;
00517 }
00518 #endif
00519
00520 if (loc_card_selected + init_card_selected == n) {
00521 if (*has_init_vect == 1) return;
00522 else
00523 (*has_init_vect) = 1;
00524 }
00525
00526 (*pcard_v_mat)++;
00527 }
00528
00529
00530
00531 void CouenneSdpCuts::sparsify (bool use_new_sparsify,
00532 const int evidx, const double eigen_val,
00533 const double *v, const int n,
00534 const double *A, double **sparse_v_mat,
00535 int *card_v_mat, int *evdec_num) const {
00536
00537 int nchanged = 0,
00538 min_number_new_per_cut = 1,
00539 loc_card_new_selected = 0,
00540 card_selected = 0,
00541 loc_card_selected = 0,
00542
00543 *selected = new int [n],
00544 *loc_selected = new int [n],
00545 *order = new int [n];
00546
00547 double
00548 min_delta,
00549 is_zero = 1 / (10 * sqrt ((double) n)),
00550 lhs = 0.,
00551 loc_lhs = 0.,
00552
00553 *margin = new double [n],
00554 *locv = new double [n],
00555 *locv_orig = new double [n],
00556 *locmargin = new double [n],
00557 *locmat = new double [n*n],
00558 *mat = CoinCopyOfArray (A, n*n);
00559
00560 *card_v_mat = 0;
00561
00562 for (int i=0; i<n; i++) {
00563
00564 order [i] = i;
00565
00566
00567 if (fabs (v[i]) < is_zero) {
00568
00569 locv_orig [i] = 0;
00570 selected [i] = -1;
00571 card_selected++;
00572
00573 } else {
00574 selected [i] = 0;
00575 locv_orig [i] = v[i];
00576 }
00577 }
00578
00580 for (int i=0; i<n; ++i) {
00581
00582 int
00583 newpos = i + (int) floor (((double) (n - i) - 1.e-3) * drand48 ()),
00584 tmp = order [newpos];
00585
00586 order [newpos] = order [i];
00587 order [i] = tmp;
00588 }
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598 update_sparsify_structures (n, locv_orig, margin, mat, &lhs, NULL, evidx, false, evdec_num);
00599
00600 int
00601 init_card_selected = card_selected,
00602 has_init_vect = 0,
00603 start_point = -1;
00604
00605 min_delta = lhs * (use_new_sparsify ? SPARSIFY_NEW_DELTA : SPARSIFY_OLD_DELTA);
00606
00607 while (card_selected < n) {
00608
00609 for (int i=0; i<n; i++)
00610
00611 if (selected [order [i]] == 0) {
00612 start_point = i;
00613 break;
00614 }
00615
00616 loc_card_selected = n;
00617 loc_card_new_selected = n;
00618 loc_lhs = lhs;
00619
00620 double
00621 recomp_gap = fabs (lhs * WISE_SPARSIFY_GAP),
00622 threshold = lhs + recomp_gap;
00623
00624
00625 CoinCopyN (locv_orig, n, locv);
00626 CoinCopyN (mat, n*n, locmat);
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636 for(int i=0; i<n; i++) {
00637 if(selected[i] == -1) {
00638 loc_selected[i] = 0;
00639 loc_card_selected--;
00640 loc_card_new_selected--;
00641 } else {
00642 loc_selected[i] = 1;
00643
00644 if (selected[i] == 1)
00645 loc_card_new_selected--;
00646 }
00647
00648 locmargin[i] = margin[i];
00649 }
00650
00651 if (loc_lhs >= min_delta) {
00652
00653
00654
00655 card_selected = n;
00656
00657 if (onlyNegEV_) {
00658
00659 int new_selected = 0;
00660
00661 add_v_cut (n, loc_selected, loc_card_selected, locv,
00662 init_card_selected, &has_init_vect,
00663 selected, &card_selected, &new_selected,
00664 sparse_v_mat, card_v_mat);
00665 }
00666
00667 } else {
00668
00669 int changed = 1;
00670
00671 while (changed) {
00672
00673 int curr_i = start_point;
00674
00675 changed = 0;
00676
00677 int curr_nchanged = -1;
00678
00679 while (curr_nchanged) {
00680
00681 zero_unified (SELECTED,
00682 n, order, selected, min_number_new_per_cut,
00683 min_delta, start_point,
00684 curr_i, loc_selected,
00685 &loc_card_selected, &loc_card_new_selected,
00686 &loc_lhs, locmargin, locmat,
00687 &curr_nchanged,locv,evidx, use_new_sparsify,
00688 &recomp_gap,
00689 &threshold,
00690 evdec_num);
00691
00692 if (curr_nchanged)
00693 nchanged += curr_nchanged;
00694 }
00695
00696 curr_nchanged = -1;
00697
00698 while (curr_nchanged) {
00699
00700 zero_unified (POS_DELTA,
00701 n, order, selected, min_number_new_per_cut,
00702 min_delta,
00703 start_point, start_point, loc_selected,
00704 &loc_card_selected, &loc_card_new_selected,
00705 &loc_lhs, locmargin, locmat,
00706 &curr_nchanged,locv,evidx,use_new_sparsify, &recomp_gap,&threshold,
00707 evdec_num);
00708
00709 if (curr_nchanged) {
00710 nchanged += curr_nchanged;
00711 changed = 1;
00712 }
00713 }
00714
00715 if (changed)
00716 continue;
00717
00718 curr_i = start_point;
00719
00720 curr_nchanged = -1;
00721
00722 if (curr_nchanged) {
00723
00724 zero_unified (VALID_DELTA,
00725 n, order, selected, min_number_new_per_cut,
00726 min_delta, start_point,
00727 curr_i, loc_selected,
00728 &loc_card_selected, &loc_card_new_selected,
00729 &loc_lhs, locmargin, locmat,
00730 &curr_nchanged,locv,evidx, use_new_sparsify, &recomp_gap,&threshold,
00731 evdec_num);
00732
00733 if (curr_nchanged) {
00734 nchanged += curr_nchanged;
00735 changed = 1;
00736 }
00737 }
00738 }
00739
00740 if ((loc_card_selected < n * (use_new_sparsify ? SPARSIFY_NEW_NZ_THRESHOLD : SPARSIFY_OLD_NZ_THRESHOLD)) || (*card_v_mat == 0)) {
00741
00742 int new_selected = 0;
00743
00744 add_v_cut (n, loc_selected, loc_card_selected, locv,
00745 init_card_selected, &has_init_vect,
00746 selected, &card_selected, &new_selected,
00747 sparse_v_mat, card_v_mat);
00748 } else {
00749 selected [order [start_point]] = 1;
00750 card_selected++;
00751 }
00752 }
00753 }
00754
00755 delete[] order;
00756
00757 delete [] mat;
00758 delete [] locmat;
00759
00760 delete[] locv;
00761 delete[] locv_orig;
00762 delete[] margin;
00763 delete[] locmargin;
00764
00765 delete[] selected;
00766 delete[] loc_selected;
00767 }