Example #1
0
//######################################################################
/// 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;
}