#include "arhiplex_client.h"
#include <iostream>

// The problem to solve:
//
//  Maximize:
//    x1 + 2 * x2 - 0.1 * x3 - 3 * x4
//
//  Subject to:
//     c0: x1 + x2 <= 5
//     c1: 2 * x1 - x2 >= 0
//     c2: -x1 + 3 * x2 >= 0
//     c3: x3 + x4 >= 0.5
//
//  where:
//    x1 Free
//    x2 Free
//    1.1 <= x3 <= 10.0
//    x4 Free

int main(int argc, char *argv[])
{
  try
  {
    setlocale(LC_CTYPE, "Russian");
    using namespace arhiplex;
    arhiplex::Model model;
    //Как пример - для данной простой модели не актуально
    model.SetDblParam("time_limit", 10.0); //10 сек
    model.SetDblParam("mip_rel_gap", 0.0005); //0.05%

    // Добавление переменных
    auto x1 = model.AddVariable(-arhiplex::inf, arhiplex::inf, 0.0,
      variable_type::continuous, "x1");
    auto x2 = model.AddVariable(-arhiplex::inf, arhiplex::inf, 0.0,
      variable_type::continuous, "x2");
    auto x3 = model.AddVariable(0.0, arhiplex::inf, 0.0,
      variable_type::continuous, "x3");
    auto x4 = model.AddVariable(-arhiplex::inf, arhiplex::inf, 0.0,
      variable_type::continuous, "x4");

    x3.SetLowerBound(1.1);
    x3.SetUpperBound(10.0);
    // или сразу 
    // auto x3 = model.AddVariable(1.1, 10.0, 0.0,
    //   variable_type::continuous, "x3");

    model.SetObjective(x1 + 2 * x2 - 0.1 * x3 - 3 * x4,
      objective_sense::maximize);

    model.AddConstraint(x1 + x2 <= 5, "c0");
    model.AddConstraint(2 * x1 - x2 >= 0, "c1");
    model.AddConstraint(-x1 + 3 * x2 >= 0, "c2");
    model.AddConstraint(x3 + x4 >= 0.5, "c3");

    auto solve_result = model.Solve();
    
    auto solve_time = solve_result.GetSolveTime();
    auto solve_res = solve_result.GetSolveResult();
    auto solution_status = solve_result.GetSolutionStatus();

    if (solve_res == solve_result::success && 
        (solution_status == solution_status::optimal ||
         solution_status == solution_status::feasible))
    {
      auto gap = solve_result.GetRelativeGap();
      auto x1val = solve_result.GetVariableValue(x1);
      auto x2val = solve_result.GetVariableValue("x2");
      auto x3val = solve_result.GetVariableValue("x3");
      auto x4val = solve_result.GetVariableValue(x4);
      std::cout << "Gap: "  << gap << "\n";
      std::cout << "Variables:\n" << "x1: " << x1val <<
        "\nx2: " << x2val << "\nx3: " << x3val <<
        "\nx4: " << x4val << "\n";
    }       
  }
  catch (const arhiplex::arhiplex_exception &ex)
  {
    std::cout << ex.what() << std::endl;
  }
  catch (...)
  {
    std::cout << "Unknown exception occurs!";
  }
  return 0;
}
