dust3d/thirdparty/cgal/CGAL-5.1/include/CGAL/QP_models.h

1550 lines
47 KiB
C
Raw Normal View History

// Copyright (c) 1997-2007 ETH Zurich (Switzerland).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
2020-10-13 12:44:25 +00:00
// $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>
2020-10-13 12:44:25 +00:00
#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:
2020-10-13 12:44:25 +00:00
typedef Const_oneset_iterator<value_type>
It_1d; // 1-dimensional random access iterator for a constant value
2020-10-13 12:44:25 +00:00
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)
2020-10-13 12:44:25 +00:00
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
2020-10-13 12:44:25 +00:00
class Quadratic_program_from_iterators
{
public:
// types
typedef A_it A_iterator;
2020-10-13 12:44:25 +00:00
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;
2020-10-13 12:44:25 +00:00
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;
2020-10-13 12:44:25 +00:00
B_iterator b_it;
R_iterator r_it;
FL_iterator fl_it;
L_iterator l_it;
FU_iterator fu_it;
2020-10-13 12:44:25 +00:00
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
2020-10-13 12:44:25 +00:00
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))
2020-10-13 12:44:25 +00:00
: 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;}
2020-10-13 12:44:25 +00:00
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)
2020-10-13 12:44:25 +00:00
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 (
2020-10-13 12:44:25 +00:00
int n, int m,
const A_it& a,
const B_it& b,
const R_it& r,
const FL_it& fl,
const L_it& l,
2020-10-13 12:44:25 +00:00
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);
2020-10-13 12:44:25 +00:00
}
// Linear_program_from_iterators
// -----------------------------
template <
typename A_it, // for constraint matrix A (columnwise)
2020-10-13 12:44:25 +00:00
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
2020-10-13 12:44:25 +00:00
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:
2020-10-13 12:44:25 +00:00
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 (
2020-10-13 12:44:25 +00:00
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)
2020-10-13 12:44:25 +00:00
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 (
2020-10-13 12:44:25 +00:00
int n, int m,
const A_it& a,
const B_it& b,
const R_it& r,
const FL_it& fl,
const L_it& l,
2020-10-13 12:44:25 +00:00
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);
2020-10-13 12:44:25 +00:00
}
// Nonnegative_quadratic_program_from_iterators
// --------------------------------------------
template <
typename A_it, // for constraint matrix A (columnwise)
2020-10-13 12:44:25 +00:00
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
2020-10-13 12:44:25 +00:00
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,
2020-10-13 12:44:25 +00:00
typename QP_model_default_iterators<bool*>::It_1d,
typename QP_model_default_iterators<C_it>::It_1d,
D_it, C_it>
{
private:
2020-10-13 12:44:25 +00:00
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,
2020-10-13 12:44:25 +00:00
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 (
2020-10-13 12:44:25 +00:00
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)
{}
};
2020-10-13 12:44:25 +00:00
// corresponding global function
// make_nonnegative_quadratic_program_from_iterators
// -------------------------------------------------
template <
typename A_it, // for constraint matrix A (columnwise)
2020-10-13 12:44:25 +00:00
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 (
2020-10-13 12:44:25 +00:00
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);
2020-10-13 12:44:25 +00:00
}
// Nonnegative_linear_program_from_iterators
// -----------------------------------------
template <
typename A_it, // for constraint matrix A (columnwise)
2020-10-13 12:44:25 +00:00
typename B_it, // for right-hand side b
typename R_it, // for relations (value type Comparison)
typename C_it > // for objective function c
2020-10-13 12:44:25 +00:00
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,
2020-10-13 12:44:25 +00:00
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:
2020-10-13 12:44:25 +00:00
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,
2020-10-13 12:44:25 +00:00
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 (
2020-10-13 12:44:25 +00:00
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)
2020-10-13 12:44:25 +00:00
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 (
2020-10-13 12:44:25 +00:00
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);
}
2020-10-13 12:44:25 +00:00
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;
2020-10-13 12:44:25 +00:00
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
2020-10-13 12:44:25 +00:00
typedef std::map<std::size_t, NT>
Sparse_vector;
typedef std::map<std::size_t, CGAL::Comparison_result>
Sparse_r_vector;
2020-10-13 12:44:25 +00:00
typedef std::map<std::size_t, bool>
Sparse_f_vector;
// Sparse_matrix
2020-10-13 12:44:25 +00:00
typedef std::vector<Sparse_vector>
Sparse_matrix;
// Sparse_vector_iterators
2020-10-13 12:44:25 +00:00
//typedef CGAL::Fake_random_access_const_iterator<Sparse_vector>
typedef boost::transform_iterator<CGAL::Map_with_default<Sparse_vector>,
2020-10-13 12:44:25 +00:00
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>,
2020-10-13 12:44:25 +00:00
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
2020-10-13 12:44:25 +00:00
(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;
2020-10-13 12:44:25 +00:00
// 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
2020-10-13 12:44:25 +00:00
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;
2020-10-13 12:44:25 +00:00
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
2020-10-13 12:44:25 +00:00
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
2020-10-13 12:44:25 +00:00
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:
2020-10-13 12:44:25 +00:00
// 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
2020-10-13 12:44:25 +00:00
int get_n() const
{
CGAL_qpe_assertion(is_valid());
return n_;
}
2020-10-13 12:44:25 +00:00
int get_m() const
{
CGAL_qpe_assertion(is_valid());
return m_;
}
2020-10-13 12:44:25 +00:00
A_iterator get_a() const
{
CGAL_qpe_assertion(is_valid());
return A_iterator (a_matrix.begin(), Beginner());
}
2020-10-13 12:44:25 +00:00
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),
2020-10-13 12:44:25 +00:00
CGAL::Map_with_default<Sparse_vector>
(&b_vector, NT(0)));
}
2020-10-13 12:44:25 +00:00
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),
2020-10-13 12:44:25 +00:00
CGAL::Map_with_default<Sparse_r_vector>
(&r_vector, default_r));
}
2020-10-13 12:44:25 +00:00
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),
2020-10-13 12:44:25 +00:00
CGAL::Map_with_default<Sparse_f_vector>
(&fl_vector, default_fl));
}
2020-10-13 12:44:25 +00:00
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),
2020-10-13 12:44:25 +00:00
CGAL::Map_with_default<Sparse_vector>
(&l_vector, default_l));
}
2020-10-13 12:44:25 +00:00
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),
2020-10-13 12:44:25 +00:00
CGAL::Map_with_default<Sparse_f_vector>
(&fu_vector, default_fu));
}
2020-10-13 12:44:25 +00:00
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),
2020-10-13 12:44:25 +00:00
CGAL::Map_with_default<Sparse_vector>
(&u_vector, default_u));
}
2020-10-13 12:44:25 +00:00
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),
2020-10-13 12:44:25 +00:00
CGAL::Map_with_default<Sparse_vector>
(&c_vector, NT(0)));
}
2020-10-13 12:44:25 +00:00
D_iterator get_d() const
{
CGAL_qpe_assertion(is_valid());
return D_iterator (d_matrix.begin(), Beginner());
}
2020-10-13 12:44:25 +00:00
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
2020-10-13 12:44:25 +00:00
Quadratic_program
(CGAL::Comparison_result relation = CGAL::EQUAL,
bool finite_lower = true,
NT lower = 0,
bool finite_upper = false,
2020-10-13 12:44:25 +00:00
NT upper = 0)
: n_(0), m_(0), c0_(0),
default_r(relation), default_fl(finite_lower),
2020-10-13 12:44:25 +00:00
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
2020-10-13 12:44:25 +00:00
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
2020-10-13 12:44:25 +00:00
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,
2020-10-13 12:44:25 +00:00
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) {
2020-10-13 12:44:25 +00:00
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)
2020-10-13 12:44:25 +00:00
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"
2020-10-13 12:44:25 +00:00
// 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_);
}
2020-10-13 12:44:25 +00:00
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
2020-10-13 12:44:25 +00:00
for (typename Sparse_vector::const_iterator
j = lu.begin(); j != lu.end(); ++j)
if (!CGAL::is_zero(j->second)) return false;
return true;
}
}
2020-10-13 12:44:25 +00:00
public:
bool is_nonnegative() const
{
2020-10-13 12:44:25 +00:00
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
{
2020-10-13 12:44:25 +00:00
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
{
2020-10-13 12:44:25 +00:00
return
all_bounds_are (false, fl_vector, default_fl) &&
all_bounds_are (false, fu_vector, default_fu);
}
// set methods
2020-10-13 12:44:25 +00:00
void set_a (int j, int i, const NT& val)
{
CGAL_qpe_assertion (j >= 0);
CGAL_qpe_assertion (i >= 0);
if (j >= n_) {
2020-10-13 12:44:25 +00:00
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);
2020-10-13 12:44:25 +00:00
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)
2020-10-13 12:44:25 +00:00
{
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))
2020-10-13 12:44:25 +00:00
{
CGAL_qpe_assertion (j >= 0);
if (j >= n_) {
2020-10-13 12:44:25 +00:00
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;
}
2020-10-13 12:44:25 +00:00
void set_u (int j, bool is_finite, const NT& val = NT(0))
2020-10-13 12:44:25 +00:00
{
CGAL_qpe_assertion (j >= 0);
if (j >= n_) {
2020-10-13 12:44:25 +00:00
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
2020-10-13 12:44:25 +00:00
u_vector[j] = val;
}
void set_c (int j, const NT& val)
2020-10-13 12:44:25 +00:00
{
CGAL_qpe_assertion (j >= 0);
if (j >= n_) {
2020-10-13 12:44:25 +00:00
n_ = j+1;
grow_a_d(n_);
}
2020-10-13 12:44:25 +00:00
if (CGAL::is_zero(val))
c_vector.erase(j);
else
c_vector[j] = val;
}
void set_c0 (const NT& val)
{
c0_ = val;
}
2020-10-13 12:44:25 +00:00
void set_d (int i, int j, const NT& val)
{
CGAL_qpe_assertion (i >= 0);
CGAL_qpe_assertion (j >= 0);
2020-10-13 12:44:25 +00:00
CGAL_qpe_assertion (j <= i); // lower-diagonal entry
if (i >= n_) {
n_ = i+1;
grow_a_d(n_);
2020-10-13 12:44:25 +00:00
}
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,
2020-10-13 12:44:25 +00:00
const std::string& parameter1) {
error_msg = replace1(msg,parameter1);
is_valid_ = false;
return false;
}
bool err2(const char* msg,
2020-10-13 12:44:25 +00:00
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,
2020-10-13 12:44:25 +00:00
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_>
2020-10-13 12:44:25 +00:00
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:
2020-10-13 12:44:25 +00:00
// types
typedef std::map<std::string,unsigned int> Index_map;
typedef std::pair<std::string,unsigned int> String_int_pair;
public:
// constructor
2020-10-13 12:44:25 +00:00
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())
2020-10-13 12:44:25 +00:00
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
2020-10-13 12:44:25 +00:00
const std::string& get_comment() const
{
return comment_;
}
// returns name of the problem
2020-10-13 12:44:25 +00:00
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];
2020-10-13 12:44:25 +00:00
}
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;
2020-10-13 12:44:25 +00:00
else
return var_name->second;
}
2020-10-13 12:44:25 +00:00
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];
2020-10-13 12:44:25 +00:00
}
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;
2020-10-13 12:44:25 +00:00
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;
2020-10-13 12:44:25 +00:00
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) {
2020-10-13 12:44:25 +00:00
if (c!='\r' && c!='\n') {
if (remember_comment)
comment_.push_back(c);
} else
in_comment = false;
} else { // not in comment?
2020-10-13 12:44:25 +00:00
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;
}
2020-10-13 12:44:25 +00:00
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)) {
2020-10-13 12:44:25 +00:00
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();
}
2020-10-13 12:44:25 +00:00
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;
2020-10-13 12:44:25 +00:00
if (whitespace())
// line break eaten, name is empty
return true;
do {
from.get(c);
if (c == '\r' || c == '\n') break;
2020-10-13 12:44:25 +00:00
if (isspace(c))
whitespaces.push_back(c); // save whitespace
else {
2020-10-13 12:44:25 +00:00
// 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':
2020-10-13 12:44:25 +00:00
// register name of objective row:
if (obj.size() == 0) // remember first (and ignore others)
obj = t;
break;
case 'G':
case 'L':
case 'E':
2020-10-13 12:44:25 +00:00
{
// 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:
2020-10-13 12:44:25 +00:00
return
this->err1
("expected 'N', 'L', 'E', or 'G' in ROWS section but found '%'",
symbol);
}
t = token();
}
put_token_back(t);
return true;
}
2020-10-13 12:44:25 +00:00
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());
2020-10-13 12:44:25 +00:00
col_name = t;
var_names.insert(String_int_pair(t,var_index));
var_by_index.push_back(t);
} else { // variable that is already known?
2020-10-13 12:44:25 +00:00
var_index = var_name->second;
col_name = var_name->first;
}
2020-10-13 12:44:25 +00:00
bool doItAgain = true;
for (int i=0; doItAgain; ++i) {
2020-10-13 12:44:25 +00:00
// 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();
}
2020-10-13 12:44:25 +00:00
// 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" &&
2020-10-13 12:44:25 +00:00
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?
2020-10-13 12:44:25 +00:00
rhs_id = t;
} else { // rhs_id already set
2020-10-13 12:44:25 +00:00
if (t != rhs_id) {
ignore = true; // ignore other rhs identifiers
ignored = t;
}
}
bool doItAgain = true;
for (int i=0; doItAgain; ++i) {
2020-10-13 12:44:25 +00:00
// 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();
}
2020-10-13 12:44:25 +00:00
// read next token:
t = token();
}
put_token_back(t);
2020-10-13 12:44:25 +00:00
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;
2020-10-13 12:44:25 +00:00
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?
2020-10-13 12:44:25 +00:00
range_id = t;
} else { // range_id already set
2020-10-13 12:44:25 +00:00
if (t != range_id) {
ignore = true; // ignore other range identifiers
ignored = t;
}
}
bool doItAgain = true;
for (int i=0; doItAgain; ++i) {
2020-10-13 12:44:25 +00:00
// 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();
}
2020-10-13 12:44:25 +00:00
// read next token:
t = token();
}
put_token_back(t);
2020-10-13 12:44:25 +00:00
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")
2020-10-13 12:44:25 +00:00
type = LO;
else if (t=="UP")
2020-10-13 12:44:25 +00:00
type = UP;
else if (t=="FX")
2020-10-13 12:44:25 +00:00
type = FX;
else if (t=="FR")
2020-10-13 12:44:25 +00:00
type = FR;
else if (t=="MI")
2020-10-13 12:44:25 +00:00
type = MI;
else if (t=="PL")
2020-10-13 12:44:25 +00:00
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
2020-10-13 12:44:25 +00:00
// the bounds having the first bound label that occurs. This
// label may be empty, though
2020-10-13 12:44:25 +00:00
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?
2020-10-13 12:44:25 +00:00
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 {
2020-10-13 12:44:25 +00:00
// 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?
2020-10-13 12:44:25 +00:00
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)
2020-10-13 12:44:25 +00:00
if (!number(val))
return this->err2("expected number after '%' in % bound",t,bound);
// store bound:
switch (type) {
case FX:
2020-10-13 12:44:25 +00:00
this->set_u (var_index, true, val);
CGAL_FALLTHROUGH;
case LO:
2020-10-13 12:44:25 +00:00
this->set_l (var_index, true, val);
break;
case UP:
2020-10-13 12:44:25 +00:00
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:
2020-10-13 12:44:25 +00:00
this->set_u(var_index, false);
this->set_l(var_index, false);
break;
case MI:
2020-10-13 12:44:25 +00:00
this->set_l(var_index, false);
break;
case PL:
2020-10-13 12:44:25 +00:00
this->set_u(var_index, false);
break;
default:
2020-10-13 12:44:25 +00:00
CGAL_qpe_assertion(false);
}
2020-10-13 12:44:25 +00:00
// 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;
2020-10-13 12:44:25 +00:00
}
// 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?
2020-10-13 12:44:25 +00:00
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?
2020-10-13 12:44:25 +00:00
return this->err2("unknown second variable '%' in '%' section",
t, D_section);
const unsigned int var2_index = var2_name->second;;
2020-10-13 12:44:25 +00:00
// read value:
NT val;
if (!number(val))
2020-10-13 12:44:25 +00:00
return this->err2("expected number after '%' in section '%'",
t, D_section);
// multiply by two if approriate:
if (multiply_by_two)
2020-10-13 12:44:25 +00:00
val *= NT(2);
// set entry in D:
int i, j;
if (var2_index <= var1_index) {
2020-10-13 12:44:25 +00:00
i = var1_index; j = var2_index;
} else {
2020-10-13 12:44:25 +00:00
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)
2020-10-13 12:44:25 +00:00
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);
2020-10-13 12:44:25 +00:00
return true;
}
2020-10-13 12:44:25 +00:00
};
} //namespace CGAL
#include <CGAL/enable_warnings.h>
#endif // CGAL_QP_MODELS_H