/** Computes indicators for printing. They are v2=vstar * vstar, asc= v*v, vu= vstar * u, vabs = sum( abs(vstar[i]))/m, v2= sum( vstar[i]^2) / m. */ VOL_indc::VOL_indc(const VOL_dvector& dual_lb, const VOL_dvector& dual_ub, const VOL_primal& primal, const VOL_primal& pstar, const VOL_dual& dual) { v2 = vu = vabs = asc = 0.0; const VOL_dvector v = primal.v; const VOL_dvector vstar = pstar.v; const VOL_dvector u = dual.u; int i; const int nc = vstar.size(); for (i = 0; i < nc; ++i) { if (u[i] == 0.0 && dual_lb[i] == 0.0 && vstar[i] <= 0.0) continue; if (u[i] == 0.0 && dual_ub[i] == 0.0 && vstar[i] >= 0.0) continue; v2 += vstar[i] * vstar[i]; asc += v[i] * v[i]; vu -= vstar[i] * u[i]; vabs += VolAbs(vstar[i]); } v2 = sqrt(v2) / nc; vabs /= nc; }
/// Here we increase the target once we get within 5% of it double VOL_problem::readjust_target(const double oldtarget, const double lcost) const { double target = oldtarget; if (lcost >= target - VolAbs(target) * 0.05) { if (VolAbs(lcost) < 10.0) { target = 10.0; } else { target += 0.025 * VolAbs(target); target = VolMax(target, lcost + 0.05 * VolAbs(lcost)); } if (target != oldtarget && (parm.printflag & 2)) { printf(" **** readjusting target!!! new target = %f *****\n", target); } } return target; }
//############################################################################ /// find maximum absolute value of the primal violations void VOL_primal::find_max_viol(const VOL_dvector& dual_lb, const VOL_dvector& dual_ub) { const int nc = v.size(); viol = 0; for ( int i = 0; i < nc; ++i ) { if ( (v[i] > 0.0 && dual_ub[i] != 0.0) || (v[i] < 0.0 && dual_lb[i] != 0.0) ) viol = VolMax(viol, VolAbs(v[i])); } }
//###################################################################### /// this is the Volume Algorithm int VOL_problem::solve(VOL_user_hooks& hooks, const bool use_preset_dual) { if (initialize(use_preset_dual) < 0) // initialize several parameters return -1; double best_ub = parm.ubinit; // upper bound int retval = 0; VOL_dvector rc(psize); // reduced costs VOL_dual dual(dsize); // dual vector dual.u = dsol; VOL_primal primal(psize, dsize); // primal vector retval = hooks.compute_rc(dual.u, rc); // compute reduced costs if (retval < 0) return -1; // solve relaxed problem retval = hooks.solve_subproblem(dual.u, rc, dual.lcost, primal.x, primal.v, primal.value); if (retval < 0) return -1; // set target for the lagrangian value double target = readjust_target(-COIN_DBL_MAX/2, dual.lcost); // find primal violation primal.find_max_viol(dual_lb, dual_ub); // this may be left out for speed VOL_primal pstar(primal); // set pstar=primal pstar.find_max_viol(dual_lb, dual_ub); // set violation of pstar dual.compute_xrc(pstar.x, primal.x, rc); // compute xrc // VOL_dual dstar(dual); // dstar is the best dual solution so far VOL_dual dlast(dual); // set dlast=dual iter_ = 0; if (parm.printflag) print_info(iter_, primal, pstar, dual); VOL_swing swing; VOL_alpha_factor alpha_factor; double * lcost_sequence = new double[parm.ascent_check_invl]; const int ascent_first_check = VolMax(parm.ascent_first_check, parm.ascent_check_invl); for (iter_ = 1; iter_ <= parm.maxsgriters; ++iter_) { // main iteration dlast = dual; // take a dual step dual.step(target, lambda_, dual_lb, dual_ub, pstar.v); // compute reduced costs retval = hooks.compute_rc(dual.u, rc); if (retval < 0) break; // solve relaxed problem retval = hooks.solve_subproblem(dual.u, rc, dual.lcost, primal.x, primal.v, primal.value); if (retval < 0) break; // set the violation of primal primal.find_max_viol(dual_lb, dual_ub); // this may be left out for speed dual.compute_xrc(pstar.x, primal.x, rc); // compute xrc if (dual.lcost > dstar.lcost) { dstar = dual; // update dstar } // check if target should be updated target = readjust_target(target, dstar.lcost); // compute inner product between the new subgradient and the // last direction. This to decide among green, yellow, red const double ascent = dual.ascent(primal.v, dlast.u); // green, yellow, red swing.cond(dlast, dual.lcost, ascent, iter_); // change lambda if needed lambda_ *= swing.lfactor(parm, lambda_, iter_); if (iter_ % parm.alphaint == 0) { // change alpha if needed const double fact = alpha_factor.factor(parm, dstar.lcost, alpha_); if (fact != 1.0 && (parm.printflag & 2)) { printf(" ------------decreasing alpha to %f\n", alpha_*fact); } alpha_ *= fact; } // convex combination with new primal vector pstar.cc(power_heur(primal, pstar, dual), primal); pstar.find_max_viol(dual_lb, dual_ub); // find maximum violation of pstar if (swing.rd) dual = dstar; // if there is no improvement reset dual=dstar if ((iter_ % parm.printinvl == 0) && parm.printflag) { // printing iteration information print_info(iter_, primal, pstar, dual); swing.print(); } if (iter_ % parm.heurinvl == 0) { // run primal heuristic double ub = COIN_DBL_MAX; retval = hooks.heuristics(*this, pstar.x, ub); if (retval < 0) break; if (ub < best_ub) best_ub = ub; } // save dual solution every 500 iterations if (iter_ % 500 == 0 && parm.temp_dualfile != 0) { FILE* outfile = fopen(parm.temp_dualfile, "w"); const VOL_dvector& u = dstar.u; const int m = u.size(); for (int i = 0; i < m; ++i) { fprintf(outfile, "%i %f\n", i+1, u[i]); } fclose(outfile); } // test terminating criteria const bool primal_feas = (pstar.viol < parm.primal_abs_precision); //const double gap = VolAbs(pstar.value - dstar.lcost); const double gap = pstar.value - dstar.lcost; const bool small_gap = VolAbs(dstar.lcost) < 0.0001 ? (gap < parm.gap_abs_precision) : ( (gap < parm.gap_abs_precision) || (gap/VolAbs(dstar.lcost) < parm.gap_rel_precision) ); // test optimality if (primal_feas && small_gap){ if (parm.printflag) printf(" small lp gap \n"); break; } // test proving integer optimality if (best_ub - dstar.lcost < parm.granularity){ if (parm.printflag) printf(" small ip gap \n"); break; } // test for non-improvement const int k = iter_ % parm.ascent_check_invl; if (iter_ > ascent_first_check) { if (dstar.lcost - lcost_sequence[k] < VolAbs(lcost_sequence[k]) * parm.minimum_rel_ascent){ if (parm.printflag) printf(" small improvement \n"); break; } } lcost_sequence[k] = dstar.lcost; } delete[] lcost_sequence; if (parm.printflag) print_info(iter_, primal, pstar, dual); // set solution to return value = dstar.lcost; psol = pstar.x; dsol = dstar.u; viol = pstar.v; return retval; }
//###################################################################### /// this is the Volume Algorithm int VOL_problem::solve(VOL_user_hooks& hooks, const bool use_preset_dual) { if (initialize(use_preset_dual) < 0) // initialize several parameters return -1; // JWB: the use_preset_dual option works with files. In my application, // I have initial values for the dual in memory and the UFL object has // a method to transfer these to the dsol object. I've added a // call to that method below. double best_ub = parm.ubinit; // upper bound int retval = 0; int found_integer_feasible = 0; VOL_dvector rc(psize); // reduced costs VOL_dual dual(dsize); // dual vector // JWB: here's the call to initialize the dual from an array if (use_preset_dual) { hooks.init_u(dual.u); } else { dual.u = dsol; } VOL_primal primal(psize, dsize); // primal vector retval = hooks.compute_rc(dual.u, rc); // compute reduced costs if (retval < 0) return -1; // solve relaxed problem retval = hooks.solve_subproblem(dual.u, rc, dual.lcost, primal.x, primal.v, primal.value); if (retval < 0) return -1; // set target for the lagrangian value double target = readjust_target(-DBL_MAX / 2, dual.lcost); // find primal violation primal.find_max_viol(dual_lb, dual_ub); // this may be left out for speed VOL_primal pstar(primal); // set pstar=primal pstar.find_max_viol(dual_lb, dual_ub); // set violation of pstar dual.compute_xrc(pstar.x, primal.x, rc); // compute xrc // VOL_dual dstar(dual); // dstar is the best dual solution so far VOL_dual dlast(dual); // set dlast=dual iter_ = 0; if (parm.printflag) print_info(iter_, primal, pstar, dual); VOL_swing swing; VOL_alpha_factor alpha_factor; double* lcost_sequence = new double[parm.ascent_check_invl]; const int ascent_first_check = VolMax(parm.ascent_first_check, parm.ascent_check_invl); for (iter_ = 1; iter_ <= parm.maxsgriters; ++iter_) // main iteration { dlast = dual; cur_u = &dlast.u; // take a dual step dual.step(target, lambda_, dual_lb, dual_ub, pstar.v); // compute reduced costs retval = hooks.compute_rc(dual.u, rc); if (retval < 0) { printf("VOL breaking because of compute_rc\n"); break; } // solve relaxed problem retval = hooks.solve_subproblem(dual.u, rc, dual.lcost, primal.x, primal.v, primal.value); if (retval < 0) { printf("VOL breaking because of solve_subproblem\n"); break; } // set the violation of primal primal.find_max_viol(dual_lb, dual_ub); // this may be left out for speed dual.compute_xrc(pstar.x, primal.x, rc); // compute xrc if (dual.lcost > dstar.lcost) { dstar = dual; // update dstar } // check if target should be updated target = readjust_target(target, dstar.lcost); // compute inner product between the new subgradient and the // last direction. This to decide among green, yellow, red const double ascent = dual.ascent(primal.v, dlast.u); // green, yellow, red swing.cond(dlast, dual.lcost, ascent, iter_); // change lambda if needed lambda_ *= swing.lfactor(parm, lambda_, iter_); if (iter_ % parm.alphaint == 0) // change alpha if needed { const double fact = alpha_factor.factor(parm, dstar.lcost, alpha_); alpha_ *= fact; } // convex combination with new primal vector pstar.cc(power_heur(primal, pstar, dual), primal); pstar.find_max_viol(dual_lb, dual_ub); // find maximum violation of pstar if (swing.rd) dual = dstar; // if there is no improvement reset dual=dstar if ((iter_ % parm.printinvl == 0) && parm.printflag) // printing iteration information { print_info(iter_, primal, pstar, dual); swing.print(); } if ((iter_ + 1) % parm.heurinvl == 0) // run primal heuristic { double ub = DBL_MAX; printf("Vol: iter: %d, heurinvl: %d\n", iter_, parm.heurinvl); fflush(stdout); retval = hooks.heuristics(*this, pstar.x, ub, dual.lcost); if (retval < 0) { found_integer_feasible = true; break; } if (retval > 0) found_integer_feasible = 1; if (ub < best_ub) best_ub = ub; } // save dual solution every 500 iterations if (iter_ % 500 == 0 && parm.temp_dualfile != 0) { FILE* outfile = fopen(parm.temp_dualfile, "w"); const VOL_dvector& u = dstar.u; const int m = u.size(); for (int i = 0; i < m; ++i) { fprintf(outfile, "%i %f\n", i + 1, u[i]); } fclose(outfile); } // test terminating criteria const bool primal_feas = (pstar.viol < parm.primal_abs_precision); const double gap = VolAbs(pstar.value - dstar.lcost); printf("Vol: pstar: %f, lbound: %f\n", pstar.value, dstar.lcost); const bool small_gap = VolAbs(dstar.lcost) < 0.0001 ? (gap < parm.gap_abs_precision) : ((gap < parm.gap_abs_precision) || (gap / VolAbs(dstar.lcost) < parm.gap_rel_precision)); // test optimality if (primal_feas && small_gap) { printf("VOL breaking because of small lp gap:(%lf/%lf)\n", pstar.value, dstar.lcost); break; } // test proving integer optimality if (best_ub - dstar.lcost < parm.granularity) { printf("VOL breaking because of small integer gap\n"); break; } // test for non-improvement const int k = iter_ % parm.ascent_check_invl; if (iter_ > ascent_first_check) { if (dstar.lcost - lcost_sequence[k] < VolAbs(lcost_sequence[k]) * parm.minimum_rel_ascent) { printf("VOL breaking because non-improvement\n"); break; } } lcost_sequence[k] = dstar.lcost; } printf("VOL took %d iterations\n", iter_); delete[] lcost_sequence; if (parm.printflag) print_info(iter_, primal, pstar, dual); // set solution to return value = dstar.lcost; psol = pstar.x; dsol = dstar.u; viol = pstar.v; //return retval; return found_integer_feasible; }