// Copyright (c) 1997-2007  ETH Zurich (Switzerland).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL: https://github.com/CGAL/cgal/blob/v6.1.1/QP_solver/include/CGAL/QP_functions.h $
// $Id: include/CGAL/QP_functions.h 08b27d3db14 $
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s)     : Bernd Gaertner <gaertner@inf.ethz.ch>

#ifndef CGAL_QP_FUNCTIONS_H
#define CGAL_QP_FUNCTIONS_H

#include <CGAL/license/QP_solver.h>

#include <CGAL/disable_warnings.h>

#include <iostream>
#include <string>
#include <CGAL/QP_options.h>
#include <CGAL/QP_solution.h>

namespace CGAL {

namespace QP_functions_detail {
  // internal routine; writes P to out in MPS format
  // Is_linear == Tag_true / Tag_false:
  //    p is treated as LinearProgram / QuadraticProgram
  // Is_nonnegative == Tag_true / Tag_false
  //    p is treated as Nonnegative / Arbitrary
  // the dmatrix parameter specifies whether the quadratic matrix (if any)
  // is written in DMATRIX format (no multiplication by two, good for
  // cross-checking output, or in QMATRIX format (good for using other
  // solvers like CPLEX)
  template <typename P, typename Is_linear, typename Is_nonnegative>
  void print_program
  (std::ostream& out,
   const P &p,
   const std::string& problem_name,
   Is_linear is_linear,
   Is_nonnegative is_nonnegative);

  // internal routine: solves a program, depending on the tags
  template <typename Program, typename ET,
            typename Is_linear,typename Is_nonnegative >
  Quadratic_program_solution<ET> solve_program
  (const Program &p, const ET&,
   Is_linear is_linear,
   Is_nonnegative is_nonnegative,
   const Quadratic_program_options& options = Quadratic_program_options());

  // internal routines: prints name of solution function
  inline void print_solution_function
  (std::ostream& out,
   Tag_true /*is_linear*/, Tag_true /*is_nonnegative*/)
  {
    out << "solve_nonnegative_linear_program";
  }
  inline void print_solution_function
  (std::ostream& out,
   Tag_false /*is_linear*/, Tag_true /*is_nonnegative*/)
  {
    out << "solve_nonnegative_quadratic_program";
  }
  inline void print_solution_function
  (std::ostream& out,
   Tag_true /*is_linear*/, Tag_false /*is_nonnegative*/)
  {
    out << "solve_linear_program";
  }
  inline void print_solution_function
  (std::ostream& out,
   Tag_false /*is_linear*/, Tag_false /*is_nonnegative*/)
  {
    out << "solve_quadratic_program";
  }

  // internal routine:
  // test whether the system is of the form A x == b (equations only)
  template <typename R>
  bool is_in_equational_form (const R& r);

  // internal routine:
  // test whether the row vectors of A that correspond to equations
  // are linearly independent; this is done using type ET. The value
  // type of LinearInequalitySystem must be convertible to ET
  template <class Ar, class ET>
  bool has_linearly_independent_equations
  (const Ar& ar, const ET& dummy);
}

template <typename QuadraticProgram>
void print_quadratic_program
(std::ostream& out, const QuadraticProgram &qp,
 const std::string& problem_name = std::string("MY_MPS"))
// writes qp to out in MPS format
{
  QP_functions_detail::print_program
    (out, qp, problem_name, CGAL::Tag_false(), CGAL::Tag_false());
}

template <typename LinearProgram>
void print_linear_program
(std::ostream& out, const LinearProgram &lp,
 const std::string& problem_name = std::string("MY_MPS"))
// writes lp to out in MPS format
{
  QP_functions_detail::print_program
    (out, lp, problem_name, CGAL::Tag_true(), CGAL::Tag_false());
}

template <typename NonnegativeQuadraticProgram>
void print_nonnegative_quadratic_program
(std::ostream& out, const NonnegativeQuadraticProgram &qp,
 const std::string& problem_name = std::string("MY_MPS"))
// writes qp to out in MPS format
{
  QP_functions_detail::print_program
    (out, qp, problem_name, CGAL::Tag_false(), CGAL::Tag_true());
}

template <typename NonnegativeLinearProgram>
void print_nonnegative_linear_program
(std::ostream& out, const NonnegativeLinearProgram &lp,
 const std::string& problem_name = std::string("MY_MPS"))
// writes lp to out in MPS format
{
  QP_functions_detail::print_program
    (out, lp, problem_name, CGAL::Tag_true(), CGAL::Tag_true());
}

template <typename QuadraticProgram, typename ET>
Quadratic_program_solution<ET> solve_quadratic_program
(const QuadraticProgram &qp, const ET&,
const Quadratic_program_options& options = Quadratic_program_options());

template <typename NonnegativeQuadraticProgram, typename ET>
Quadratic_program_solution<ET> solve_nonnegative_quadratic_program
(const NonnegativeQuadraticProgram &qp, const ET&,
const Quadratic_program_options& options = Quadratic_program_options());

template <typename LinearProgram, typename ET>
Quadratic_program_solution<ET> solve_linear_program
(const LinearProgram &lp, const ET&,
const Quadratic_program_options& options = Quadratic_program_options());

template <typename NonnegativeLinearProgram, typename ET>
Quadratic_program_solution<ET> solve_nonnegative_linear_program
(const NonnegativeLinearProgram &lp, const ET&,
const Quadratic_program_options& options = Quadratic_program_options());

} //namespace CGAL

#include <CGAL/QP_solver/QP_functions_impl.h>

#include <CGAL/enable_warnings.h>

#endif // CGAL_QP_FUNCTIONS_H
