1550 lines
47 KiB
C
1550 lines
47 KiB
C
|
// 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/v5.1/QP_solver/include/CGAL/QP_models.h $
|
||
|
// $Id: QP_models.h 0779373 2020-03-26T13:31:46+01:00 Sébastien Loriot
|
||
|
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||
|
//
|
||
|
//
|
||
|
// Author(s) : Bernd Gaertner <gaertner@inf.ethz.ch>, Kaspar Fischer
|
||
|
|
||
|
#ifndef CGAL_QP_MODELS_H
|
||
|
#define CGAL_QP_MODELS_H
|
||
|
|
||
|
#include <CGAL/license/QP_solver.h>
|
||
|
|
||
|
#include <CGAL/disable_warnings.h>
|
||
|
|
||
|
#include <CGAL/basic.h>
|
||
|
#include <CGAL/iterator.h>
|
||
|
#include <CGAL/algorithm.h>
|
||
|
#include <CGAL/QP_solver/basic.h>
|
||
|
#include <CGAL/QP_solver/functors.h>
|
||
|
#include <CGAL/IO/io.h>
|
||
|
#include <vector>
|
||
|
#include <map>
|
||
|
#include <iomanip>
|
||
|
#include <istream>
|
||
|
#include <sstream>
|
||
|
|
||
|
#include <CGAL/boost/iterator/counting_iterator.hpp>
|
||
|
#include <CGAL/boost/iterator/transform_iterator.hpp>
|
||
|
|
||
|
// this file defines the following models:
|
||
|
// - Quadratic_program_from_iterators
|
||
|
// - Quadratic_program
|
||
|
// - Quadratic_program_from_mps
|
||
|
// - Nonngative_quadratic_program_from_iterators
|
||
|
// - Linear_program_from_iterators
|
||
|
// - Nonngative_linear_program_from_iterators
|
||
|
|
||
|
// for convenience, every model is actually a model of the
|
||
|
// concept QuadraticProgramInterface:
|
||
|
#define QP_MODEL_ITERATOR_TYPES \
|
||
|
typedef typename Base::A_iterator A_iterator;\
|
||
|
typedef typename Base::B_iterator B_iterator;\
|
||
|
typedef typename Base::R_iterator R_iterator;\
|
||
|
typedef typename Base::FL_iterator FL_iterator;\
|
||
|
typedef typename Base::L_iterator L_iterator;\
|
||
|
typedef typename Base::FU_iterator FU_iterator;\
|
||
|
typedef typename Base::U_iterator U_iterator;\
|
||
|
typedef typename Base::D_iterator D_iterator;\
|
||
|
typedef typename Base::C_iterator C_iterator;\
|
||
|
typedef typename Base::C_entry C_entry
|
||
|
namespace CGAL {
|
||
|
|
||
|
// default iterator types to used to make linear / nonnegative models
|
||
|
// conform to QuadraticProgramInterface
|
||
|
template <class Iterator>
|
||
|
class QP_model_default_iterators {
|
||
|
private:
|
||
|
typedef typename std::iterator_traits<Iterator>::value_type value_type;
|
||
|
public:
|
||
|
typedef Const_oneset_iterator<value_type>
|
||
|
It_1d; // 1-dimensional random access iterator for a constant value
|
||
|
typedef Const_oneset_iterator<Const_oneset_iterator<value_type> >
|
||
|
It_2d; // 2-dimensional random access iterator for a constant value
|
||
|
};
|
||
|
|
||
|
// Quadratic_program_from_iterators
|
||
|
// --------------------------------
|
||
|
// this is the base class for all non-mps models
|
||
|
template <
|
||
|
typename A_it, // for constraint matrix A (columnwise)
|
||
|
typename B_it, // for right-hand side b
|
||
|
typename R_it, // for relations (value type Comparison)
|
||
|
typename FL_it, // for finiteness of lower bounds (value type bool)
|
||
|
typename L_it, // for lower bounds
|
||
|
typename FU_it, // for finiteness of upper bounds (value type bool)
|
||
|
typename U_it, // for upper bounds
|
||
|
typename D_it, // for quadratic matrix D (rowwise)
|
||
|
typename C_it > // for objective function c
|
||
|
class Quadratic_program_from_iterators
|
||
|
{
|
||
|
public:
|
||
|
// types
|
||
|
typedef A_it A_iterator;
|
||
|
typedef B_it B_iterator;
|
||
|
typedef R_it R_iterator;
|
||
|
typedef FL_it FL_iterator;
|
||
|
typedef L_it L_iterator;
|
||
|
typedef FU_it FU_iterator;
|
||
|
typedef U_it U_iterator;
|
||
|
typedef D_it D_iterator;
|
||
|
typedef C_it C_iterator;
|
||
|
typedef typename std::iterator_traits<C_it>::value_type C_entry;
|
||
|
protected:
|
||
|
// data
|
||
|
int n_;
|
||
|
int m_;
|
||
|
A_iterator a_it;
|
||
|
B_iterator b_it;
|
||
|
R_iterator r_it;
|
||
|
FL_iterator fl_it;
|
||
|
L_iterator l_it;
|
||
|
FU_iterator fu_it;
|
||
|
U_iterator u_it;
|
||
|
D_iterator d_it;
|
||
|
C_iterator c_it;
|
||
|
C_entry c_0; // constant term
|
||
|
public:
|
||
|
// construction
|
||
|
Quadratic_program_from_iterators (
|
||
|
int n, int m, // number of variables / constraints
|
||
|
const A_iterator& a,
|
||
|
const B_iterator& b,
|
||
|
const R_iterator& r,
|
||
|
const FL_iterator& fl,
|
||
|
const L_iterator& l,
|
||
|
const FU_iterator& fu,
|
||
|
const U_iterator& u,
|
||
|
const D_iterator& d,
|
||
|
const C_iterator& c,
|
||
|
const C_entry& c0 = C_entry(0))
|
||
|
: n_ (n), m_ (m), a_it (a), b_it (b), r_it (r), fl_it (fl), l_it (l),
|
||
|
fu_it (fu), u_it (u), d_it (d), c_it (c), c_0 (c0)
|
||
|
{}
|
||
|
|
||
|
// access
|
||
|
int get_n() const {return n_;}
|
||
|
int get_m() const {return m_;}
|
||
|
A_iterator get_a() const {return a_it;}
|
||
|
B_iterator get_b() const {return b_it;}
|
||
|
R_iterator get_r() const {return r_it;}
|
||
|
FL_iterator get_fl() const {return fl_it;}
|
||
|
L_iterator get_l() const {return l_it;}
|
||
|
FU_iterator get_fu() const {return fu_it;}
|
||
|
U_iterator get_u() const {return u_it;}
|
||
|
D_iterator get_d() const {return d_it;}
|
||
|
C_iterator get_c() const {return c_it;}
|
||
|
C_entry get_c0() const {return c_0;}
|
||
|
};
|
||
|
|
||
|
// corresponding global function make_quadratic_program_from_iterators
|
||
|
// -------------------------------------------------------------------
|
||
|
template <
|
||
|
typename A_it, // for constraint matrix A (columnwise)
|
||
|
typename B_it, // for right-hand side b
|
||
|
typename R_it, // for relations (value type Comparison)
|
||
|
typename FL_it, // for finiteness of lower bounds (value type bool)
|
||
|
typename L_it, // for lower bounds
|
||
|
typename FU_it, // for finiteness of upper bounds (value type bool)
|
||
|
typename U_it, // for upper bounds
|
||
|
typename D_it, // for quadratic matrix D (rowwise)
|
||
|
typename C_it > // for objective function c
|
||
|
Quadratic_program_from_iterators<A_it, B_it, R_it, FL_it, L_it, FU_it, U_it, D_it, C_it>
|
||
|
make_quadratic_program_from_iterators (
|
||
|
int n, int m,
|
||
|
const A_it& a,
|
||
|
const B_it& b,
|
||
|
const R_it& r,
|
||
|
const FL_it& fl,
|
||
|
const L_it& l,
|
||
|
const FU_it& fu,
|
||
|
const U_it& u,
|
||
|
const D_it& d,
|
||
|
const C_it& c,
|
||
|
typename std::iterator_traits<C_it>::value_type c0 =
|
||
|
typename std::iterator_traits<C_it>::value_type(0))
|
||
|
{
|
||
|
return Quadratic_program_from_iterators
|
||
|
<A_it, B_it, R_it, FL_it, L_it, FU_it, U_it, D_it, C_it>
|
||
|
(n, m, a, b, r, fl, l, fu, u, d, c, c0);
|
||
|
}
|
||
|
|
||
|
|
||
|
// Linear_program_from_iterators
|
||
|
// -----------------------------
|
||
|
template <
|
||
|
typename A_it, // for constraint matrix A (columnwise)
|
||
|
typename B_it, // for right-hand side b
|
||
|
typename R_it, // for relations (value type Comparison)
|
||
|
typename FL_it, // for finiteness of lower bounds (value type bool)
|
||
|
typename L_it, // for lower bounds
|
||
|
typename FU_it, // for finiteness of upper bounds (value type bool)
|
||
|
typename U_it, // for upper bounds
|
||
|
typename C_it > // for objective function c
|
||
|
class Linear_program_from_iterators :
|
||
|
public Quadratic_program_from_iterators
|
||
|
<A_it, B_it, R_it, FL_it, L_it, FU_it, U_it,
|
||
|
typename QP_model_default_iterators<C_it>::It_2d, C_it>
|
||
|
{
|
||
|
private:
|
||
|
typedef Quadratic_program_from_iterators
|
||
|
<A_it, B_it, R_it, FL_it, L_it, FU_it, U_it,
|
||
|
typename QP_model_default_iterators<C_it>::It_2d, C_it> Base;
|
||
|
typedef typename QP_model_default_iterators<C_it>::It_2d Const_D_iterator;
|
||
|
public:
|
||
|
QP_MODEL_ITERATOR_TYPES;
|
||
|
Linear_program_from_iterators (
|
||
|
int n, int m, // number of variables / constraints
|
||
|
const A_iterator& a,
|
||
|
const B_iterator& b,
|
||
|
const R_iterator& r,
|
||
|
const FL_iterator& fl,
|
||
|
const L_iterator& l,
|
||
|
const FU_iterator& fu,
|
||
|
const U_iterator& u,
|
||
|
const C_iterator& c,
|
||
|
const C_entry& c0 = C_entry(0)
|
||
|
)
|
||
|
: Base (n, m, a, b, r, fl, l, fu, u,
|
||
|
Const_D_iterator(C_entry(0)), c, c0)
|
||
|
{}
|
||
|
};
|
||
|
|
||
|
// corresponding global function make_linear_program_from_iterators
|
||
|
// ----------------------------------------------------------------
|
||
|
template <
|
||
|
typename A_it, // for constraint matrix A (columnwise)
|
||
|
typename B_it, // for right-hand side b
|
||
|
typename R_it, // for relations (value type Comparison)
|
||
|
typename FL_it, // for finiteness of lower bounds (value type bool)
|
||
|
typename L_it, // for lower bounds
|
||
|
typename FU_it, // for finiteness of upper bounds (value type bool)
|
||
|
typename U_it, // for upper bounds
|
||
|
typename C_it > // for objective function c
|
||
|
Linear_program_from_iterators<A_it, B_it, R_it, FL_it, L_it, FU_it, U_it, C_it>
|
||
|
make_linear_program_from_iterators (
|
||
|
int n, int m,
|
||
|
const A_it& a,
|
||
|
const B_it& b,
|
||
|
const R_it& r,
|
||
|
const FL_it& fl,
|
||
|
const L_it& l,
|
||
|
const FU_it& fu,
|
||
|
const U_it& u,
|
||
|
const C_it& c,
|
||
|
typename std::iterator_traits<C_it>::value_type c0 =
|
||
|
typename std::iterator_traits<C_it>::value_type(0))
|
||
|
{
|
||
|
return Linear_program_from_iterators
|
||
|
<A_it, B_it, R_it, FL_it, L_it, FU_it, U_it, C_it>
|
||
|
(n, m, a, b, r, fl, l, fu, u, c, c0);
|
||
|
}
|
||
|
|
||
|
|
||
|
// Nonnegative_quadratic_program_from_iterators
|
||
|
// --------------------------------------------
|
||
|
template <
|
||
|
typename A_it, // for constraint matrix A (columnwise)
|
||
|
typename B_it, // for right-hand side b
|
||
|
typename R_it, // for relations (value type Comparison)
|
||
|
typename D_it, // for quadratic matrix D (rowwise)
|
||
|
typename C_it > // for objective function c
|
||
|
class Nonnegative_quadratic_program_from_iterators :
|
||
|
public Quadratic_program_from_iterators <A_it, B_it, R_it,
|
||
|
typename QP_model_default_iterators<bool*>::It_1d,
|
||
|
typename QP_model_default_iterators<C_it>::It_1d,
|
||
|
typename QP_model_default_iterators<bool*>::It_1d,
|
||
|
typename QP_model_default_iterators<C_it>::It_1d,
|
||
|
D_it, C_it>
|
||
|
{
|
||
|
private:
|
||
|
typedef Quadratic_program_from_iterators <A_it, B_it, R_it,
|
||
|
typename QP_model_default_iterators<bool*>::It_1d,
|
||
|
typename QP_model_default_iterators<C_it>::It_1d,
|
||
|
typename QP_model_default_iterators<bool*>::It_1d,
|
||
|
typename QP_model_default_iterators<C_it>::It_1d,
|
||
|
D_it, C_it> Base;
|
||
|
typedef typename QP_model_default_iterators<bool*>::It_1d Const_FLU_iterator;
|
||
|
typedef typename QP_model_default_iterators<C_it>::It_1d Const_LU_iterator;
|
||
|
public:
|
||
|
QP_MODEL_ITERATOR_TYPES;
|
||
|
Nonnegative_quadratic_program_from_iterators (
|
||
|
int n, int m, // number of variables / constraints
|
||
|
const A_iterator& a,
|
||
|
const B_iterator& b,
|
||
|
const R_iterator& r,
|
||
|
const D_iterator& d,
|
||
|
const C_iterator& c,
|
||
|
const C_entry& c0 = C_entry(0)
|
||
|
)
|
||
|
: Base (n, m, a, b, r,
|
||
|
Const_FLU_iterator(true), Const_LU_iterator(C_entry(0)),
|
||
|
Const_FLU_iterator(false), Const_LU_iterator(C_entry(0)),
|
||
|
d, c, c0)
|
||
|
{}
|
||
|
};
|
||
|
|
||
|
// corresponding global function
|
||
|
// make_nonnegative_quadratic_program_from_iterators
|
||
|
// -------------------------------------------------
|
||
|
template <
|
||
|
typename A_it, // for constraint matrix A (columnwise)
|
||
|
typename B_it, // for right-hand side b
|
||
|
typename R_it, // for relations (value type Comparison)
|
||
|
typename D_it, // for quadratic matrix D (rowwise)
|
||
|
typename C_it > // for objective function c
|
||
|
Nonnegative_quadratic_program_from_iterators
|
||
|
<A_it, B_it, R_it, D_it, C_it>
|
||
|
make_nonnegative_quadratic_program_from_iterators (
|
||
|
int n, int m,
|
||
|
const A_it& a,
|
||
|
const B_it& b,
|
||
|
const R_it& r,
|
||
|
const D_it& d,
|
||
|
const C_it& c,
|
||
|
typename std::iterator_traits<C_it>::value_type c0 =
|
||
|
typename std::iterator_traits<C_it>::value_type(0))
|
||
|
{
|
||
|
return Nonnegative_quadratic_program_from_iterators
|
||
|
<A_it, B_it, R_it, D_it, C_it>
|
||
|
(n, m, a, b, r, d, c, c0);
|
||
|
}
|
||
|
|
||
|
|
||
|
// Nonnegative_linear_program_from_iterators
|
||
|
// -----------------------------------------
|
||
|
template <
|
||
|
typename A_it, // for constraint matrix A (columnwise)
|
||
|
typename B_it, // for right-hand side b
|
||
|
typename R_it, // for relations (value type Comparison)
|
||
|
typename C_it > // for objective function c
|
||
|
class Nonnegative_linear_program_from_iterators :
|
||
|
public Quadratic_program_from_iterators <A_it, B_it, R_it,
|
||
|
typename QP_model_default_iterators<bool*>::It_1d,
|
||
|
typename QP_model_default_iterators<C_it>::It_1d,
|
||
|
typename QP_model_default_iterators<bool*>::It_1d,
|
||
|
typename QP_model_default_iterators<C_it>::It_1d,
|
||
|
typename QP_model_default_iterators<C_it>::It_2d, C_it>
|
||
|
{
|
||
|
private:
|
||
|
typedef Quadratic_program_from_iterators <A_it, B_it, R_it,
|
||
|
typename QP_model_default_iterators<bool*>::It_1d,
|
||
|
typename QP_model_default_iterators<C_it>::It_1d,
|
||
|
typename QP_model_default_iterators<bool*>::It_1d,
|
||
|
typename QP_model_default_iterators<C_it>::It_1d,
|
||
|
typename QP_model_default_iterators<C_it>::It_2d, C_it> Base;
|
||
|
typedef typename QP_model_default_iterators<bool*>::It_1d Const_FLU_iterator;
|
||
|
typedef typename QP_model_default_iterators<C_it>::It_1d Const_LU_iterator;
|
||
|
typedef typename QP_model_default_iterators<C_it>::It_2d Const_D_iterator;
|
||
|
public:
|
||
|
QP_MODEL_ITERATOR_TYPES;
|
||
|
Nonnegative_linear_program_from_iterators (
|
||
|
int n, int m, // number of variables / constraints
|
||
|
const A_iterator& a,
|
||
|
const B_iterator& b,
|
||
|
const R_iterator& r,
|
||
|
const C_iterator& c,
|
||
|
const C_entry& c0 = C_entry(0)
|
||
|
)
|
||
|
: Base (n, m, a, b, r,
|
||
|
Const_FLU_iterator(true), Const_LU_iterator(C_entry(0)),
|
||
|
Const_FLU_iterator(false), Const_LU_iterator(C_entry(0)),
|
||
|
Const_D_iterator(C_entry(0)), c, c0)
|
||
|
{}
|
||
|
};
|
||
|
|
||
|
// corresponding global function
|
||
|
// make_nonnegative_linear_program_from_iterators
|
||
|
// ----------------------------------------------
|
||
|
template <
|
||
|
typename A_it, // for constraint matrix A (columnwise)
|
||
|
typename B_it, // for right-hand side b
|
||
|
typename R_it, // for relations (value type Comparison)
|
||
|
typename C_it > // for objective function c
|
||
|
Nonnegative_linear_program_from_iterators
|
||
|
<A_it, B_it, R_it, C_it>
|
||
|
make_nonnegative_linear_program_from_iterators (
|
||
|
int n, int m,
|
||
|
const A_it& a,
|
||
|
const B_it& b,
|
||
|
const R_it& r,
|
||
|
const C_it& c,
|
||
|
typename std::iterator_traits<C_it>::value_type c0 =
|
||
|
typename std::iterator_traits<C_it>::value_type(0))
|
||
|
{
|
||
|
return Nonnegative_linear_program_from_iterators
|
||
|
<A_it, B_it, R_it, C_it>
|
||
|
(n, m, a, b, r, c, c0);
|
||
|
}
|
||
|
|
||
|
|
||
|
namespace QP_model_detail {
|
||
|
// maps a container to its begin-iterator, as specified by HowToBegin
|
||
|
template<typename Container, typename Iterator, typename HowToBegin>
|
||
|
struct Begin
|
||
|
: public CGAL::cpp98::unary_function< Container, Iterator >
|
||
|
{
|
||
|
typedef Iterator result_type;
|
||
|
result_type operator () ( const Container& v) const
|
||
|
{
|
||
|
return HowToBegin()(v);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
// Quadratic_program
|
||
|
// -----------------
|
||
|
// sparse representation, entries can be set one by one, overriding
|
||
|
// defaults;
|
||
|
template <typename NT_>
|
||
|
class Quadratic_program
|
||
|
{
|
||
|
public:
|
||
|
typedef NT_ NT;
|
||
|
private:
|
||
|
// Sparse_vectors
|
||
|
typedef std::map<std::size_t, NT>
|
||
|
Sparse_vector;
|
||
|
typedef std::map<std::size_t, CGAL::Comparison_result>
|
||
|
Sparse_r_vector;
|
||
|
typedef std::map<std::size_t, bool>
|
||
|
Sparse_f_vector;
|
||
|
|
||
|
// Sparse_matrix
|
||
|
typedef std::vector<Sparse_vector>
|
||
|
Sparse_matrix;
|
||
|
|
||
|
// Sparse_vector_iterators
|
||
|
//typedef CGAL::Fake_random_access_const_iterator<Sparse_vector>
|
||
|
typedef boost::transform_iterator<CGAL::Map_with_default<Sparse_vector>,
|
||
|
boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t> >
|
||
|
Sparse_vector_iterator;
|
||
|
typedef boost::transform_iterator<CGAL::Map_with_default<Sparse_r_vector>,
|
||
|
boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t> >
|
||
|
Sparse_r_vector_iterator;
|
||
|
typedef boost::transform_iterator<CGAL::Map_with_default<Sparse_f_vector>,
|
||
|
boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t> >
|
||
|
Sparse_f_vector_iterator;
|
||
|
|
||
|
// Sparse_matrix_iterator
|
||
|
struct HowToBegin
|
||
|
{
|
||
|
Sparse_vector_iterator operator() (const Sparse_vector& v) const
|
||
|
{ return Sparse_vector_iterator
|
||
|
(boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t>(0),
|
||
|
CGAL::Map_with_default<Sparse_vector>(&v, NT(0)));}
|
||
|
};
|
||
|
|
||
|
typedef QP_model_detail::Begin
|
||
|
<Sparse_vector, Sparse_vector_iterator, HowToBegin> Beginner;
|
||
|
typedef boost::transform_iterator
|
||
|
<Beginner, typename Sparse_matrix::const_iterator>
|
||
|
Sparse_matrix_iterator;
|
||
|
|
||
|
// program data; we maintain the invariant that only the
|
||
|
// non-default elements are stored; this means that entries
|
||
|
// may get removed again, and n_, m_ might be larger than
|
||
|
// absolutely needed; we also maintain the invariants that
|
||
|
// a_matrix and d_matrix always have n_ elements
|
||
|
|
||
|
int n_;
|
||
|
int m_;
|
||
|
Sparse_matrix a_matrix;
|
||
|
Sparse_vector b_vector;
|
||
|
Sparse_r_vector r_vector;
|
||
|
Sparse_f_vector fl_vector;
|
||
|
Sparse_vector l_vector;
|
||
|
Sparse_f_vector fu_vector;
|
||
|
Sparse_vector u_vector;
|
||
|
Sparse_vector c_vector;
|
||
|
Sparse_matrix d_matrix;
|
||
|
NT c0_;
|
||
|
|
||
|
// default settings
|
||
|
CGAL::Comparison_result default_r; // from constructor
|
||
|
bool default_fl; // from constructor
|
||
|
NT default_l; // from constructor
|
||
|
bool default_fu; // from constructor
|
||
|
NT default_u; // from constructor
|
||
|
protected:
|
||
|
bool is_valid_;
|
||
|
private:
|
||
|
std::string error_msg;
|
||
|
|
||
|
// methods
|
||
|
// enlarges a_matrix, d_matrix to size s, under the
|
||
|
// precondition that the previous sizes were smaller
|
||
|
void grow_a_d (int s)
|
||
|
{
|
||
|
CGAL_qpe_assertion( a_matrix.size() == d_matrix.size() );
|
||
|
CGAL_qpe_assertion( a_matrix.size() < static_cast<unsigned int>(s));
|
||
|
for (int k = static_cast<int>(a_matrix.size()); k < s; ++k) {
|
||
|
a_matrix.push_back(Sparse_vector());
|
||
|
d_matrix.push_back(Sparse_vector());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
// interface types
|
||
|
typedef Sparse_matrix_iterator A_iterator;
|
||
|
typedef Sparse_vector_iterator B_iterator;
|
||
|
typedef Sparse_r_vector_iterator R_iterator;
|
||
|
typedef Sparse_f_vector_iterator FL_iterator;
|
||
|
typedef Sparse_vector_iterator L_iterator;
|
||
|
typedef Sparse_f_vector_iterator FU_iterator;
|
||
|
typedef Sparse_vector_iterator U_iterator;
|
||
|
typedef Sparse_vector_iterator C_iterator;
|
||
|
typedef Sparse_matrix_iterator D_iterator;
|
||
|
typedef NT C_entry;
|
||
|
|
||
|
// concept methods
|
||
|
int get_n() const
|
||
|
{
|
||
|
CGAL_qpe_assertion(is_valid());
|
||
|
return n_;
|
||
|
}
|
||
|
int get_m() const
|
||
|
{
|
||
|
CGAL_qpe_assertion(is_valid());
|
||
|
return m_;
|
||
|
}
|
||
|
A_iterator get_a() const
|
||
|
{
|
||
|
CGAL_qpe_assertion(is_valid());
|
||
|
return A_iterator (a_matrix.begin(), Beginner());
|
||
|
}
|
||
|
B_iterator get_b() const
|
||
|
{
|
||
|
CGAL_qpe_assertion(is_valid());
|
||
|
return B_iterator (boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t>(0),
|
||
|
CGAL::Map_with_default<Sparse_vector>
|
||
|
(&b_vector, NT(0)));
|
||
|
}
|
||
|
R_iterator get_r() const
|
||
|
{
|
||
|
CGAL_qpe_assertion(is_valid());
|
||
|
return R_iterator (boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t>(0),
|
||
|
CGAL::Map_with_default<Sparse_r_vector>
|
||
|
(&r_vector, default_r));
|
||
|
}
|
||
|
FL_iterator get_fl() const
|
||
|
{
|
||
|
CGAL_qpe_assertion(is_valid());
|
||
|
return FL_iterator (boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t>(0),
|
||
|
CGAL::Map_with_default<Sparse_f_vector>
|
||
|
(&fl_vector, default_fl));
|
||
|
}
|
||
|
L_iterator get_l() const
|
||
|
{
|
||
|
CGAL_qpe_assertion(is_valid());
|
||
|
return L_iterator (boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t>(0),
|
||
|
CGAL::Map_with_default<Sparse_vector>
|
||
|
(&l_vector, default_l));
|
||
|
}
|
||
|
FU_iterator get_fu() const
|
||
|
{
|
||
|
CGAL_qpe_assertion(is_valid());
|
||
|
return FU_iterator (boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t>(0),
|
||
|
CGAL::Map_with_default<Sparse_f_vector>
|
||
|
(&fu_vector, default_fu));
|
||
|
}
|
||
|
U_iterator get_u() const
|
||
|
{
|
||
|
CGAL_qpe_assertion(is_valid());
|
||
|
return U_iterator (boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t>(0),
|
||
|
CGAL::Map_with_default<Sparse_vector>
|
||
|
(&u_vector, default_u));
|
||
|
}
|
||
|
C_iterator get_c() const
|
||
|
{
|
||
|
CGAL_qpe_assertion(is_valid());
|
||
|
return C_iterator (boost::counting_iterator<std::size_t,boost::use_default,std::ptrdiff_t>(0),
|
||
|
CGAL::Map_with_default<Sparse_vector>
|
||
|
(&c_vector, NT(0)));
|
||
|
}
|
||
|
D_iterator get_d() const
|
||
|
{
|
||
|
CGAL_qpe_assertion(is_valid());
|
||
|
return D_iterator (d_matrix.begin(), Beginner());
|
||
|
}
|
||
|
C_entry get_c0() const
|
||
|
{
|
||
|
CGAL_qpe_assertion(is_valid());
|
||
|
return c0_;
|
||
|
}
|
||
|
|
||
|
bool is_valid() const
|
||
|
{
|
||
|
return is_valid_;
|
||
|
}
|
||
|
|
||
|
const std::string& get_error() const
|
||
|
{
|
||
|
CGAL_qpe_assertion(!is_valid());
|
||
|
return error_msg;
|
||
|
}
|
||
|
|
||
|
// default constructor
|
||
|
Quadratic_program
|
||
|
(CGAL::Comparison_result relation = CGAL::EQUAL,
|
||
|
bool finite_lower = true,
|
||
|
NT lower = 0,
|
||
|
bool finite_upper = false,
|
||
|
NT upper = 0)
|
||
|
: n_(0), m_(0), c0_(0),
|
||
|
default_r(relation), default_fl(finite_lower),
|
||
|
default_l(lower), default_fu(finite_upper),
|
||
|
default_u(upper), is_valid_(true)
|
||
|
{
|
||
|
CGAL_qpe_assertion(!finite_lower || !finite_upper || lower <= upper);
|
||
|
}
|
||
|
|
||
|
|
||
|
// constructor from iterators
|
||
|
template <typename A_it, typename B_it, typename R_it, typename FL_it,
|
||
|
typename L_it, typename FU_it, typename U_it, typename D_it,
|
||
|
typename C_it>
|
||
|
Quadratic_program
|
||
|
(
|
||
|
int n, int m, // number of variables / constraints
|
||
|
const A_it& a,
|
||
|
const B_it& b,
|
||
|
const R_it& r,
|
||
|
const FL_it& fl,
|
||
|
const L_it& l,
|
||
|
const FU_it& fu,
|
||
|
const U_it& u,
|
||
|
const D_it& d,
|
||
|
const C_it& c,
|
||
|
const typename std::iterator_traits<C_it>::value_type& c0 = 0)
|
||
|
: n_(0), m_(0), c0_(0),
|
||
|
default_r(CGAL::EQUAL), default_fl(true),
|
||
|
default_l(0), default_fu(false), default_u(0), is_valid_(true)
|
||
|
{
|
||
|
// now copy, using the set methods
|
||
|
for (int j=0; j<n; ++j) {
|
||
|
for (int i=0; i<m; ++i)
|
||
|
set_a (j, i, (*(a+j))[i]);
|
||
|
set_l (j, *(fl+j), *(l+j));
|
||
|
set_u (j, *(fu+j), *(u+j));
|
||
|
set_c (j, *(c+j));
|
||
|
}
|
||
|
for (int i=0; i<m; ++i) {
|
||
|
set_b (i, *(b+i));
|
||
|
set_r (i, *(r+i));
|
||
|
}
|
||
|
for (int i=0; i<n; ++i)
|
||
|
for (int j=0; j<=i; ++j)
|
||
|
set_d (i, j, (*(d+i))[j]);
|
||
|
set_c0 (c0);
|
||
|
}
|
||
|
|
||
|
// type of problem
|
||
|
bool is_linear() const
|
||
|
{
|
||
|
CGAL_qpe_assertion(d_matrix.size() == (unsigned int)(n_));
|
||
|
for (int i=0; i<n_; ++i)
|
||
|
if (!d_matrix[i].empty()) return false;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
// helpers to determine bound status
|
||
|
// checks whether all bounds in flu are as given by the parameter "finite"
|
||
|
// default_flu is the default-value of the underlying map that is not
|
||
|
// stored
|
||
|
bool all_bounds_are
|
||
|
(bool finite, const Sparse_f_vector& flu, bool default_flu) const
|
||
|
{
|
||
|
if (finite == default_flu)
|
||
|
return flu.empty();
|
||
|
else
|
||
|
// are there exactly n non-default values "finite"?
|
||
|
return flu.size() == (unsigned int)(n_);
|
||
|
}
|
||
|
|
||
|
bool all_bounds_are_zero
|
||
|
// checks whether all bounds in lu are 0. default_lu is the default-value
|
||
|
// of the underlying map that is not stored
|
||
|
(const Sparse_vector& lu, const NT& default_lu) const
|
||
|
{
|
||
|
if (CGAL::is_zero(default_lu))
|
||
|
return lu.empty();
|
||
|
else {
|
||
|
// are there exactly n non-default values?
|
||
|
if (lu.size() != (unsigned int)(n_)) return false;
|
||
|
// ok, we have to test each of the non-default values against zero
|
||
|
for (typename Sparse_vector::const_iterator
|
||
|
j = lu.begin(); j != lu.end(); ++j)
|
||
|
if (!CGAL::is_zero(j->second)) return false;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
|
||
|
bool is_nonnegative() const
|
||
|
{
|
||
|
return
|
||
|
all_bounds_are (true, fl_vector, default_fl) &&
|
||
|
all_bounds_are_zero (l_vector, default_l) &&
|
||
|
all_bounds_are (false, fu_vector, default_fu);
|
||
|
}
|
||
|
|
||
|
bool is_nonpositive() const
|
||
|
{
|
||
|
return
|
||
|
all_bounds_are (false, fl_vector, default_fl) &&
|
||
|
all_bounds_are_zero (u_vector, default_u) &&
|
||
|
all_bounds_are (true, fu_vector, default_fu);
|
||
|
}
|
||
|
|
||
|
bool is_free() const
|
||
|
{
|
||
|
return
|
||
|
all_bounds_are (false, fl_vector, default_fl) &&
|
||
|
all_bounds_are (false, fu_vector, default_fu);
|
||
|
}
|
||
|
|
||
|
// set methods
|
||
|
void set_a (int j, int i, const NT& val)
|
||
|
{
|
||
|
CGAL_qpe_assertion (j >= 0);
|
||
|
CGAL_qpe_assertion (i >= 0);
|
||
|
if (j >= n_) {
|
||
|
n_ = j+1;
|
||
|
grow_a_d(n_);
|
||
|
}
|
||
|
if (i >= m_) m_ = i+1;
|
||
|
if (CGAL::is_zero(val))
|
||
|
a_matrix[j].erase(i);
|
||
|
else
|
||
|
a_matrix[j][i] = val;
|
||
|
}
|
||
|
|
||
|
void set_b (int i, const NT& val)
|
||
|
{
|
||
|
CGAL_qpe_assertion (i >= 0);
|
||
|
if (i >= m_) m_ = i+1;
|
||
|
if (CGAL::is_zero(val))
|
||
|
b_vector.erase(i);
|
||
|
else
|
||
|
b_vector[i] = val;
|
||
|
}
|
||
|
|
||
|
void set_r (int i, CGAL::Comparison_result val)
|
||
|
{
|
||
|
CGAL_qpe_assertion (i >= 0);
|
||
|
if (i >= m_) m_ = i+1;
|
||
|
if (val == default_r)
|
||
|
r_vector.erase(i);
|
||
|
else
|
||
|
r_vector[i] = val;
|
||
|
}
|
||
|
|
||
|
void set_l (int j, bool is_finite, const NT& val = NT(0))
|
||
|
{
|
||
|
CGAL_qpe_assertion (j >= 0);
|
||
|
if (j >= n_) {
|
||
|
n_ = j+1;
|
||
|
grow_a_d(n_);
|
||
|
}
|
||
|
if (is_finite == default_fl)
|
||
|
fl_vector.erase(j);
|
||
|
else
|
||
|
fl_vector[j] = is_finite;
|
||
|
if (val == default_l)
|
||
|
l_vector.erase(j);
|
||
|
else
|
||
|
l_vector[j] = val;
|
||
|
}
|
||
|
|
||
|
void set_u (int j, bool is_finite, const NT& val = NT(0))
|
||
|
{
|
||
|
CGAL_qpe_assertion (j >= 0);
|
||
|
if (j >= n_) {
|
||
|
n_ = j+1;
|
||
|
grow_a_d(n_);
|
||
|
}
|
||
|
if (is_finite == default_fu)
|
||
|
fu_vector.erase(j);
|
||
|
else
|
||
|
fu_vector[j] = is_finite;
|
||
|
if (val == default_u)
|
||
|
u_vector.erase(j);
|
||
|
else
|
||
|
u_vector[j] = val;
|
||
|
}
|
||
|
|
||
|
void set_c (int j, const NT& val)
|
||
|
{
|
||
|
CGAL_qpe_assertion (j >= 0);
|
||
|
if (j >= n_) {
|
||
|
n_ = j+1;
|
||
|
grow_a_d(n_);
|
||
|
}
|
||
|
if (CGAL::is_zero(val))
|
||
|
c_vector.erase(j);
|
||
|
else
|
||
|
c_vector[j] = val;
|
||
|
}
|
||
|
|
||
|
void set_c0 (const NT& val)
|
||
|
{
|
||
|
c0_ = val;
|
||
|
}
|
||
|
|
||
|
void set_d (int i, int j, const NT& val)
|
||
|
{
|
||
|
CGAL_qpe_assertion (i >= 0);
|
||
|
CGAL_qpe_assertion (j >= 0);
|
||
|
CGAL_qpe_assertion (j <= i); // lower-diagonal entry
|
||
|
if (i >= n_) {
|
||
|
n_ = i+1;
|
||
|
grow_a_d(n_);
|
||
|
}
|
||
|
if (CGAL::is_zero(val))
|
||
|
d_matrix[i].erase(j);
|
||
|
else
|
||
|
d_matrix[i][j] = val;
|
||
|
}
|
||
|
|
||
|
protected:
|
||
|
// helpers for errors/warnings
|
||
|
std::string replace1
|
||
|
(const std::string& msg,const std::string& replacement) const
|
||
|
{
|
||
|
std::string result(msg);
|
||
|
const std::string::size_type pos = result.find('%');
|
||
|
CGAL_qpe_assertion(pos < result.size());
|
||
|
result.replace(pos,1,replacement);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
bool err(const char* msg) {
|
||
|
error_msg = msg;
|
||
|
is_valid_ = false;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool err1(const char* msg,
|
||
|
const std::string& parameter1) {
|
||
|
error_msg = replace1(msg,parameter1);
|
||
|
is_valid_ = false;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool err2(const char* msg,
|
||
|
const std::string& parameter1,
|
||
|
const std::string& parameter2) {
|
||
|
error_msg = replace1(replace1(msg,parameter1),parameter2);
|
||
|
is_valid_ = false;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool err3(const char* msg,
|
||
|
const std::string& parameter1,
|
||
|
const std::string& parameter2,
|
||
|
const std::string& parameter3) {
|
||
|
error_msg =
|
||
|
replace1(replace1(replace1(msg,parameter1),parameter2),parameter3);
|
||
|
is_valid_ = false;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void warn(const std::string& msg) const {
|
||
|
std::cerr << "Warning: " << msg << '.' << std::endl;
|
||
|
}
|
||
|
|
||
|
void warn1(const std::string& msg,const std::string& parameter1) const {
|
||
|
warn(replace1(msg,parameter1));
|
||
|
}
|
||
|
|
||
|
|
||
|
};
|
||
|
|
||
|
// Quadratic_program_from_mps
|
||
|
// --------------------------
|
||
|
// for reading a QP from a stream in MPS format
|
||
|
|
||
|
template <typename NT_>
|
||
|
class Quadratic_program_from_mps :
|
||
|
public Quadratic_program<NT_>
|
||
|
{
|
||
|
public:
|
||
|
typedef NT_ NT;
|
||
|
private:
|
||
|
typedef Quadratic_program<NT> Base;
|
||
|
public:
|
||
|
QP_MODEL_ITERATOR_TYPES;
|
||
|
private:
|
||
|
// types
|
||
|
typedef std::map<std::string,unsigned int> Index_map;
|
||
|
typedef std::pair<std::string,unsigned int> String_int_pair;
|
||
|
public:
|
||
|
// constructor
|
||
|
Quadratic_program_from_mps
|
||
|
(std::istream& in)
|
||
|
: Base(), from(in), nt0(0), use_put_back_token(false)
|
||
|
{
|
||
|
// read NAME section:
|
||
|
if (!name_section())
|
||
|
return;
|
||
|
|
||
|
// read ROWS section:
|
||
|
if (!rows_section())
|
||
|
return;
|
||
|
|
||
|
// read COLUMNS section:
|
||
|
if (!columns_section())
|
||
|
return;
|
||
|
|
||
|
// read RHS section:
|
||
|
if (!rhs_section())
|
||
|
return;
|
||
|
|
||
|
// check for (optional) RANGES section:
|
||
|
if (!ranges_section())
|
||
|
return;
|
||
|
|
||
|
// read optional BOUNDS section:
|
||
|
if (!bounds_section())
|
||
|
return;
|
||
|
|
||
|
// read optional QMATRIX section:
|
||
|
if (!qmatrix_section())
|
||
|
return;
|
||
|
|
||
|
// check for ENDATA:
|
||
|
const std::string end = token();
|
||
|
if (end != "ENDATA") {
|
||
|
this->err1("ENDDATA expected but found '%'",end);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// remember the number of variables/constraint that we have now
|
||
|
n_after_construction = this->get_n();
|
||
|
m_after_construction = this->get_m();
|
||
|
}
|
||
|
|
||
|
// returns the first comment that was read from the MPS stream
|
||
|
const std::string& get_comment() const
|
||
|
{
|
||
|
return comment_;
|
||
|
}
|
||
|
|
||
|
// returns name of the problem
|
||
|
const std::string& get_problem_name() const
|
||
|
{
|
||
|
return name;
|
||
|
}
|
||
|
|
||
|
const std::string& variable_name_by_index(int j) const
|
||
|
{
|
||
|
CGAL_qpe_assertion(this->is_valid());
|
||
|
CGAL_qpe_assertion(0<=j && j<n_after_construction);
|
||
|
return var_by_index[j];
|
||
|
}
|
||
|
|
||
|
int variable_index_by_name (const std::string& name) const
|
||
|
{
|
||
|
const Index_map::const_iterator var_name = var_names.find(name);
|
||
|
if (var_name == var_names.end()) // unknown variable
|
||
|
return -1;
|
||
|
else
|
||
|
return var_name->second;
|
||
|
}
|
||
|
|
||
|
const std::string& constraint_name_by_index(int i) const
|
||
|
{
|
||
|
CGAL_qpe_assertion(this->is_valid());
|
||
|
CGAL_qpe_assertion(0<=i && i<m_after_construction);
|
||
|
return row_by_index[i];
|
||
|
}
|
||
|
|
||
|
int constraint_index_by_name (const std::string& name) const
|
||
|
{
|
||
|
const Index_map::const_iterator row_name = row_names.find(name);
|
||
|
if (row_name == row_names.end()) // unknown constraint
|
||
|
return -1;
|
||
|
else
|
||
|
return row_name->second;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
// data
|
||
|
// ----
|
||
|
std::istream& from; // input stream
|
||
|
NT nt0;
|
||
|
|
||
|
std::string D_section; // name of the section from which D was read
|
||
|
std::string name; // name of the problem
|
||
|
std::string comment_; // first comment in the input, if any
|
||
|
std::string obj; // name of the objective "constraint"
|
||
|
int n_after_construction;
|
||
|
int m_after_construction;
|
||
|
|
||
|
Index_map row_names;
|
||
|
Index_map duplicated_row_names; // to handle RANGES section
|
||
|
Index_map var_names;
|
||
|
std::vector<std::string> var_by_index; // name of i-th column
|
||
|
std::vector<std::string> row_by_index; // name of i-th row
|
||
|
|
||
|
// variables used in token() (see below):
|
||
|
bool use_put_back_token;
|
||
|
std::string put_back_token;
|
||
|
|
||
|
// parsing routines
|
||
|
// (Note: returns true iff a line-break was eaten.)
|
||
|
bool whitespace()
|
||
|
{
|
||
|
// support for put_token_back():
|
||
|
if (use_put_back_token)
|
||
|
return false;
|
||
|
bool lineBreakFound = false;
|
||
|
|
||
|
char c;
|
||
|
bool in_comment = false; // true iff we are within a comment
|
||
|
const bool remember_comment = comment_.size() == 0;
|
||
|
while (from.get(c))
|
||
|
if (in_comment) {
|
||
|
if (c!='\r' && c!='\n') {
|
||
|
if (remember_comment)
|
||
|
comment_.push_back(c);
|
||
|
} else
|
||
|
in_comment = false;
|
||
|
} else { // not in comment?
|
||
|
if (!isspace(c)) {
|
||
|
if (c!='$' && c!='*') {
|
||
|
from.putback(c);
|
||
|
break;
|
||
|
}
|
||
|
in_comment = true;
|
||
|
lineBreakFound = true;
|
||
|
} else {
|
||
|
if (c=='\r' || c=='\n')
|
||
|
lineBreakFound = true;
|
||
|
}
|
||
|
}
|
||
|
return lineBreakFound;
|
||
|
}
|
||
|
|
||
|
std::string token() {
|
||
|
if (use_put_back_token) {
|
||
|
use_put_back_token = false;
|
||
|
return put_back_token;
|
||
|
}
|
||
|
whitespace();
|
||
|
std::string token;
|
||
|
char c;
|
||
|
while (from.get(c)) {
|
||
|
if (isspace(c)) {
|
||
|
from.putback(c);
|
||
|
break;
|
||
|
}
|
||
|
token.push_back(c);
|
||
|
}
|
||
|
return token;
|
||
|
}
|
||
|
|
||
|
void put_token_back(const std::string& token) {
|
||
|
CGAL_qpe_assertion(!use_put_back_token);
|
||
|
use_put_back_token = true;
|
||
|
put_back_token = token;
|
||
|
}
|
||
|
|
||
|
template<typename NumberType>
|
||
|
bool number(NumberType& entry) {
|
||
|
// whitespace(); the following >> should care for this
|
||
|
from >> CGAL::iformat(entry);
|
||
|
return from.good();
|
||
|
}
|
||
|
|
||
|
bool name_section()
|
||
|
{
|
||
|
const std::string t = token();
|
||
|
if (t != "NAME")
|
||
|
return this->err("expected 'NAME'");
|
||
|
// NAME: everything found until line break; whitespaces are allowed
|
||
|
char c;
|
||
|
std::string token;
|
||
|
std::string whitespaces;
|
||
|
if (whitespace())
|
||
|
// line break eaten, name is empty
|
||
|
return true;
|
||
|
do {
|
||
|
from.get(c);
|
||
|
if (c == '\r' || c == '\n') break;
|
||
|
if (isspace(c))
|
||
|
whitespaces.push_back(c); // save whitespace
|
||
|
else {
|
||
|
// new actual character found: previous whitespaces belong to name
|
||
|
name += whitespaces;
|
||
|
whitespaces.clear();
|
||
|
name.push_back(c);
|
||
|
}
|
||
|
} while (true);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool rows_section()
|
||
|
{
|
||
|
std::string t = token();
|
||
|
if (t != "ROWS")
|
||
|
return this->err1("expected 'ROWS' but found '%'",t);
|
||
|
|
||
|
// read 'N', 'G', 'L', or 'E', and the name of the constraint:
|
||
|
t = token();
|
||
|
int i = 0; // row index
|
||
|
while (t != "COLUMNS") {
|
||
|
const char type = t[0];
|
||
|
const std::string symbol(t); // for error message below
|
||
|
t = token();
|
||
|
switch (type) {
|
||
|
case 'N':
|
||
|
// register name of objective row:
|
||
|
if (obj.size() == 0) // remember first (and ignore others)
|
||
|
obj = t;
|
||
|
break;
|
||
|
case 'G':
|
||
|
case 'L':
|
||
|
case 'E':
|
||
|
{
|
||
|
// register name of >=, <=, or = constraint:
|
||
|
this->set_r (i,
|
||
|
type == 'G'? CGAL::LARGER :
|
||
|
(type == 'E'? CGAL::EQUAL : CGAL::SMALLER));
|
||
|
if (row_names.find(t) != row_names.end())
|
||
|
return this->err1("duplicate row name '%' in section ROWS",t);
|
||
|
row_names.insert(String_int_pair(t,i));
|
||
|
row_by_index.push_back(t);
|
||
|
++i;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
return
|
||
|
this->err1
|
||
|
("expected 'N', 'L', 'E', or 'G' in ROWS section but found '%'",
|
||
|
symbol);
|
||
|
}
|
||
|
t = token();
|
||
|
}
|
||
|
put_token_back(t);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool columns_section()
|
||
|
{
|
||
|
std::string t = token();
|
||
|
if (t != "COLUMNS")
|
||
|
return this->err1("expected 'COLUMNS' but found '%'",t);
|
||
|
|
||
|
t = token();
|
||
|
while (t != "RHS") {
|
||
|
// find variable name:
|
||
|
unsigned int var_index;
|
||
|
std::string col_name;
|
||
|
const Index_map::const_iterator var_name = var_names.find(t);
|
||
|
if (var_name == var_names.end()) { // new variable?
|
||
|
var_index = static_cast<unsigned int>(var_names.size());
|
||
|
col_name = t;
|
||
|
var_names.insert(String_int_pair(t,var_index));
|
||
|
var_by_index.push_back(t);
|
||
|
} else { // variable that is already known?
|
||
|
var_index = var_name->second;
|
||
|
col_name = var_name->first;
|
||
|
}
|
||
|
|
||
|
bool doItAgain = true;
|
||
|
for (int i=0; doItAgain; ++i) {
|
||
|
// read row identifier:
|
||
|
t = token();
|
||
|
|
||
|
// read number:
|
||
|
NT val;
|
||
|
if (!number(val))
|
||
|
return this->err2
|
||
|
("number expected after row identifier '%' in '%' COLUMNS record",
|
||
|
t,col_name);
|
||
|
|
||
|
// store number:
|
||
|
if (t == obj) { // objective row?
|
||
|
this->set_c(var_index, val);
|
||
|
} else { // not objective row?
|
||
|
const Index_map::const_iterator row_name = row_names.find(t);
|
||
|
if (row_name == row_names.end())
|
||
|
return this->err1
|
||
|
("unknown row identifier '%' in section COLUMNS",t);
|
||
|
this->set_a (var_index, row_name->second, val);
|
||
|
}
|
||
|
|
||
|
// determine if we need to read another number:
|
||
|
doItAgain = i==0 && !whitespace();
|
||
|
}
|
||
|
|
||
|
// read next token:
|
||
|
t = token();
|
||
|
}
|
||
|
put_token_back(t);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool rhs_section()
|
||
|
{
|
||
|
this->set_c0 (nt0); // no constant term yet
|
||
|
std::string t = token();
|
||
|
if (t != "RHS")
|
||
|
return this->err1("expected 'RHS' but found '%'",t);
|
||
|
|
||
|
t = token();
|
||
|
std::string rhs_id;
|
||
|
while (t != "RANGES" && t != "BOUNDS" &&
|
||
|
t != "DMATRIX" && t != "QMATRIX" && t != "QUADOBJ" &&
|
||
|
t != "ENDATA") {
|
||
|
// read rhs identifier and if it is different from the one
|
||
|
// from the previous iteration, ignore the whole row:
|
||
|
bool ignore = false;
|
||
|
std::string ignored;
|
||
|
if (rhs_id.size() == 0) { // first time we enter the loop?
|
||
|
rhs_id = t;
|
||
|
} else { // rhs_id already set
|
||
|
if (t != rhs_id) {
|
||
|
ignore = true; // ignore other rhs identifiers
|
||
|
ignored = t;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool doItAgain = true;
|
||
|
for (int i=0; doItAgain; ++i) {
|
||
|
// read row identifier:
|
||
|
t = token();
|
||
|
|
||
|
// read number:
|
||
|
NT val;
|
||
|
if (!number(val))
|
||
|
return this->err1("number expected after '%' in this RHS record",t);
|
||
|
|
||
|
// store number:
|
||
|
const Index_map::const_iterator row_name = row_names.find(t);
|
||
|
if (row_name == row_names.end()) {
|
||
|
// no corresponding constraint; is it the constant term?
|
||
|
if (t == obj)
|
||
|
this->set_c0(-val);
|
||
|
else
|
||
|
return this->err1("unknown row identifier '%' in section RHS",t);
|
||
|
} else {
|
||
|
// we have an actual constraint
|
||
|
if (!ignore) {
|
||
|
this->set_b(row_name->second, val);
|
||
|
} else {
|
||
|
this->warn1("rhs with identifier '%' ignored", ignored);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// determine if we need to read another number:
|
||
|
doItAgain = i==0 && !whitespace();
|
||
|
}
|
||
|
|
||
|
// read next token:
|
||
|
t = token();
|
||
|
}
|
||
|
put_token_back(t);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool ranges_section()
|
||
|
{
|
||
|
std::string t = token();
|
||
|
if (t != "RANGES") { // (Note: RANGES section is optional.)
|
||
|
put_token_back(t);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
t = token();
|
||
|
std::string range_id;
|
||
|
while ((t != "BOUNDS" && t != "QMATRIX" &&
|
||
|
t != "DMATRIX" && t != "QUADOBJ" && t != "ENDATA")) {
|
||
|
// read rhs identifier and if it is different from the one
|
||
|
// from the previous iteration, ignore the whole row:
|
||
|
bool ignore = false;
|
||
|
std::string ignored;
|
||
|
if (range_id.size() == 0) { // first time we enter the loop?
|
||
|
range_id = t;
|
||
|
} else { // range_id already set
|
||
|
if (t != range_id) {
|
||
|
ignore = true; // ignore other range identifiers
|
||
|
ignored = t;
|
||
|
}
|
||
|
}
|
||
|
bool doItAgain = true;
|
||
|
for (int i=0; doItAgain; ++i) {
|
||
|
// read row identifier:
|
||
|
t = token();
|
||
|
|
||
|
// read number:
|
||
|
NT val;
|
||
|
if (!number(val))
|
||
|
return this->err1
|
||
|
("number expected after '%' in this RANGES record",t);
|
||
|
|
||
|
// duplicate the constraint, depending on sign of val and type
|
||
|
// of constraint
|
||
|
const Index_map::const_iterator row_name = row_names.find(t);
|
||
|
if (row_name == row_names.end()) {
|
||
|
return this->err1("unknown row identifier '%' in section RANGES",t);
|
||
|
} else {
|
||
|
if (!ignore) {
|
||
|
int index = row_name->second;
|
||
|
CGAL::Comparison_result type = *(this->get_r()+index);
|
||
|
// duplicate the row, unless it has already been duplicated
|
||
|
const Index_map::const_iterator duplicated_row_name =
|
||
|
duplicated_row_names.find(t);
|
||
|
if (duplicated_row_name != duplicated_row_names.end())
|
||
|
return this->err1
|
||
|
("duplicate row identifier '%' in section RANGES",t);
|
||
|
duplicated_row_names.insert(*row_name);
|
||
|
std::string dup_name = row_name->first+std::string("_DUPLICATED");
|
||
|
int new_index = this->get_m();
|
||
|
row_names.insert(String_int_pair (dup_name, new_index));
|
||
|
row_by_index.push_back (dup_name);
|
||
|
for (unsigned int j=0; j<var_names.size(); ++j) {
|
||
|
NT val = (*(this->get_a()+j))[index];
|
||
|
this->set_a (j, new_index, val);
|
||
|
}
|
||
|
// determine rhs for this new row. Here are the rules:
|
||
|
// if r is the ranges value and b is the old right-hand
|
||
|
// side, then we have h <= constraint <= u according to
|
||
|
// this table:
|
||
|
//
|
||
|
// row type sign of r h u
|
||
|
// ----------------------------------------------
|
||
|
// G + or - b b + |r|
|
||
|
// L + or - b - |r| b
|
||
|
// E + b b + |r|
|
||
|
// E - b - |r| b
|
||
|
|
||
|
switch (type) {
|
||
|
case CGAL::LARGER: // introduce "<= b+|r|"
|
||
|
this->set_r(new_index, CGAL::SMALLER);
|
||
|
this->set_b(new_index, *(this->get_b()+index) + CGAL::abs(val));
|
||
|
break;
|
||
|
case CGAL::SMALLER: // introduce ">= b-|r|"
|
||
|
this->set_r(new_index, CGAL::LARGER);
|
||
|
this->set_b(new_index, *(this->get_b()+index) - CGAL::abs(val));
|
||
|
break;
|
||
|
case CGAL::EQUAL:
|
||
|
if (CGAL_NTS is_positive (val)) {
|
||
|
// introduce "<= b+|r|"
|
||
|
this->set_r(new_index, CGAL::SMALLER);
|
||
|
} else {
|
||
|
// introduce ">= b-|r|"
|
||
|
this->set_r(new_index, CGAL::LARGER);
|
||
|
}
|
||
|
this->set_b(new_index, *(this->get_b()+index) + val);
|
||
|
break;
|
||
|
default:
|
||
|
CGAL_qpe_assertion(false);
|
||
|
}
|
||
|
} else {
|
||
|
this->warn1("range with identifier '%' ignored", ignored);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// determine if we need to read another number:
|
||
|
doItAgain = i==0 && !whitespace();
|
||
|
}
|
||
|
|
||
|
// read next token:
|
||
|
t = token();
|
||
|
}
|
||
|
put_token_back(t);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool bounds_section()
|
||
|
{
|
||
|
std::string t = token();
|
||
|
if (t != "BOUNDS") { // (Note: BOUNDS section is optional.)
|
||
|
put_token_back(t);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
t = token();
|
||
|
std::string bound_id;
|
||
|
while (t != "QMATRIX" && t != "DMATRIX" && t != "QUADOBJ" && t != "ENDATA") {
|
||
|
// process type of bound:
|
||
|
enum Bound_type { LO, UP, FX, FR, MI, PL};
|
||
|
Bound_type type;
|
||
|
if (t=="LO")
|
||
|
type = LO;
|
||
|
else if (t=="UP")
|
||
|
type = UP;
|
||
|
else if (t=="FX")
|
||
|
type = FX;
|
||
|
else if (t=="FR")
|
||
|
type = FR;
|
||
|
else if (t=="MI")
|
||
|
type = MI;
|
||
|
else if (t=="PL")
|
||
|
type = PL;
|
||
|
else
|
||
|
return
|
||
|
this->err1
|
||
|
("expected 'LO', 'UP', 'FX', 'FR', 'MI', or 'PL' here but found '%'",
|
||
|
t);
|
||
|
|
||
|
// remember bound:
|
||
|
const std::string bound = t;
|
||
|
|
||
|
// find bound label; there may be several, but we only process
|
||
|
// the bounds having the first bound label that occurs. This
|
||
|
// label may be empty, though
|
||
|
t = token(); // bound label or variable name (case of empty bound label)
|
||
|
if (bound_id.size() == 0) { // first time we see a bound label / variable?
|
||
|
const Index_map::const_iterator var_name = var_names.find(t);
|
||
|
if (var_name != var_names.end()) { // is the token a variable?
|
||
|
bound_id = " "; // there is no bound label
|
||
|
put_token_back(t); // the variable name is processed below
|
||
|
} else
|
||
|
bound_id = t; // we found a bound label
|
||
|
} else {
|
||
|
// now we already know the bound label
|
||
|
if (bound_id == " ") // empty bound label?
|
||
|
put_token_back(t); // the variable name is processed below
|
||
|
else
|
||
|
if (t != bound_id) {
|
||
|
this->warn1("ignoring all bounds for bound label '%'",t);
|
||
|
this->warn1("(only bounds for bound label '%' are accepted)",
|
||
|
bound_id);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// find variable name;
|
||
|
t = token();
|
||
|
const Index_map::const_iterator var_name = var_names.find(t);
|
||
|
if (var_name == var_names.end()) // unknown variable?
|
||
|
return this->err1("unknown variable '%' in BOUNDS section",t);
|
||
|
const unsigned int var_index = var_name->second;;
|
||
|
|
||
|
// read value of bound, if appropriate:
|
||
|
NT val;
|
||
|
if (type==LO || type==UP || type==FX)
|
||
|
if (!number(val))
|
||
|
return this->err2("expected number after '%' in % bound",t,bound);
|
||
|
|
||
|
// store bound:
|
||
|
switch (type) {
|
||
|
case FX:
|
||
|
this->set_u (var_index, true, val);
|
||
|
CGAL_FALLTHROUGH;
|
||
|
case LO:
|
||
|
this->set_l (var_index, true, val);
|
||
|
break;
|
||
|
case UP:
|
||
|
this->set_u (var_index, true, val);
|
||
|
if (val <= 0 && *(this->get_fl()+var_index)
|
||
|
&& *(this->get_l()+var_index) == 0)
|
||
|
if (val < 0)
|
||
|
this->set_l(var_index, false);
|
||
|
break;
|
||
|
case FR:
|
||
|
this->set_u(var_index, false);
|
||
|
this->set_l(var_index, false);
|
||
|
break;
|
||
|
case MI:
|
||
|
this->set_l(var_index, false);
|
||
|
break;
|
||
|
case PL:
|
||
|
this->set_u(var_index, false);
|
||
|
break;
|
||
|
default:
|
||
|
CGAL_qpe_assertion(false);
|
||
|
}
|
||
|
|
||
|
// read next token:
|
||
|
t = token();
|
||
|
}
|
||
|
put_token_back(t);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool qmatrix_section()
|
||
|
{
|
||
|
std::string t = token();
|
||
|
if (t!="QMATRIX" && t!="DMATRIX" && t!="QUADOBJ") { // optional
|
||
|
put_token_back(t);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// remember section name:
|
||
|
D_section = t;
|
||
|
const bool multiply_by_two = t=="DMATRIX";
|
||
|
|
||
|
t = token();
|
||
|
std::string bound_id;
|
||
|
while (t != "ENDATA") {
|
||
|
// find first variable name;
|
||
|
const Index_map::const_iterator var1_name = var_names.find(t);
|
||
|
if (var1_name == var_names.end()) // unknown variable?
|
||
|
return this->err2("unknown first variable '%' in '%' section",
|
||
|
t, D_section);
|
||
|
const unsigned int var1_index = var1_name->second;
|
||
|
|
||
|
// find second variable name;
|
||
|
t = token();
|
||
|
const Index_map::const_iterator var2_name = var_names.find(t);
|
||
|
if (var2_name == var_names.end()) // unknown variable?
|
||
|
return this->err2("unknown second variable '%' in '%' section",
|
||
|
t, D_section);
|
||
|
const unsigned int var2_index = var2_name->second;;
|
||
|
|
||
|
// read value:
|
||
|
NT val;
|
||
|
if (!number(val))
|
||
|
return this->err2("expected number after '%' in section '%'",
|
||
|
t, D_section);
|
||
|
|
||
|
// multiply by two if approriate:
|
||
|
if (multiply_by_two)
|
||
|
val *= NT(2);
|
||
|
|
||
|
// set entry in D:
|
||
|
int i, j;
|
||
|
if (var2_index <= var1_index) {
|
||
|
i = var1_index; j = var2_index;
|
||
|
} else {
|
||
|
i = var2_index; j = var1_index;
|
||
|
}
|
||
|
// rule out that we previously put a different (nonzero) value at (i,j)
|
||
|
NT old_val = (*(this->get_d()+i))[j];
|
||
|
if (!CGAL::is_zero(old_val) && old_val != val)
|
||
|
return this->err3("nonsymmetric '%' section at variables '%' and '%'",
|
||
|
D_section, var1_name->first, var2_name->first);
|
||
|
this->set_d(i, j, val);
|
||
|
|
||
|
// read next token:
|
||
|
t = token();
|
||
|
}
|
||
|
put_token_back(t);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
} //namespace CGAL
|
||
|
|
||
|
#include <CGAL/enable_warnings.h>
|
||
|
|
||
|
#endif // CGAL_QP_MODELS_H
|