Beispiel #1
0
bool IASolverRelaxed::solve()
{
  
  // solve the nlp to get a non-integral solution, which we hope is close to a good integer solution    
  // adapted from HS071 ipopt example

  // p_norm set in constructor. 3 seems to work well, comes close to lex-max-min
  // smaller p has the effect of valuing the fidelity of shorter curves over longer curves more
  // larger p approaches min max
  IANlp *myianlp = new IANlp(iaData, iaSolution, silent);
  Ipopt::SmartPtr<TNLP> mynlp = myianlp; // Ipopt requires the use of smartptrs!
  
  Ipopt::SmartPtr<Ipopt::IpoptApplication> app = IpoptApplicationFactory();
  app->Options()->SetNumericValue("tol", 1e-7); // 2 seems close enough, could do less, say .1
  app->Options()->SetStringValue("mu_strategy", "adaptive");
  // print level 0 to 12, most. Ipopt Default is 5
  int print_level = (silent) ? 0 : 1; // 1, 5
  // int print_level = 5;
  app->Options()->SetIntegerValue("print_level", print_level);  
  // uncomment next line to write the solution to an output file
  // app->Options()->SetStringValue("output_file", "IA.out");  
  // The following overwrites the default name (ipopt.opt) of the options file
  // app->Options()->SetStringValue("option_file_name", "IA.opt");
  
  // Intialize the IpoptApplication and process the options
  Ipopt::ApplicationReturnStatus status;
  status = app->Initialize();
  if (status != Ipopt::Solve_Succeeded) {
    if (!silent)
      printf("\n\n*** Error during ipopt initialization!\n");
    return (int) status;
  }
  
  // Ask Ipopt to solve the problem
  status = app->OptimizeTNLP(mynlp); // the inherited IANlp
  // todo: also check for a valid solution even if ! Solve_Succeeded, such as a sub-optimal time-out
  bool is_solved = (status == Ipopt::Solve_Succeeded);
  bool is_satisfied = is_solved && equal_constraints( false, debugging );
  // don't check even-ness, as those are like the integrality constraints and are not solved here
  
  if (!silent)
  {
    if (is_solved) {
      printf("\n\n*** The relaxed problem solved!");
      if (!is_satisfied)
        printf(" But equality-constraints were VIOLATED!");
      printf("\n");
    }
    else {
      printf("\n\n*** The relaxed problem FAILED!\n");
    }
  }
  return is_satisfied;
}  
IpoptSolution CppADSolver::solve(OptProblemData &data){
    size_t n = opt_prob->num_of_variables();
    size_t m = opt_prob->num_of_constraints();
    // create the Ipopt interface
    cppad_ipopt_solution solution;
    CppADOptProblemData cppad_data(data);
    Ipopt::SmartPtr<Ipopt::TNLP> cppad_nlp = new cppad_ipopt_nlp(
        n, m, cppad_data.x_i, cppad_data.x_l, cppad_data.x_u, cppad_data.g_l, cppad_data.g_u, &(*fg_info_ptr), &solution
        );

    // Create an instance of the IpoptApplication
    Ipopt::SmartPtr<Ipopt::IpoptApplication> app = new IpoptApplication();

    // turn off any printing
    app->Options()->SetIntegerValue("print_level", 4);
    app->Options()->SetStringValue("sb", "yes");

    // maximum number of iterations
    app->Options()->SetIntegerValue("max_iter", 5000);

    // approximate accuracy in first order necessary conditions;
    // see Mathematical Programming, Volume 106, Number 1, 
    // Pages 25-57, Equation (6)
    app->Options()->SetNumericValue("tol", 1e-9);

    // derivative testing
//    app->Options()->
//    SetStringValue("derivative_test", "second-order");
//    app->Options()-> SetNumericValue(
//            "point_perturbation_radius", 0.
//    );

    // Initialize the IpoptApplication and process the options
    Ipopt::ApplicationReturnStatus status = app->Initialize();
    assert(status == Ipopt::Solve_Succeeded);

    // Run the IpoptApplication
    status = app->OptimizeTNLP(cppad_nlp);
    return IpoptSolution(solution);
}
Beispiel #3
0
bool retape_k1_l1(void)
{   bool ok = true;
    size_t j;


    // number of independent variables (domain dimension for f and g)
    size_t n = 2;
    // number of constraints (range dimension for g)
    size_t m = 1;
    // initial value of the independent variables
    NumberVector x_i(n);
    x_i[0] = 2.0;
    x_i[1] = 2.0;
    // lower and upper limits for x
    NumberVector x_l(n);
    NumberVector x_u(n);
    for(j = 0; j < n; j++)
    {   x_l[j] = -10.;
        x_u[j] = +10.;
    }
    // lower and upper limits for g
    NumberVector g_l(m);
    NumberVector g_u(m);
    g_l[0] = -1.;
    g_u[0] = 1.0e19;

    // object in derived class
    FG_retape fg_retape;
    cppad_ipopt_fg_info *fg_info = &fg_retape;

    // create the Ipopt interface
    cppad_ipopt_solution solution;
    Ipopt::SmartPtr<Ipopt::TNLP> cppad_nlp = new cppad_ipopt_nlp(
        n, m, x_i, x_l, x_u, g_l, g_u, fg_info, &solution
    );

    // Create an instance of the IpoptApplication
    using Ipopt::IpoptApplication;
    Ipopt::SmartPtr<IpoptApplication> app = new IpoptApplication();

    // turn off any printing
    app->Options()->SetIntegerValue("print_level", 0);
    app->Options()->SetStringValue("sb", "yes");

    // maximum number of iterations
    app->Options()->SetIntegerValue("max_iter", 10);

    // approximate accuracy in first order necessary conditions;
    // see Mathematical Programming, Volume 106, Number 1,
    // Pages 25-57, Equation (6)
    app->Options()->SetNumericValue("tol", 1e-9);

    // derivative testing
    app->Options()->
    SetStringValue("derivative_test", "second-order");

    // Initialize the IpoptApplication and process the options
    Ipopt::ApplicationReturnStatus status = app->Initialize();
    ok    &= status == Ipopt::Solve_Succeeded;

    // Run the IpoptApplication
    status = app->OptimizeTNLP(cppad_nlp);
    ok    &= status == Ipopt::Solve_Succeeded;

    /*
    Check some of the solution values
    */
    ok &= solution.status == cppad_ipopt_solution::success;
    //
    double check_x[]   = { -1., 0. };
    double rel_tol     = 1e-6;  // relative tolerance
    double abs_tol     = 1e-6;  // absolute tolerance
    for(j = 0; j < n; j++)
    {   ok &= CppAD::NearEqual(
                  check_x[j],   solution.x[j],   rel_tol, abs_tol
              );
    }

    return ok;
}
Beispiel #4
0
bool multiple_solution(void)
{
	bool ok = true;
	// number of independent variables (domain dimension for f and g)
	size_t n = 2;
	// number of constraints (range dimension for g)
	size_t m = 2; 
	// initial value of the independent variables
	NumberVector x_i(n);
	NumberVector x_l(n);
	NumberVector x_u(n);

	size_t i = 0;
	for(i = 0; i < n; i++)
	{	x_i[i] = 0.;
		x_l[i] = -1.0;
		x_u[i] = +1.0;
	}

	// lower and upper limits for g
	NumberVector g_l(m);
	NumberVector g_u(m);
	g_l[0] = -1; g_u[0] = 0.;
	g_l[1] = 0.; g_u[1] = 1.;

	// object for evaluating function
	bool retape = false;
	FG_J_changes my_fg_info(retape);
	cppad_ipopt_fg_info *fg_info = &my_fg_info;

	cppad_ipopt_solution solution;
	Ipopt::SmartPtr<Ipopt::TNLP> cppad_nlp = new cppad_ipopt_nlp(
		n, m, x_i, x_l, x_u, g_l, g_u, fg_info, &solution
	);

	// Create an instance of the IpoptApplication
	using Ipopt::IpoptApplication;
	Ipopt::SmartPtr<IpoptApplication> app = new IpoptApplication();

	// turn off any printing
	app->Options()->SetIntegerValue("print_level", 0);
	app->Options()->SetStringValue("sb", "yes");

	// approximate accuracy in first order necessary conditions;
	// see Mathematical Programming, Volume 106, Number 1,
	// Pages 25-57, Equation (6)
	app->Options()->SetNumericValue("tol", 1e-9);
	app->Options()-> SetStringValue("derivative_test", "second-order");

	// Initialize the IpoptApplication and process the options
	Ipopt::ApplicationReturnStatus status = app->Initialize();
	ok    &= status == Ipopt::Solve_Succeeded;

	// Run the IpoptApplication
	status = app->OptimizeTNLP(cppad_nlp);
	ok    &= status == Ipopt::Solve_Succeeded;

	/*
	 Check solution status
	 */
	ok &= solution.status == cppad_ipopt_solution::success;
	ok &= CppAD::NearEqual(solution.x[1], 0., 1e-6, 1e-6);

	return ok;
}
Beispiel #5
0
bool k_gt_one(void)
{	bool ok = true;
	size_t j;


	// number of independent variables (domain dimension for f and g)
	size_t n = 4;  
	// number of constraints (range dimension for g)
	size_t m = 2;
	// initial value of the independent variables
	NumberVector x_i(n);
	x_i[0] = 1.0;
	x_i[1] = 5.0;
	x_i[2] = 5.0;
	x_i[3] = 1.0;
	// lower and upper limits for x
	NumberVector x_l(n);
	NumberVector x_u(n);
	for(j = 0; j < n; j++)
	{	x_l[j] = 1.0;
		x_u[j] = 5.0;
	}
	// lower and upper limits for g
	NumberVector g_l(m);
	NumberVector g_u(m);
	g_l[0] = 25.0;     g_u[0] = 1.0e19;
  	g_l[1] = 40.0;     g_u[1] = 40.0;

	// known solution to check against
	double check_x[]   = { 1.000000, 4.743000, 3.82115, 1.379408 };

	size_t icase;
	for(icase = 0; icase <= 1; icase++)
	{	// Should cppad_ipopt_nlp retape the operation sequence for
		// every new x. Can test both true and false cases because 
		// the operation sequence does not depend on x (for this case).
		bool retape = bool(icase);

		// check case where upper and lower limits are equal
		if( icase == 1 )
		{	x_l[2] = check_x[2];
			x_u[2] = check_x[2];
		}

		// object in derived class
		FG_K_gt_one my_fg_info(retape);
		cppad_ipopt_fg_info *fg_info = &my_fg_info;  

		// create the Ipopt interface
		cppad_ipopt_solution solution;
		Ipopt::SmartPtr<Ipopt::TNLP> cppad_nlp = new cppad_ipopt_nlp(
		n, m, x_i, x_l, x_u, g_l, g_u, fg_info, &solution
		);

		// Create an instance of the IpoptApplication
		using Ipopt::IpoptApplication;
		Ipopt::SmartPtr<IpoptApplication> app = new IpoptApplication();

		// turn off any printing
		app->Options()->SetIntegerValue("print_level", 0);

		// maximum number of iterations
		app->Options()->SetIntegerValue("max_iter", 10);

		// approximate accuracy in first order necessary conditions;
		// see Mathematical Programming, Volume 106, Number 1, 
		// Pages 25-57, Equation (6)
		app->Options()->SetNumericValue("tol", 1e-9);

		// derivative testing
		app->Options()->
		SetStringValue("derivative_test", "second-order");

		// Initialize the IpoptApplication and process the options
		Ipopt::ApplicationReturnStatus status = app->Initialize();
		ok    &= status == Ipopt::Solve_Succeeded;

		// Run the IpoptApplication
		status = app->OptimizeTNLP(cppad_nlp);
		ok    &= status == Ipopt::Solve_Succeeded;

		/*
 		Check some of the solution values
 		*/
		ok &= solution.status == cppad_ipopt_solution::success;
		//
		double check_z_l[] = { 1.087871, 0.,       0.,      0.       };
		double check_z_u[] = { 0.,       0.,       0.,      0.       };
		double rel_tol     = 1e-6;  // relative tolerance
		double abs_tol     = 1e-6;  // absolute tolerance
		for(j = 0; j < n; j++)
		{	ok &= CppAD::NearEqual(
			check_x[j],   solution.x[j],   rel_tol, abs_tol
			);
			ok &= CppAD::NearEqual(
			check_z_l[j], solution.z_l[j], rel_tol, abs_tol
			);
			ok &= CppAD::NearEqual(
			check_z_u[j], solution.z_u[j], rel_tol, abs_tol
			);
		}
	}

	return ok;
}
Beispiel #6
0
void solve(
	const std::string&                   options   ,
	const Dvector&                       xi        ,
	const Dvector&                       xl        ,
	const Dvector&                       xu        ,
	const Dvector&                       gl        ,
	const Dvector&                       gu        ,
	FG_eval&                             fg_eval   ,
	ipopt::solve_result<Dvector>&        solution  )
{	bool ok = true;

	typedef typename FG_eval::ADvector ADvector;

	CPPAD_ASSERT_KNOWN(
		xi.size() == xl.size() && xi.size() == xu.size() ,
		"ipopt::solve: size of xi, xl, and xu are not all equal."
	);
	CPPAD_ASSERT_KNOWN(
		gl.size() == gu.size() ,
		"ipopt::solve: size of gl and gu are not equal."
	);
	size_t nx = xi.size();
	size_t ng = gl.size();

	// Create an IpoptApplication
	using Ipopt::IpoptApplication;
	Ipopt::SmartPtr<IpoptApplication> app = new IpoptApplication();

	// process the options argument
	size_t begin_1, end_1, begin_2, end_2, begin_3, end_3;
	begin_1     = 0;
	bool retape          = false;
	bool sparse_forward  = false;
	bool sparse_reverse  = false;
	while( begin_1 < options.size() )
	{	// split this line into tokens
		while( options[begin_1] == ' ')
			begin_1++;
		end_1   = options.find_first_of(" \n", begin_1);
		begin_2 = end_1;
		while( options[begin_2] == ' ')
			begin_2++;
		end_2   = options.find_first_of(" \n", begin_2);
		begin_3 = end_2;
		while( options[begin_3] == ' ')
			begin_3++;
		end_3   = options.find_first_of(" \n", begin_3);

		// check for errors
		CPPAD_ASSERT_KNOWN(
			(end_1 != std::string::npos)  &
			(end_2 != std::string::npos)  &
			(end_3 != std::string::npos)  ,
			"ipopt::solve: missing '\\n' at end of an option line"
		);
		CPPAD_ASSERT_KNOWN(
			(end_1 > begin_1) & (end_2 > begin_2) ,
			"ipopt::solve: an option line does not have two tokens"
		);

		// get first two tokens
		std::string tok_1 = options.substr(begin_1, end_1 - begin_1);
		std::string tok_2 = options.substr(begin_2, end_2 - begin_2);

		// get third token
		std::string tok_3;
		bool three_tok = false;
		three_tok |= tok_1 == "Sparse";
		three_tok |= tok_1 == "String";
		three_tok |= tok_1 == "Numeric";
		three_tok |= tok_1 == "Integer";
		if( three_tok )
		{	CPPAD_ASSERT_KNOWN(
				(end_3 > begin_3) ,
				"ipopt::solve: a Sparse, String, Numeric, or Integer\n"
				"option line does not have three tokens."
			);
			tok_3 = options.substr(begin_3, end_3 - begin_3);
		}

		// switch on option type
		if( tok_1 == "Retape" )
		{	CPPAD_ASSERT_KNOWN(
				(tok_2 == "true") | (tok_2 == "false") ,
				"ipopt::solve: Retape value is not true or false"
			);
			retape = (tok_2 == "true");
		}
		else if( tok_1 == "Sparse" )
		{	CPPAD_ASSERT_KNOWN(
				(tok_2 == "true") | (tok_2 == "false") ,
				"ipopt::solve: Sparse value is not true or false"
			);
			CPPAD_ASSERT_KNOWN(
				(tok_3 == "forward") | (tok_3 == "reverse") ,
				"ipopt::solve: Sparse direction is not forward or reverse"
			);
			if( tok_2 == "false" )
			{	sparse_forward = false;
				sparse_reverse = false;
			}
			else
			{	sparse_forward = tok_3 == "forward";
				sparse_reverse = tok_3 == "reverse";
			}
		}
		else if ( tok_1 == "String" )
			app->Options()->SetStringValue(tok_2.c_str(), tok_3.c_str());
		else if ( tok_1 == "Numeric" )
		{	Ipopt::Number value = std::atof( tok_3.c_str() );
			app->Options()->SetNumericValue(tok_2.c_str(), value);
		}
		else if ( tok_1 == "Integer" )
		{	Ipopt::Index value = std::atoi( tok_3.c_str() );
			app->Options()->SetIntegerValue(tok_2.c_str(), value);
		}
		else	CPPAD_ASSERT_KNOWN(
			false,
			"ipopt::solve: First token is not one of\n"
			"Retape, Sparse, String, Numeric, Integer"
		);

		begin_1 = end_3;
		while( options[begin_1] == ' ')
			begin_1++;
		if( options[begin_1] != '\n' ) CPPAD_ASSERT_KNOWN(
			false,
			"ipopt::solve: either more than three tokens "
			"or no '\\n' at end of a line"
		);
		begin_1++;
	}
	CPPAD_ASSERT_KNOWN(
		! ( retape & (sparse_forward | sparse_reverse) ) ,
		"ipopt::solve: retape and sparse both true is not supported."
	);

	// Initialize the IpoptApplication and process the options
	Ipopt::ApplicationReturnStatus status = app->Initialize();
	ok    &= status == Ipopt::Solve_Succeeded;
	if( ! ok )
	{	solution.status = solve_result<Dvector>::unknown;
		return;
	}

	// Create an interface from Ipopt to this specific problem.
	// Note the assumption here that ADvector is same as cppd_ipopt::ADvector
	size_t nf = 1;
	Ipopt::SmartPtr<Ipopt::TNLP> cppad_nlp =
	new CppAD::ipopt::solve_callback<Dvector, ADvector, FG_eval>(
		nf,
		nx,
		ng,
		xi,
		xl,
		xu,
		gl,
		gu,
		fg_eval,
		retape,
		sparse_forward,
		sparse_reverse,
		solution
	);

	// Run the IpoptApplication
	app->OptimizeTNLP(cppad_nlp);

	return;
}
Beispiel #7
0
bool IASolverInt::solve_wave_workhorse(IAIntWaveNlp *mynlp)
{
  if (debugging)
  {
    printf("IASolverInt::solve_wave() - ");        
    printf("Attempting to enforce an integer and even solution to the relaxed NLP by adding constraints that repeat wave-like at each integer lattice point.\n");
  }
  
  // solver setup  
  Ipopt::SmartPtr<Ipopt::IpoptApplication> app = IpoptApplicationFactory();
/* try leaving defaults
  // convergence parameters
  // see $IPOPTDIR/Ipopt/src/Interfaces/IpIpoptApplication.cpp
  // our real criteria are: all integer, constraints satisfied. How to test the "all_integer" part?
  app->Options()->SetNumericValue("tol", 1e-6); //"converged" if NLP error<this, default is 1e-7. Obj are scaled to be >1, so e-2 is plenty // was 1e-2
  app->Options()->SetNumericValue("max_cpu_time", sqrt( iaData->num_variables() ) ); // max time allowed in seconds
  app->Options()->SetIntegerValue("max_iter", 3 * (10 + iaData->num_variables() ) ); // max number of iterations
  // app->Options()->SetNumericValue("primal_inf_tol", 1e-2 ); 
  app->Options()->SetNumericValue("dual_inf_tol", 1e-2 ); // how close to infeasibility? // was 1e-2
  app->Options()->SetNumericValue("constr_viol_tol", 1e-2 ); // by how much can constraints be violated?
  app->Options()->SetNumericValue("compl_inf_tol", 1e-6 ); // max norm of complementary condition // was 1e-2
  
  // second criteria convergence parameters: quit if within this tol for many iterations
  // was  app->Options()->SetIntegerValue("acceptable_iter", 4 + sqrt( iaData->num_variables() ) ); //as "tol"
  app->Options()->SetNumericValue("acceptable_tol", 1e-6 ); //as "tol" was 1e-1
  
  app->Options()->SetStringValue("mu_strategy", "adaptive");
  // print level 0 to 12, Ipopt default is 5
  const int print_level = (silent) ? 0 : 1;  // simple info is 1, debug at other values
  app->Options()->SetIntegerValue("print_level", print_level);  
  // uncomment next line to write the solution to an output file
  // app->Options()->SetStringValue("output_file", "IA.out");  
  // The following overwrites the default name (ipopt.opt) of the options file
  // app->Options()->SetStringValue("option_file_name", "IA.opt");
  
  */
  
  // Intialize the IpoptApplication and process the options
  Ipopt::ApplicationReturnStatus status;
  status = app->Initialize();
  if (status != Ipopt::Solve_Succeeded) {
    if (!silent)
      printf("\n\n*** Error during initialization!\n");
    return (int) status;
  }
  
  bool try_again = true;
  int iter = 0;
  
  // print();
  bool solution_ok = false;
  
  do {
    if (debugging)
    {
      print();
      printf("%d IntWave iteration\n", iter );
      // build the hessian, evaluate it and f at the current solution?
    }
      
    // Ask Ipopt to solve the problem
    status = app->OptimizeTNLP(mynlp); // the inherited IANlp
    
    // see /CoinIpopt/build/include/coin/IpReturnCodes_inc.h
    /*
    Solve_Succeeded=0,
    Solved_To_Acceptable_Level=1,
    Infeasible_Problem_Detected=2,
    Search_Direction_Becomes_Too_Small=3,
    Diverging_Iterates=4,
    User_Requested_Stop=5,
    Feasible_Point_Found=6,
    
    Maximum_Iterations_Exceeded=-1,
    Restoration_Failed=-2,
    Error_In_Step_Computation=-3,
    Maximum_CpuTime_Exceeded=-4,
    Not_Enough_Degrees_Of_Freedom=-10,
    Invalid_Problem_Definition=-11,
    Invalid_Option=-12,
    Invalid_Number_Detected=-13,
    
    Unrecoverable_Exception=-100,
    NonIpopt_Exception_Thrown=-101,
    Insufficient_Memory=-102,
    Internal_Error=-199
     */

    bool solved_full = false;
    bool solved_partial = false;
    bool solver_failed = false;
    bool bad_problem = false;

    switch (status) {
      case Ipopt::Solve_Succeeded:
      case Ipopt::Solved_To_Acceptable_Level:
      case Ipopt::Feasible_Point_Found:
        solved_full = true;
        break;
      case Ipopt::Maximum_Iterations_Exceeded:
      case Ipopt::User_Requested_Stop:
      case Ipopt::Maximum_CpuTime_Exceeded:
        solved_partial = true;
        break;
      case Ipopt::Infeasible_Problem_Detected:
      case Ipopt::Not_Enough_Degrees_Of_Freedom:
      case Ipopt::Invalid_Problem_Definition:
      case Ipopt::Invalid_Option:
      case Ipopt::Invalid_Number_Detected:
        bad_problem = true;
        break;
      case Ipopt::Search_Direction_Becomes_Too_Small:
      case Ipopt::Restoration_Failed:
      case Ipopt::Diverging_Iterates:
      case Ipopt::Error_In_Step_Computation:
      case Ipopt::Unrecoverable_Exception:
      case Ipopt::NonIpopt_Exception_Thrown:
      case Ipopt::Insufficient_Memory:
      case Ipopt::Internal_Error:        
        solver_failed = true;
        break;
        
      default:
        break;
    }
  
    if (!silent)
    {
      if (solved_full) {
        printf("\n\n*** IntWave solved!\n");
      }
      else {
        printf("\n\n*** IntWave FAILED!\n");
      }
    }
    
    if (debugging)
    {
      printf("\nChecking solution.\n");
      bool integer_sat = solution_is_integer(true);
      bool even_sat = even_constraints( false, true);
      bool equal_sat = equal_constraints( false, true );
      printf("IntWave solution summary, %s, equal-constraints %s, even-constraints %s.\n", 
             integer_sat ? "integer" : "NON-INTEGER",
             equal_sat ? "satisfied" : "VIOLATED", 
             even_sat ? "satisfied" : "VIOLATED" );
      if (!integer_sat)
        printf("investigate integer neighborhood\n");
      if (!even_sat)
        printf("investigate even neighborhood\n");
      if (!equal_sat)
        printf("investigate equal neighborhood\n");
    }
    
    
    IASolution nlp_solution;
    nlp_solution.x_solution = ia_solution()->x_solution; // vector copy
    IASolverToolInt sti( ia_data(), &nlp_solution );
    sti.round_solution();
    if (debugging)
      printf("Checking rounded solution, ignoring even constraints.\n");
    if (sti.equal_constraints(false, debugging))
    {
      // also even constraints
      if (debugging)
        printf("Rounding worked.\n");
      
      // rounding was a valid integer solution
      ia_solution()->x_solution.swap( nlp_solution.x_solution );
      // ia_solution()->obj_value is no longer accurate, as it was for the non-rounded solution
      return true;
    }
    
    // todo: detect and act
    // may have converged to a locally optimal, but non-feasible solution
    // if so, try a new starting point
    
    // check solution feasibility, even when not debugging
    
    if ( solved_full || solved_partial )
    {
      bool integer_sat = solution_is_integer(false);
      bool even_sat = even_constraints( false, false);
      bool equal_sat = equal_constraints( false, false );
      if ( integer_sat && even_sat && equal_sat )
        return true;
    }

    // find out which vars were not integer, 
    // try moving to a farther starting point resolving
    
 
    try_again = false; 
  } while (try_again);
  
  
  // now 
  // As the SmartPtrs go out of scope, the reference count
  // will be decremented and the objects will automatically
  // be deleted.  
  return solution_ok;
  
}
Beispiel #8
0
bool IASolverInt::solve_round()
{
  // set up and call the separate IARoundingNlp, which has a linear objective to get a natural integer solution 
  // the intuition is this will solve integrality for  most variables all at once

  if (debugging)
  {
    printf("IASolverInt::solve_bend_workhorse() - ");        
  }

  
  // solver setup  
  Ipopt::SmartPtr<Ipopt::IpoptApplication> app = IpoptApplicationFactory();
  
  // convergence parameters
  // see $IPOPTDIR/Ipopt/src/Interfaces/IpIpoptApplication.cpp
  // our real criteria are: all integer, constraints satisfied. How to test the "all_integer" part?
  app->Options()->SetNumericValue("tol", 1e-6); //"converged" if NLP error<this, default is 1e-7. Obj are scaled to be >1, so e-2 is plenty // was 1e-2
  app->Options()->SetNumericValue("max_cpu_time", sqrt( iaData->num_variables() ) ); // max time allowed in seconds
  app->Options()->SetIntegerValue("max_iter", 3 * iaData->num_variables() ); // max number of iterations
  // app->Options()->SetNumericValue("primal_inf_tol", 1e-2 ); 
  app->Options()->SetNumericValue("dual_inf_tol", 1e-6 ); // how close to infeasibility? // was 1e-2
  app->Options()->SetNumericValue("constr_viol_tol", 1e-6 ); // by how much can constraints be violated?
  app->Options()->SetNumericValue("compl_inf_tol", 1e-6 ); // max norm of complementary condition // was 1e-2

  // second criteria convergence parameters: quit if within this tol for many iterations
// was  app->Options()->SetIntegerValue("acceptable_iter", 4 + sqrt( iaData->num_variables() ) ); //as "tol"
  app->Options()->SetNumericValue("acceptable_tol", 1e-6 ); //as "tol" was 1e-1

  app->Options()->SetStringValue("mu_strategy", "adaptive");
  // print level 0 to 12, Ipopt default is 5
  const int print_level = (silent) ? 0 : 1; 
  app->Options()->SetIntegerValue("print_level", print_level);  
  // uncomment next line to write the solution to an output file
  // app->Options()->SetStringValue("output_file", "IA.out");  
  // The following overwrites the default name (ipopt.opt) of the options file
  // app->Options()->SetStringValue("option_file_name", "IA.opt");
  
  // Intialize the IpoptApplication and process the options
  Ipopt::ApplicationReturnStatus status;
  status = app->Initialize();
  if (status != Ipopt::Solve_Succeeded) {
    if (!silent)
      printf("\n\n*** Error during initialization!\n");
    return (int) status;
  }
  
  
  Ipopt::TNLP *tnlp = NULL;

  IARoundingNlp *myianlp = new IARoundingNlp(iaData, ipData, iaSolution, silent);
  if (debugging) 
  {          
    printf("ROUNDING problem formulation\n");
    printf("Attempting to find a naturally-integer solution by linearizing the objective function.\n");
    printf("Variables are constrained within [floor,ceil] of relaxed solution.\n");
  }
  
  // problem setup
  // a couple of different models, simplest to more complex
  // IARoundingFarNlp *myianlp = new IARoundingFarNlp(iaData, ipData, this);
  // IARoundingFar3StepNlp *myianlp = new IARoundingFar3StepNlp(iaData, ipData, this); // haven't tested this. It compiles and runs but perhaps isn't correct
  // IAIntWaveNlp *myianlp = new IAIntWaveNlp(iaData, ipData, this); // haven't tested this. It compiles and runs but perhaps isn't correct

  tnlp = myianlp;
  Ipopt::SmartPtr<Ipopt::TNLP> mynlp = tnlp; // Ipopt requires the use of smartptrs!

  bool try_again = true;
  int iter = 0;
  do {
    printf("%d rounding iteration\n", iter );
    
    // Ask Ipopt to solve the problem
    status = app->OptimizeTNLP(mynlp); // the inherited IANlp
    
    if (!silent)
    {
      if (status == Ipopt::Solve_Succeeded) {
        printf("\n\n*** The problem solved!\n");
      }
      else {
        printf("\n\n*** The problem FAILED!\n");
      }
    }
    
    // The problem should have been feasible, but it is possible that it had no integer solution.
    // figure out which variables are still integer
    
    // check solution for integrality and constraint satified    
    if (debugging)
    {
      printf("\nChecking Natural (non-rounded) solution.\n");
      bool integer_sat = solution_is_integer(true);
      bool even_sat = even_constraints( false, true);
            bool equal_sat = equal_constraints( false, true );
      printf("Natural solution summary, %s, equal-constraints %s, even-constraints %s.\n", 
             integer_sat ? "integer" : "NON-INTEGER",
             equal_sat ? "satisfied" : "VIOLATED", 
             even_sat ? "satisfied" : "VIOLATED" );
      if (!integer_sat)
        printf("investigate this\n");
    }
    
    IASolution nlp_solution;
    nlp_solution.x_solution = ia_solution()->x_solution; // vector copy
    IASolverToolInt sti( ia_data(), &nlp_solution );
    sti.round_solution();
    if (debugging)
      printf("Checking rounded solution, ignoring even constraints.\n");
    if (sti.equal_constraints(false, debugging))
    {
      // also even constraints
      if (debugging)
        printf("Rounding worked.\n");

      // rounding was a valid integer solution
      ia_solution()->x_solution.swap( nlp_solution.x_solution );
      // ia_solution()->obj_value is no longer accurate, as it was for the non-rounded solution
      return true;
    }

    // find out which vars were not integer, 
    // try rounding their weights and resolving
    // bool int_sat = solution_is_integer();
    ++iter;
    try_again = iter < 4 + sqrt(iaData->num_variables());
    if (try_again)
    {
      if (debugging)
        printf("rounding failed, randomizing weights\n");
    
      myianlp->randomize_weights_of_non_int(); // try again? debug
    }
    else if (debugging)
      printf("giving up on rounding to non-integer solution\n");

    // try_again = false; // debug
  } while (try_again);

  
  // todo: update partially-integer solution, perhaps using ipData - figure out how we're going to use it, first, for what structure makes sense.
  
  // As the SmartPtrs go out of scope, the reference count
  // will be decremented and the objects will automatically
  // be deleted.  
  return status == Ipopt::Solve_Succeeded;
  
}