/* This is the header file of the Parma Polyhedra Library.
   Copyright (C) 2001-2006 Roberto Bagnara <bagnara@cs.unipr.it>

This file is part of the Parma Polyhedra Library (PPL).

The PPL is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.

The PPL is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.

For the most up-to-date information see the Parma Polyhedra Library
site: http://www.cs.unipr.it/ppl/ . */

#ifndef PPL_ppl_hh
#define PPL_ppl_hh 1

#ifdef NDEBUG
# define PPL_SAVE_NDEBUG 1
# undef NDEBUG
#endif

// Automatically generated from PPL source file ../config.h line 1
/* config.h.  Generated by configure.  */
/* config.h.in.  Generated from configure.ac by autoheader.  */


#ifndef PPL_ppl_config_h
#define PPL_ppl_config_h 1


/* Defined if the integral type to be used for coefficients is a checked one.
   */
/* #undef CHECKED_INTEGERS */

/* The number of bits of coefficients; 0 if unbounded. */
#define COEFFICIENT_BITS 0

/* The integral type used to represent coefficients. */
#define COEFFICIENT_TYPE mpz_class

/* The binary format of C++ doubles, if supported; undefined otherwise. */
#define CXX_DOUBLE_BINARY_FORMAT float_ieee754_double

/* The binary format of C++ floats, if supported; undefined otherwise. */
#define CXX_FLOAT_BINARY_FORMAT float_ieee754_single

/* The binary format of C++ long doubles, if supported; undefined otherwise.
   */
#define CXX_LONG_DOUBLE_BINARY_FORMAT float_intel_double_extended

/* Not zero if the C++ compiler supports __attribute__ ((weak)). */
#define CXX_SUPPORTS_ATTRIBUTE_WEAK 1

/* Not zero if the C++ compiler supports flexible arrays. */
#define CXX_SUPPORTS_FLEXIBLE_ARRAYS 1

/* Enable more assertions when defined. */
/* #undef EXTRA_ROW_DEBUG */

/* Defined if the integral type to be used for coefficients is GMP's one. */
#define GMP_INTEGERS 1

/* Not zero if GMP has been compiled with support for exceptions. */
#define GMP_SUPPORTS_EXCEPTIONS 1

/* Define to 1 if you have the declaration of `ffs', and to 0 if you don't. */
#define HAVE_DECL_FFS 1

/* Define to 1 if you have the declaration of `fma', and to 0 if you don't. */
#define HAVE_DECL_FMA 1

/* Define to 1 if you have the declaration of `fmaf', and to 0 if you don't.
   */
#define HAVE_DECL_FMAF 1

/* Define to 1 if you have the declaration of `fmal', and to 0 if you don't.
   */
#define HAVE_DECL_FMAL 1

/* Define to 1 if you have the declaration of `getenv', and to 0 if you don't.
   */
#define HAVE_DECL_GETENV 1

/* Define to 1 if you have the declaration of `rintf', and to 0 if you don't.
   */
#define HAVE_DECL_RINTF 1

/* Define to 1 if you have the declaration of `rintl', and to 0 if you don't.
   */
#define HAVE_DECL_RINTL 0

/* Define to 1 if you have the declaration of `RLIMIT_AS', and to 0 if you
   don't. */
#define HAVE_DECL_RLIMIT_AS 1

/* Define to 1 if you have the declaration of `RLIMIT_DATA', and to 0 if you
   don't. */
#define HAVE_DECL_RLIMIT_DATA 1

/* Define to 1 if you have the declaration of `RLIMIT_RSS', and to 0 if you
   don't. */
#define HAVE_DECL_RLIMIT_RSS 1

/* Define to 1 if you have the declaration of `RLIMIT_VMEM', and to 0 if you
   don't. */
#define HAVE_DECL_RLIMIT_VMEM 1

/* Define to 1 if you have the declaration of `strtod', and to 0 if you don't.
   */
#define HAVE_DECL_STRTOD 1

/* Define to 1 if you have the declaration of `strtof', and to 0 if you don't.
   */
#define HAVE_DECL_STRTOF 1

/* Define to 1 if you have the declaration of `strtold', and to 0 if you
   don't. */
#define HAVE_DECL_STRTOLD 1

/* Define to 1 if you have the declaration of `strtoll', and to 0 if you
   don't. */
#define HAVE_DECL_STRTOLL 1

/* Define to 1 if you have the declaration of `strtoull', and to 0 if you
   don't. */
#define HAVE_DECL_STRTOULL 1

/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1

/* Define to 1 if you have the <fenv.h> header file. */
#define HAVE_FENV_H 1

/* Define to 1 if you have the <getopt.h> header file. */
#define HAVE_GETOPT_H 1

/* Define to 1 if you have the <ieeefp.h> header file. */
#define HAVE_IEEEFP_H 1

/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1

/* Define to 1 if the system has the type `int_fast16_t'. */
#define HAVE_INT_FAST16_T 1

/* Define to 1 if the system has the type `int_fast32_t'. */
#define HAVE_INT_FAST32_T 1

/* Define to 1 if the system has the type `int_fast64_t'. */
#define HAVE_INT_FAST64_T 1

/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1

/* Define to 1 if you have the <signal.h> header file. */
#define HAVE_SIGNAL_H 1

/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1

/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1

/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1

/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1

/* Define to 1 if you have the <sys/resource.h> header file. */
#define HAVE_SYS_RESOURCE_H 1

/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1

/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1

/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1

/* Define to 1 if the system has the type `uint_fast16_t'. */
#define HAVE_UINT_FAST16_T 1

/* Define to 1 if the system has the type `uint_fast32_t'. */
#define HAVE_UINT_FAST32_T 1

/* Define to 1 if the system has the type `uint_fast64_t'. */
#define HAVE_UINT_FAST64_T 1

/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1

/* Define to 1 if `_mp_alloc' is member of `__mpz_struct'. */
#define HAVE___MPZ_STRUCT__MP_ALLOC 1

/* Define to 1 if `_mp_d' is member of `__mpz_struct'. */
#define HAVE___MPZ_STRUCT__MP_D 1

/* Define to 1 if `_mp_size' is member of `__mpz_struct'. */
#define HAVE___MPZ_STRUCT__MP_SIZE 1

/* Defined if the integral type to be used for coefficients is a native one.
   */
/* #undef NATIVE_INTEGERS */

/* Assertions are disabled when this is defined. */
#define NDEBUG 1

/* Name of package */
#define PACKAGE "ppl"

/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "ppl-devel@cs.unipr.it"

/* Define to the full name of this package. */
#define PACKAGE_NAME "the Parma Polyhedra Library"

/* Define to the full name and version of this package. */
#define PACKAGE_STRING "the Parma Polyhedra Library 0.9"

/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "ppl"

/* Define to the version of this package. */
#define PACKAGE_VERSION "0.9"

/* Not zero if the FPU can be controlled. */
#define PPL_CAN_CONTROL_FPU 1

/* This contains the options with which `configure' was invoked. */
#define PPL_CONFIGURE_OPTIONS "'--disable-debugging' '--enable-optimization' '--with-cflags=-O2 -fno-strict-aliasing -pipe' '--with-cxxflags=-O2 -fno-strict-aliasing -pipe' '--with-libgmp-prefix=/usr/local' '--with-libgmpxx-prefix=/usr/local' '--prefix=/usr/local' '--mandir=/usr/local/man' '--infodir=/usr/local/info/' '--build=amd64-portbld-freebsd7.1' 'CC=cc' 'CFLAGS=-O2 -fno-strict-aliasing -pipe' 'CXXFLAGS=-O2 -fno-strict-aliasing -pipe' 'CXX=c++' 'build_alias=amd64-portbld-freebsd7.1'"

/* Not zero if doubles are supported. */
#define PPL_SUPPORTED_DOUBLE 1

/* Not zero if floats are supported. */
#define PPL_SUPPORTED_FLOAT 1

/* Not zero if long doubles are supported. */
#define PPL_SUPPORTED_LONG_DOUBLE 1

/* The size of a `double', as computed by sizeof. */
#define SIZEOF_DOUBLE 8

/* The size of a `float', as computed by sizeof. */
#define SIZEOF_FLOAT 4

/* The size of a `int', as computed by sizeof. */
#define SIZEOF_INT 4

/* The size of a `long', as computed by sizeof. */
#define SIZEOF_LONG 8

/* The size of a `long double', as computed by sizeof. */
#define SIZEOF_LONG_DOUBLE 16

/* The size of a `long long', as computed by sizeof. */
#define SIZEOF_LONG_LONG 8

/* The size of a `mp_limb_t', as computed by sizeof. */
#define SIZEOF_MP_LIMB_T 8

/* The size of a `size_t', as computed by sizeof. */
#define SIZEOF_SIZE_T 8

/* The size of a `unsigned', as computed by sizeof. */
#define SIZEOF_UNSIGNED 4

/* The size of a `unsigned long', as computed by sizeof. */
#define SIZEOF_UNSIGNED_LONG 8

/* The size of a `unsigned long long', as computed by sizeof. */
#define SIZEOF_UNSIGNED_LONG_LONG 8

/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1

/* Version number of package */
#define VERSION "0.9"

/* Define to 1 if your processor stores words with the most significant byte
   first (like Motorola and SPARC, unlike Intel and VAX). */
/* #undef WORDS_BIGENDIAN */

/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */

/* Define to `__inline__' or `__inline' if that's what the C compiler
   calls it, or to nothing if 'inline' is not supported under any name.  */
#ifndef __cplusplus
/* #undef inline */
#endif


/*
  In order for the definition of `int64_t' to be seen by Comeau C/C++,
  we must make sure <stdint.h> is included before <sys/types.hh> is
  (even indirectly) included.
*/
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif

#endif /* !defined(PPL_ppl_config_h) */

// Automatically generated from PPL source file ../src/version.hh line 1
/* Declaration of macros and functions providing version  -*- C++ -*-
   and licensing information.
*/


//! The major number of the PPL version.
/*! \ingroup PPL_CXX_interface */
#define PPL_VERSION_MAJOR 0

//! The minor number of the PPL version.
/*! \ingroup PPL_CXX_interface */
#define PPL_VERSION_MINOR 9

//! The revision number of the PPL version.
/*! \ingroup PPL_CXX_interface */
#define PPL_VERSION_REVISION 0

/*! \brief
  The beta number of the PPL version.  This is zero for official
  releases and nonzero for development snapshots.
  \ingroup PPL_CXX_interface
*/
#define PPL_VERSION_BETA 0

//! A string containing the PPL version.
/*! \ingroup PPL_CXX_interface
  Let <CODE>M</CODE> and <CODE>m</CODE> denote the numbers associated
  to PPL_VERSION_MAJOR and PPL_VERSION_MINOR, respectively.  The
  format of PPL_VERSION is <CODE>M "." m</CODE> if both
  PPL_VERSION_REVISION (<CODE>r</CODE>) and PPL_VERSION_BETA
  (<CODE>b</CODE>)are zero, <CODE>M "." m "pre" b</CODE> if
  PPL_VERSION_REVISION is zero and PPL_VERSION_BETA is not zero,
  <CODE>M "." m "." r</CODE> if PPL_VERSION_REVISION is not zero and
  PPL_VERSION_BETA is zero, <CODE>M "." m "." r "pre" b</CODE> if
  neither PPL_VERSION_REVISION nor PPL_VERSION_BETA are zero.
*/
#define PPL_VERSION "0.9"

namespace Parma_Polyhedra_Library {

//! Returns the major number of the PPL version.
unsigned
version_major();

//! Returns the minor number of the PPL version.
unsigned
version_minor();

//! Returns the revision number of the PPL version.
unsigned
version_revision();

//! Returns the beta number of the PPL version.
unsigned
version_beta();

//! Returns a character string containing the PPL version.
const char* version();

//! Returns a character string containing the PPL banner.
/*!
  The banner provides information about the PPL version, the licensing,
  the lack of any warranty whatsoever, the C++ compiler used to build
  the library, where to report bugs and where to look for further
  information.
*/
const char* banner();

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/namespaces.hh line 1
/* Documentation for used namespaces.
*/


//! The entire library is confined to this namespace.
/*! \ingroup PPL_CXX_interface */
namespace Parma_Polyhedra_Library {

//! All input/output operators are confined to this namespace.
/*! \ingroup PPL_CXX_interface
  This is done so that the library's input/output operators
  do not interfere with those the user might want to define.
  In fact, it is highly unlikely that any pre-defined I/O
  operator will suit the needs of a client application.
  On the other hand, those applications for which the PPL
  I/O operator are enough can easily obtain access to them.
  For example, a directive like
  \code
    using namespace Parma_Polyhedra_Library::IO_Operators;
  \endcode
  would suffice for most uses.
  In more complex situations, such as
  \code
    const Constraint_System& cs = ...;
    copy(cs.begin(), cs.end(),
	 ostream_iterator<Constraint>(cout, "\n"));
  \endcode
  the Parma_Polyhedra_Library namespace must be suitably extended.
  This can be done as follows:
  \code
    namespace Parma_Polyhedra_Library {
      // Import all the output operators into the main PPL namespace.
      using IO_Operators::operator<<;
    }
  \endcode
*/
namespace IO_Operators {
} // namespace IO_Operators

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Types and functions implementing checked numbers.
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
namespace Checked {
} // namespace Checked

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! %Implementation related data and functions.
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
namespace Implementation {
} // namespace Implementation


} // namespace Parma_Polyhedra_Library


//! The standard C++ namespace.
/*! \ingroup PPL_CXX_interface
  The Parma Polyhedra Library conforms to the C++ standard and,
  in particular, as far as reserved names are concerned (17.4.3.1,
  [lib.reserved.names]).  The PPL, however, defines several
  template specializations for the standard library function templates
  <CODE>swap()</CODE> and <CODE>iter_swap()</CODE> (25.2.2, [lib.alg.swap]),
  and for the class template <CODE>numeric_limits</CODE>
  (18.2.1, [lib.limits]).

  \note
  The PPL provides the specializations of the class template
  <CODE>numeric_limits</CODE> not only for PPL-specific numeric types,
  but also for the GMP types <CODE>mpz_class</CODE> and
  <CODE>mpq_class</CODE>. These specializations will be removed
  as soon as they will be provided by the C++ interface of GMP.
*/
namespace std {
} // namespace std


// Automatically generated from PPL source file ../src/compiler.hh line 1
/* C++ compiler related stuff.
*/


namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Used to avoid unused variable warnings from the compiler.
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename T>
inline void
used(const T&) {
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Coefficient_traits_template.hh line 1


namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Coefficient traits.
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename Coefficient>
struct Coefficient_traits_template {
};

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Checked_Number.types.hh line 1


// Automatically generated from PPL source file ../src/Checked_Number.types.hh line 16

namespace Parma_Polyhedra_Library {

struct Checked_Number_Default_Policy;
struct Extended_Number_Policy;

template <typename T, typename Policy = Checked_Number_Default_Policy>
class Checked_Number;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/GMP_Integer.types.hh line 1


// Automatically generated from PPL source file ../src/GMP_Integer.types.hh line 16
#include <gmpxx.h>

namespace Parma_Polyhedra_Library {

/*! \class Parma_Polyhedra_Library::GMP_Integer
  \brief
  Unbounded integers as provided by the GMP library.

  \ingroup PPL_CXX_interface
  GMP_Integer is an alias for the <CODE>mpz_class</CODE> type
  defined in the C++ interface of the GMP library.
  For more information, see <CODE>http://www.swox.com/gmp/</CODE>
*/
typedef mpz_class GMP_Integer;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Coefficient traits specialization for unbounded integers.
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <>
struct Coefficient_traits_template<GMP_Integer> {
  //! The type used for references to const unbounded integers.
  typedef const GMP_Integer& const_reference;
};

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Coefficient.types.hh line 1


// Automatically generated from PPL source file ../src/Checked_Number.defs.hh line 1
/* Checked_Number class declaration.
*/


// Automatically generated from PPL source file ../src/checked.defs.hh line 1
/* Abstract checked arithmetic function container
*/


#include <iostream>
#include <gmpxx.h>
// Automatically generated from PPL source file ../src/Rounding_Dir.defs.hh line 1
/* Declaration of Rounding_Dir and related functions.
*/


// Automatically generated from PPL source file ../src/Result.defs.hh line 1
/* Result enum and supporting function declarations.
*/


namespace Parma_Polyhedra_Library {

//! Possible outcomes of a checked arithmetic computation.
/*! \ingroup PPL_CXX_interface */
enum Result {

  VC_MASK = 48,

  //! \hideinitializer Ordinary result class.
  VC_NORMAL = 0,

  //! \hideinitializer The computed result is inexact and rounded up.
  V_LT = 1,

  //! \hideinitializer The computed result is inexact and rounded down.
  V_GT = 2,

  //! \hideinitializer The computed result is exact.
  V_EQ = 4,

  //! \hideinitializer The computed result is inexact.
  V_NE = V_LT | V_GT,

  //! \hideinitializer The computed result may be inexact and rounded up.
  V_LE = V_EQ | V_LT,

  //! \hideinitializer The computed result may be inexact and rounded down.
  V_GE = V_EQ | V_GT,

  //! \hideinitializer The computed result may be inexact.
  V_LGE = V_LT | V_EQ | V_GT,

  //! \hideinitializer Negative infinity unrepresentable result class.
  VC_MINUS_INFINITY = 16,

  //! \hideinitializer A negative overflow occurred.
  V_NEG_OVERFLOW = VC_MINUS_INFINITY | V_GT,

  //! \hideinitializer Positive infinity unrepresentable result class.
  VC_PLUS_INFINITY = 32,

  //! \hideinitializer A positive overflow occurred.
  V_POS_OVERFLOW = VC_PLUS_INFINITY | V_LT,

  //! \hideinitializer Not a number result class.
  VC_NAN = 48,

  //! \hideinitializer Converting from unknown string.
  V_CVT_STR_UNK = 49,

  //! \hideinitializer Dividing by zero.
  V_DIV_ZERO = 50,

  //! \hideinitializer Adding two infinities having opposite signs.
  V_INF_ADD_INF = 51,

  //! \hideinitializer Dividing two infinities.
  V_INF_DIV_INF = 52,

  //! \hideinitializer Taking the modulus of an infinity.
  V_INF_MOD = 53,

  //! \hideinitializer Multiplying an infinity by zero.
  V_INF_MUL_ZERO = 54,

  //! \hideinitializer Subtracting two infinities having the same sign.
  V_INF_SUB_INF = 55,

  //! \hideinitializer Computing a remainder modulo zero.
  V_MOD_ZERO = 56,

  //! \hideinitializer Taking the square root of a negative number.
  V_SQRT_NEG = 57,

  //! \hideinitializer Unknown result due to intermediate negative overflow.
  V_UNKNOWN_NEG_OVERFLOW = 58,

  //! \hideinitializer Unknown result due to intermediate positive overflow.
  V_UNKNOWN_POS_OVERFLOW = 59,

  //! \hideinitializer Unordered comparison.
  V_UNORD_COMP = 60
};

bool is_special(Result r);
Result classify(Result r);
Result sign(Result r);

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Result.inlines.hh line 1
/* Result supporting functions implementation: inline functions.
*/


#include <cassert>

namespace Parma_Polyhedra_Library {

inline Result
classify(Result r) {
  return static_cast<Result>(r & VC_MASK);
}

inline bool
is_special(Result r) {
  return classify(r) != VC_NORMAL;
}

inline Result
sign(Result r) {
  switch (r) {
  case V_LT:
  case V_EQ:
  case V_GT:
  case VC_NAN:
    return r;
  case VC_MINUS_INFINITY:
    return V_LT;
  case VC_PLUS_INFINITY:
    return V_GT;
  default:
    assert(false);
    return VC_NAN;
  }
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Result.defs.hh line 117

// Automatically generated from PPL source file ../src/fpu.defs.hh line 1
/* Floating point unit related functions.
*/


// Automatically generated from PPL source file ../src/fpu.types.hh line 1


#ifdef HAVE_IEEEFP_H
#include <ieeefp.h>
#endif

namespace Parma_Polyhedra_Library {

typedef int fpu_rounding_direction_type;
typedef int fpu_rounding_control_word_type;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/fpu.defs.hh line 27

namespace Parma_Polyhedra_Library {

//! Returns the current FPU rounding direction.
fpu_rounding_direction_type
fpu_get_rounding_direction();

//! Sets the FPU rounding direction to \p dir.
void
fpu_set_rounding_direction(fpu_rounding_direction_type dir);

/*! \brief
  Sets the FPU rounding direction to \p dir and returns the rounding
  control word previously in use.
*/
fpu_rounding_control_word_type
fpu_save_rounding_direction(fpu_rounding_direction_type dir);

/*! \brief
  Sets the FPU rounding direction to \p dir, clears the <EM>inexact
  computation</EM> status, and returns the rounding control word
  previously in use.
*/
fpu_rounding_control_word_type
fpu_save_rounding_direction_reset_inexact(fpu_rounding_direction_type dir);

//! Restores the FPU rounding rounding control word to \p cw.
void
fpu_restore_rounding_direction(fpu_rounding_control_word_type w);

//! Clears the <EM>inexact computation</EM> status.
void
fpu_reset_inexact();

/*! \brief
  Queries the <EM>inexact computation</EM> status.

  Returns 0 if the computation was definitely exact, 1 if it was
  definitely inexact, -1 if definite exactness information is unavailable.
*/
int
fpu_check_inexact();

} // namespace Parma_Polyhedra_Library

#if defined(__i386__)
// Automatically generated from PPL source file ../src/fpu-ia32.inlines.hh line 1
/* ia32 floating point unit related functions.
*/

// Automatically generated from PPL source file ../src/fpu-ia32.inlines.hh line 24

#define FPU_INVALID      0x01
#define FPU_DIVBYZERO    0x04
#define FPU_OVERFLOW     0x08
#define FPU_UNDERFLOW    0x10
#define FPU_INEXACT      0x20

#define FPU_ALL_EXCEPT \
  (FPU_INEXACT | FPU_DIVBYZERO | FPU_UNDERFLOW | FPU_OVERFLOW | FPU_INVALID)

#define FPU_TONEAREST    0
#define FPU_DOWNWARD     0x400
#define FPU_UPWARD       0x800
#define FPU_TOWARDZERO   0xc00

#define FPU_ROUNDING_MASK 0xc00

#define PPL_FPU_CONTROL_DEFAULT_BASE 0x37f
// This MUST be congruent with the definition of ROUND_DIRECT
#define PPL_FPU_CONTROL_DEFAULT (PPL_FPU_CONTROL_DEFAULT_BASE | FPU_UPWARD)

namespace Parma_Polyhedra_Library {

typedef struct
{
  unsigned short control_word;
  unsigned short unused1;
  unsigned short status_word;
  unsigned short unused2;
  unsigned short tags;
  unsigned short unused3;
  unsigned int eip;
  unsigned short cs_selector;
  unsigned int opcode:11;
  unsigned int unused4:5;
  unsigned int data_offset;
  unsigned short data_selector;
  unsigned short unused5;
} ia32_fenv_t;

inline int
fpu_get_control() {
  unsigned short cw;
  __asm__ __volatile__ ("fnstcw %0" : "=m" (cw));
  return cw;
}

inline void
fpu_set_control(unsigned short cw) {
  __asm__ __volatile__ ("fldcw %0" : : "m" (cw));
}

inline int
fpu_get_status() {
  int sw;
  __asm__ __volatile__ ("fnstsw %0" : "=a" (sw));
  return sw;
}

inline void
fpu_clear_status(unsigned short bits) {
  /* There is no fldsw instruction */
  ia32_fenv_t env;
  __asm__ ("fnstenv %0" : "=m" (env));
  env.status_word &= ~bits;
  __asm__ ("fldenv %0" : : "m" (env));
}

inline void
fpu_clear_exceptions() {
  __asm__ __volatile__ ("fnclex" : /* No outputs.  */);
}

inline fpu_rounding_direction_type
fpu_get_rounding_direction() {
  return fpu_get_control() & FPU_ROUNDING_MASK;
}

inline void
fpu_set_rounding_direction(fpu_rounding_direction_type dir) {
  fpu_set_control(PPL_FPU_CONTROL_DEFAULT_BASE | dir);
}

inline fpu_rounding_control_word_type
fpu_save_rounding_direction(fpu_rounding_direction_type dir) {
  fpu_set_control(PPL_FPU_CONTROL_DEFAULT_BASE | dir);
  return 0;
}

inline void
fpu_reset_inexact() {
  fpu_clear_exceptions();
}

inline fpu_rounding_control_word_type
fpu_save_rounding_direction_reset_inexact(fpu_rounding_direction_type dir) {
  fpu_reset_inexact();
  return fpu_save_rounding_direction(dir);
}

inline void
fpu_restore_rounding_direction(fpu_rounding_control_word_type) {
  fpu_set_control(PPL_FPU_CONTROL_DEFAULT);
}

inline int
fpu_check_inexact() {
  return (fpu_get_status() & FPU_INEXACT) ? 1 : 0;
}

} // namespace Parma_Polyhedra_Library
// Automatically generated from PPL source file ../src/fpu.defs.hh line 74
#elif defined(HAVE_FENV_H)
// Automatically generated from PPL source file ../src/fpu-c99.inlines.hh line 1
/* C99 Floating point unit related functions.
*/

#ifdef HAVE_FENV_H
#include <fenv.h>

#ifdef FE_TONEAREST
#define FPU_TONEAREST FE_TONEAREST
#endif
#ifdef FE_UPWARD
#define FPU_UPWARD FE_UPWARD
#endif
#ifdef FE_DOWNWARD
#define FPU_DOWNWARD FE_DOWNWARD
#endif
#ifdef FE_TOWARDZERO
#define FPU_TOWARDZERO FE_TOWARDZERO
#endif

namespace Parma_Polyhedra_Library {

inline fpu_rounding_direction_type
fpu_get_rounding_direction() {
  return fegetround();
}

inline void
fpu_set_rounding_direction(fpu_rounding_direction_type dir) {
  fesetround(dir);
}

inline fpu_rounding_control_word_type
fpu_save_rounding_direction(fpu_rounding_direction_type dir) {
  fpu_rounding_direction_type old = fegetround();
  fesetround(dir);
  return old;
}

inline void
fpu_reset_inexact() {
  feclearexcept(FE_INEXACT);
}

inline fpu_rounding_control_word_type
fpu_save_rounding_direction_reset_inexact(fpu_rounding_direction_type dir) {
  fpu_reset_inexact();
  return fpu_save_rounding_direction(dir);
}

inline void
fpu_restore_rounding_direction(fpu_rounding_control_word_type w) {
  fesetround(w);
}

inline int
fpu_check_inexact() {
  return fetestexcept(FE_INEXACT) != 0;
}

} // namespace Parma_Polyhedra_Library

#endif // !defined(HAVE_FENV_H)
// Automatically generated from PPL source file ../src/fpu.defs.hh line 76
#elif defined(HAVE_IEEEFP_H)						\
  && (defined(__sparc)							\
      || defined(sparc)							\
      || defined(__sparc__))
// Automatically generated from PPL source file ../src/fpu-sparc.inlines.hh line 1
/* SPARC floating point unit related functions.
*/

#ifdef HAVE_IEEEFP_H
#include <ieeefp.h>

#define FPU_TONEAREST ((int) FP_RN)
#define FPU_UPWARD ((int) FP_RP)
#define FPU_DOWNWARD ((int) FP_RM)
#define FPU_TOWARDZERO ((int) FP_RZ)

namespace Parma_Polyhedra_Library {

inline fpu_rounding_direction_type
fpu_get_rounding_direction() {
  return fpgetround();
}

inline void
fpu_set_rounding_direction(fpu_rounding_direction_type dir) {
  fpsetround((fp_rnd) dir);
}

inline fpu_rounding_control_word_type
fpu_save_rounding_direction(fpu_rounding_direction_type dir) {
  return fpsetround((fp_rnd) dir);
}

inline void
fpu_reset_inexact() {
  fp_except except = fpgetmask();
  except &= ~FP_X_IMP;
  fpsetmask(except);
}

inline fpu_rounding_control_word_type
fpu_save_rounding_direction_reset_inexact(fpu_rounding_direction_type dir) {
  fpu_reset_inexact();
  return fpu_save_rounding_direction((fp_rnd) dir);
}

inline void
fpu_restore_rounding_direction(fpu_rounding_control_word_type w) {
  fpsetround((fp_rnd) w);
}

inline int
fpu_check_inexact() {
  return (fpgetmask() & FP_X_IMP) ? 1 : 0;
}

} // namespace Parma_Polyhedra_Library

#endif // !defined(HAVE_IEEEFP_H)
// Automatically generated from PPL source file ../src/fpu.defs.hh line 81
#else
// Automatically generated from PPL source file ../src/fpu-none.inlines.hh line 1
/* Null floating point unit related functions.
*/

#include <stdexcept>

namespace Parma_Polyhedra_Library {

inline int
fpu_get_rounding_direction() {
  throw std::logic_error("PPL::fpu_get_rounding_direction():"
			 " cannot control the FPU");
}

inline void
fpu_set_rounding_direction(int dir) {
  throw std::logic_error("PPL::fpu_set_rounding_direction():"
			 " cannot control the FPU");
}

inline int
fpu_save_rounding_direction(int dir) {
  throw std::logic_error("PPL::fpu_save_rounding_direction():"
			 " cannot control the FPU");
}

inline void
fpu_reset_inexact() {
  throw std::logic_error("PPL::fpu_reset_inexact():"
			 " cannot control the FPU");
}

inline int
fpu_save_rounding_direction_reset_inexact(int dir) {
  throw std::logic_error("PPL::fpu_save_rounding_direction_reset_inexact():"
			 " cannot control the FPU");
}

inline void
fpu_restore_rounding_direction(int dir) {
  throw std::logic_error("PPL::fpu_restore_rounding_direction():"
			 " cannot control the FPU");
}

inline int
fpu_check_inexact() {
  throw std::logic_error("PPL::fpu_check_inexact():"
			 " cannot control the FPU");
}

} // namespace Parma_Polyhedra_Library
// Automatically generated from PPL source file ../src/fpu.defs.hh line 83
#endif

// Automatically generated from PPL source file ../src/Rounding_Dir.defs.hh line 28

namespace Parma_Polyhedra_Library {

//! Rounding directions for arithmetic computations.
/*! \ingroup PPL_CXX_interface */
enum Rounding_Dir {
  /*! \hideinitializer
    Round toward \f$-\infty\f$.
  */
  ROUND_DOWN = FPU_DOWNWARD,

  /*! \hideinitializer
    Round toward \f$+\infty\f$.
  */
  ROUND_UP = FPU_UPWARD,

  /*! \hideinitializer
    Rounding is delegated to lower level. Result info is evaluated lazily.
  */
  ROUND_IGNORE = -1,
  ROUND_NATIVE = ROUND_IGNORE,

  /*! \hideinitializer
    Rounding is not needed: client code must ensure the operation is exact.
  */
  ROUND_NOT_NEEDED = -2,

  ROUND_DIRECT = ROUND_UP,
  ROUND_INVERSE = ROUND_DOWN
};

/*! \brief
  Returns the inverse rounding mode of \p dir,
  <CODE>ROUND_IGNORE</CODE> being the inverse of itself.
*/
Rounding_Dir inverse(Rounding_Dir dir);

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Rounding_Dir.inlines.hh line 1
/* Inline functions operating on enum Rounding_Dir values.
*/


// Automatically generated from PPL source file ../src/Rounding_Dir.inlines.hh line 27

namespace Parma_Polyhedra_Library {

/*! \relates Parma_Polyhedra_Library::Rounding_Dir */
inline Rounding_Dir
inverse(Rounding_Dir dir) {
  switch (dir) {
  case ROUND_UP:
    return ROUND_DOWN;
  case ROUND_DOWN:
    return ROUND_UP;
  case ROUND_IGNORE:
    return ROUND_IGNORE;
  default:
    assert(false);
    return ROUND_IGNORE;
  }
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Rounding_Dir.defs.hh line 68


// Automatically generated from PPL source file ../src/Numeric_Format.defs.hh line 1
/* Numeric format.
*/


// Automatically generated from PPL source file ../src/Numeric_Format.defs.hh line 28

namespace Parma_Polyhedra_Library {

class Numeric_Format {
};

} // namespace Parma_Polyhedra_Library


// Automatically generated from PPL source file ../src/checked.defs.hh line 30

namespace Parma_Polyhedra_Library {

namespace Checked {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A policy checking for overflows.
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
struct Check_Overflow_Policy {
  static const int check_overflow = 1;
  static const int check_inf_add_inf = 0;
  static const int check_inf_sub_inf = 0;
  static const int check_inf_mul_zero = 0;
  static const int check_div_zero = 0;
  static const int check_inf_div_inf = 0;
  static const int check_inf_mod = 0;
  static const int check_sqrt_neg = 0;
  static const int handle_nan = 0;
  static const int handle_infinity = 0;
  static const int convertible = 1;
  static const int fpu_check_inexact = 0;
  static const int check_nan_args = 1;
};

// It is a pity that function partial specialization is not permitted
// by C++.  To (partly) overcome this limitation, we use class
// encapsulated functions and partial specialization of containing
// classes.

#define FUNCTION_CLASS(name) name ## _function_struct

#define DECLARE_FUN1_0_0(name, ret_type, qual, type) \
template <typename Policy, typename type> \
struct FUNCTION_CLASS(name); \
template <typename Policy, typename type> \
inline ret_type name(qual type& arg) { \
  return FUNCTION_CLASS(name)<Policy, type>::function(arg); \
}

#define DECLARE_FUN1_0_1(name, ret_type, qual, type, after1) \
template <typename Policy, typename type> \
struct FUNCTION_CLASS(name); \
template <typename Policy, typename type> \
inline ret_type name(qual type& arg, after1 a1) { \
  return FUNCTION_CLASS(name)<Policy, type>::function(arg, a1); \
}

#define DECLARE_FUN1_0_2(name, ret_type, qual, type, after1, after2) \
template <typename Policy, typename type> \
struct FUNCTION_CLASS(name); \
template <typename Policy, typename type> \
inline ret_type name(qual type& arg, after1 a1, after2 a2) { \
  return FUNCTION_CLASS(name)<Policy, type>::function(arg, a1, a2); \
}

#define DECLARE_FUN1_0_3(name, ret_type, qual, type, after1, after2, after3) \
template <typename Policy, typename type> \
struct FUNCTION_CLASS(name); \
template <typename Policy, typename type> \
inline ret_type name(qual type& arg, after1 a1, after2 a2, after3 a3) { \
  return FUNCTION_CLASS(name)<Policy, type>::function(arg, a1, a2, a3); \
}

#define DECLARE_FUN1_1_1(name, ret_type, before1, qual, type, after1) \
template <typename Policy, typename type> \
struct FUNCTION_CLASS(name); \
template <typename Policy, typename type> \
inline ret_type name(before1 b1, qual type& arg, after1 a1) { \
  return FUNCTION_CLASS(name)<Policy, type>::function(b1, arg, a1); \
}

#define DECLARE_FUN1_1_2(name, ret_type, before1, qual, type, after1, after2) \
template <typename Policy, typename type> \
struct FUNCTION_CLASS(name); \
template <typename Policy, typename type> \
inline ret_type name(before1 b1, qual type& arg, after1 a1, after2 a2) { \
  return FUNCTION_CLASS(name)<Policy, type>::function(b1, arg, a1, a2); \
}

#define DECLARE_FUN1_2_2(name, ret_type, before1, before2, qual, type, after1, after2) \
template <typename Policy, typename type> \
struct FUNCTION_CLASS(name); \
template <typename Policy, typename type> \
inline ret_type name(before1 b1, before2 b2, qual type& arg, after1 a1, after2 a2) { \
  return FUNCTION_CLASS(name)<Policy, type>::function(b1, b2, arg, a1, a2); \
}

#define DECLARE_FUN2_0_0(name, ret_type, qual1, type1, qual2, type2) \
template <typename Policy, typename type1, typename type2> \
struct FUNCTION_CLASS(name); \
template <typename Policy, typename type1, typename type2> \
inline ret_type name(qual1 type1& arg1, qual2 type2& arg2) { \
  return FUNCTION_CLASS(name)<Policy, type1, type2>::function(arg1, arg2); \
}

#define DECLARE_FUN2_0_1(name, ret_type, qual1, type1, qual2, type2, after1) \
template <typename Policy, typename type1, typename type2> \
struct FUNCTION_CLASS(name); \
template <typename Policy, typename type1, typename type2> \
inline ret_type name(qual1 type1& arg1, qual2 type2& arg2, after1 a1) { \
  return FUNCTION_CLASS(name)<Policy, type1, type2>::function(arg1, arg2, a1); \
}

#define DECLARE_FUN2_0_2(name, ret_type, qual1, type1, qual2, type2, after1, after2) \
template <typename Policy, typename type1, typename type2> \
struct FUNCTION_CLASS(name); \
template <typename Policy, typename type1, typename type2> \
inline ret_type name(qual1 type1& arg1, qual2 type2& arg2, after1 a1, after2 a2) { \
  return FUNCTION_CLASS(name)<Policy, type1, type2>::function(arg1, arg2, a1, a2); \
}

#define DECLARE_FUN3_0_1(name, ret_type, qual1, type1, qual2, type2, qual3, type3, after1) \
template <typename Policy, typename type1, typename type2, typename type3> \
struct FUNCTION_CLASS(name); \
template <typename Policy, typename type1, typename type2, typename type3> \
inline ret_type name(qual1 type1& arg1, qual2 type2& arg2, qual3 type3& arg3, after1 a1) { \
  return FUNCTION_CLASS(name)<Policy, type1, type2, type3>::function(arg1, arg2, arg3, a1); \
}

#define DECLARE_FUN5_0_1(name, ret_type,				\
			 qual1, type1, qual2, type2, qual3, type3,	\
			 qual4, type4, qual5, type5,			\
			 after1)					\
template <typename Policy,						\
	  typename type1, typename type2, typename type3,		\
	  typename type4, typename type5>				\
struct FUNCTION_CLASS(name);						\
template <typename Policy,						\
	  typename type1, typename type2, typename type3,		\
	  typename type4, typename type5>				\
inline ret_type name(qual1 type1& arg1, qual2 type2& arg2,		\
		     qual3 type3& arg3, qual4 type4& arg4,		\
		     qual5 type5& arg5,	after1 a1) {			\
  return FUNCTION_CLASS(name)<Policy, type1, type2, type3, type4, type5> \
    ::function(arg1, arg2, arg3, arg4, arg5, a1);			\
}

#define SPECIALIZE_FUN1_0_0(name, suf, ret_type, qual, type) \
template <typename Policy> \
struct FUNCTION_CLASS(name)<Policy, type> { \
  static inline ret_type function(qual type& arg) { \
    return name ## _ ## suf<Policy>(arg); \
  } \
};

#define SPECIALIZE_FUN1_0_1(name, suf, ret_type, qual, type, after1) \
template <typename Policy> \
struct FUNCTION_CLASS(name)<Policy, type> { \
  static inline ret_type function(qual type& arg, after1 a1) { \
    return name ## _ ## suf<Policy>(arg, a1); \
  } \
};

#define SPECIALIZE_FUN1_0_2(name, suf, ret_type, qual, type, after1, after2) \
template <typename Policy> \
struct FUNCTION_CLASS(name)<Policy, type> { \
  static inline ret_type function(qual type& arg, after1 a1, after2 a2) { \
    return name ## _ ## suf<Policy>(arg, a1, a2); \
  } \
};

#define SPECIALIZE_FUN1_0_3(name, suf, ret_type, qual, type, after1, after2, after3) \
template <typename Policy> \
struct FUNCTION_CLASS(name)<Policy, type> { \
  static inline ret_type function(qual type& arg, after1 a1, after2 a2, after3 a3) { \
    return name ## _ ## suf<Policy>(arg, a1, a2, a3); \
  } \
};

#define SPECIALIZE_FUN1_1_1(name, suf, ret_type, before1, qual, type, after1) \
template <typename Policy> \
struct FUNCTION_CLASS(name)<Policy, type> { \
  static inline ret_type function(before1 b1, qual type& arg, after1 a1) { \
    return name ## _ ## suf<Policy>(b1, arg, a1); \
  } \
};

#define SPECIALIZE_FUN1_1_2(name, suf, ret_type, before1, qual, type, after1, after2) \
template <typename Policy> \
struct FUNCTION_CLASS(name)<Policy, type> { \
  static inline ret_type function(before1 b1, qual type& arg, after1 a1, after2 a2) { \
    return name ## _ ## suf<Policy>(b1, arg, a1, a2); \
  } \
};

#define SPECIALIZE_FUN1_2_2(name, suf, ret_type, before1, before2, qual, type, after1, after2) \
template <typename Policy> \
struct FUNCTION_CLASS(name)<Policy, type> { \
  static inline ret_type function(before1 b1, before2 b2, qual type& arg, after1 a1, after2 a2) { \
    return name ## _ ## suf<Policy>(b1, b2, arg, a1, a2); \
  } \
};

#define SPECIALIZE_FUN2_0_0(name, suf, ret_type, qual1, type1, qual2, type2) \
template <typename Policy> \
struct FUNCTION_CLASS(name)<Policy, type1, type2> { \
  static inline ret_type function(qual1 type1& arg1, qual2 type2 &arg2) { \
    return name ## _ ## suf<Policy>(arg1, arg2); \
  } \
};

#define SPECIALIZE_FUN2_0_1(name, suf, ret_type, qual1, type1, qual2, type2, after1) \
template <typename Policy> \
struct FUNCTION_CLASS(name)<Policy, type1, type2> { \
  static inline ret_type function(qual1 type1& arg1, qual2 type2 &arg2, after1 a1) { \
    return name ## _ ## suf<Policy>(arg1, arg2, a1); \
  } \
};

#define SPECIALIZE_FUN2_0_2(name, suf, ret_type, qual1, type1, qual2, type2, after1, after2) \
template <typename Policy> \
struct FUNCTION_CLASS(name)<Policy, type1, type2> { \
  static inline ret_type function(qual1 type1& arg1, qual2 type2 &arg2, after1 a1, after2 a2) { \
    return name ## _ ## suf<Policy>(arg1, arg2, a1, a2); \
  } \
};

#define SPECIALIZE_FUN3_0_1(name, suf, ret_type, qual1, type1, qual2, type2, qual3, type3, after1) \
template <typename Policy> \
struct FUNCTION_CLASS(name) <Policy, type1, type2, type3> { \
  static inline Result function(qual1 type1& arg1, qual2 type2 &arg2, qual3 type3 &arg3, after1 a1) { \
    return name ## _ ## suf<Policy>(arg1, arg2, arg3, a1); \
  } \
};

#define SPECIALIZE_FUN5_0_1(name, suf, ret_type,			\
			    qual1, type1, qual2, type2, qual3, type3,	\
			    qual4, type4, qual5, type5, after1)		\
template <typename Policy>						\
struct FUNCTION_CLASS(name) <Policy,					\
			     type1, type2, type3, type4, type5> {	\
  static inline Result							\
  function(qual1 type1& arg1, qual2 type2 &arg2, qual3 type3 &arg3,	\
	   qual4 type4 &arg4, qual5 type5 &arg5, after1 a1) {		\
    return name ## _ ## suf<Policy>(arg1, arg2, arg3, arg4, arg5, a1);	\
  }									\
};

#define nonconst

#define SPECIALIZE_COPY(suf, Type) \
  SPECIALIZE_FUN2_0_0(copy, suf, void, nonconst, Type, const, Type)
#define SPECIALIZE_SGN(suf, From) \
  SPECIALIZE_FUN1_0_0(sgn, suf, Result, const, From)
#define SPECIALIZE_CMP(suf, Type1, Type2) \
  SPECIALIZE_FUN2_0_0(cmp, suf, Result, const, Type1, const, Type2)
#define SPECIALIZE_SET_SPECIAL(suf, Type) \
  SPECIALIZE_FUN1_0_1(set_special, suf, Result, nonconst, Type, Result)
#define SPECIALIZE_CLASSIFY(suf, Type) \
  SPECIALIZE_FUN1_0_3(classify, suf, Result, const, Type, bool, bool, bool)
#define SPECIALIZE_IS_NAN(suf, Type) \
  SPECIALIZE_FUN1_0_0(is_nan, suf, bool, const, Type)
#define SPECIALIZE_IS_MINF(suf, Type) \
  SPECIALIZE_FUN1_0_0(is_minf, suf, bool, const, Type)
#define SPECIALIZE_IS_PINF(suf, Type) \
  SPECIALIZE_FUN1_0_0(is_pinf, suf, bool, const, Type)
#define SPECIALIZE_IS_INT(suf, Type) \
  SPECIALIZE_FUN1_0_0(is_int, suf, bool, const, Type)
#define SPECIALIZE_CONSTRUCT(suf, To, From) \
  SPECIALIZE_FUN2_0_1(construct, suf, Result, nonconst, To, const, From, Rounding_Dir)
#define SPECIALIZE_ASSIGN(suf, To, From) \
  SPECIALIZE_FUN2_0_1(assign, suf, Result, nonconst, To, const, From, Rounding_Dir)
#define SPECIALIZE_NEG(suf, To, From) \
  SPECIALIZE_FUN2_0_1(neg, suf, Result, nonconst, To, const, From, Rounding_Dir)
#define SPECIALIZE_ABS(suf, To, From) \
  SPECIALIZE_FUN2_0_1(abs, suf, Result, nonconst, To, const, From, Rounding_Dir)
#define SPECIALIZE_SQRT(suf, To, From) \
  SPECIALIZE_FUN2_0_1(sqrt, suf, Result, nonconst, To, const, From, Rounding_Dir)
#define SPECIALIZE_ADD(suf, To, From1, From2) \
  SPECIALIZE_FUN3_0_1(add, suf, Result, nonconst, To, const, From1, const, From2, Rounding_Dir)
#define SPECIALIZE_SUB(suf, To, From1, From2) \
  SPECIALIZE_FUN3_0_1(sub, suf, Result, nonconst, To, const, From1, const, From2, Rounding_Dir)
#define SPECIALIZE_MUL(suf, To, From1, From2) \
  SPECIALIZE_FUN3_0_1(mul, suf, Result, nonconst, To, const, From1, const, From2, Rounding_Dir)
#define SPECIALIZE_DIV(suf, To, From1, From2) \
  SPECIALIZE_FUN3_0_1(div, suf, Result, nonconst, To, const, From1, const, From2, Rounding_Dir)
#define SPECIALIZE_REM(suf, To, From1, From2) \
  SPECIALIZE_FUN3_0_1(rem, suf, Result, nonconst, To, const, From1, const, From2, Rounding_Dir)
#define SPECIALIZE_MUL2EXP(suf, To, From) \
  SPECIALIZE_FUN2_0_2(mul2exp, suf, Result, nonconst, To, const, From, int, Rounding_Dir)
#define SPECIALIZE_DIV2EXP(suf, To, From) \
  SPECIALIZE_FUN2_0_2(div2exp, suf, Result, nonconst, To, const, From, int, Rounding_Dir)
#define SPECIALIZE_ADD_MUL(suf, To, From1, From2) \
  SPECIALIZE_FUN3_0_1(add_mul, suf, Result, nonconst, To, const, From1, const, From2, Rounding_Dir)
#define SPECIALIZE_SUB_MUL(suf, To, From1, From2) \
  SPECIALIZE_FUN3_0_1(sub_mul, suf, Result, nonconst, To, const, From1, const, From2, Rounding_Dir)
#define SPECIALIZE_GCD(suf, To, From1, From2) \
  SPECIALIZE_FUN3_0_1(gcd, suf, Result, nonconst, To, const, From1, const, From2, Rounding_Dir)
#define SPECIALIZE_GCDEXT(suf, To1, From1, From2, To2, To3)		\
  SPECIALIZE_FUN5_0_1(gcdext, suf, Result, nonconst, To1,		\
		      const, From1, const, From2, nonconst, To2, nonconst, To3, Rounding_Dir)
#define SPECIALIZE_LCM(suf, To, From1, From2) \
  SPECIALIZE_FUN3_0_1(lcm, suf, Result, nonconst, To, const, From1, const, From2, Rounding_Dir)
#define SPECIALIZE_INPUT(suf, Type) \
  SPECIALIZE_FUN1_0_2(input, suf, Result, nonconst, Type, std::istream&, Rounding_Dir)
#define SPECIALIZE_OUTPUT(suf, Type) \
  SPECIALIZE_FUN1_1_2(output, suf, Result, std::ostream&, const, Type, const Numeric_Format&, Rounding_Dir)


DECLARE_FUN2_0_0(copy,        void, nonconst, Type1, const, Type2)
DECLARE_FUN1_0_0(sgn,         Result, const, From)
DECLARE_FUN2_0_0(cmp,         Result, const, Type1, const, Type2)
DECLARE_FUN1_0_1(set_special, Result, nonconst, Type, Result)
DECLARE_FUN1_0_3(classify,    Result, const, Type, bool, bool, bool)
DECLARE_FUN1_0_0(is_nan,      bool, const, Type)
DECLARE_FUN1_0_0(is_minf,     bool, const, Type)
DECLARE_FUN1_0_0(is_pinf,     bool, const, Type)
DECLARE_FUN1_0_0(is_int,      bool, const, Type)
DECLARE_FUN2_0_1(construct,   Result, nonconst, To, const, From, Rounding_Dir)
DECLARE_FUN2_0_1(assign,      Result, nonconst, To, const, From, Rounding_Dir)
DECLARE_FUN2_0_1(neg,         Result, nonconst, To, const, From, Rounding_Dir)
DECLARE_FUN2_0_1(abs,         Result, nonconst, To, const, From, Rounding_Dir)
DECLARE_FUN2_0_1(sqrt,        Result, nonconst, To, const, From, Rounding_Dir)
DECLARE_FUN3_0_1(add,         Result, nonconst, To, const, From1, const, From2, Rounding_Dir)
DECLARE_FUN3_0_1(sub,         Result, nonconst, To, const, From1, const, From2, Rounding_Dir)
DECLARE_FUN3_0_1(mul,         Result, nonconst, To, const, From1, const, From2, Rounding_Dir)
DECLARE_FUN3_0_1(div,         Result, nonconst, To, const, From1, const, From2, Rounding_Dir)
DECLARE_FUN3_0_1(rem,         Result, nonconst, To, const, From1, const, From2, Rounding_Dir)
DECLARE_FUN2_0_2(mul2exp,     Result, nonconst, To, const, From, int, Rounding_Dir)
DECLARE_FUN2_0_2(div2exp,     Result, nonconst, To, const, From, int, Rounding_Dir)
DECLARE_FUN3_0_1(add_mul,     Result, nonconst, To, const, From1, const, From2, Rounding_Dir)
DECLARE_FUN3_0_1(sub_mul,     Result, nonconst, To, const, From1, const, From2, Rounding_Dir)
DECLARE_FUN3_0_1(gcd,         Result, nonconst, To, const, From1, const, From2, Rounding_Dir)
DECLARE_FUN5_0_1(gcdext,      Result, nonconst, To1, const, From1, const, From2,
		                      nonconst, To2, nonconst, To3, Rounding_Dir)
DECLARE_FUN3_0_1(lcm,         Result, nonconst, To, const, From1, const, From2, Rounding_Dir)
DECLARE_FUN1_0_2(input,       Result, nonconst, Type, std::istream&, Rounding_Dir)
DECLARE_FUN1_1_2(output,      Result, std::ostream&, const, Type, const Numeric_Format&, Rounding_Dir)

template <typename Policy, typename To>
Result round(To& to, Result r, Rounding_Dir dir);

Result input_mpq(mpq_class& to, std::istream& is);

} // namespace Checked

struct Minus_Infinity {
};

struct Plus_Infinity {
};

struct Not_A_Number {
};

extern Minus_Infinity MINUS_INFINITY;
extern Plus_Infinity PLUS_INFINITY;
extern Not_A_Number NOT_A_NUMBER;

} // namespace Parma_Polyhedra_Library


#define CHECK_P(cond, check) ((cond) ? (check) : (assert(!(check)), false))

// Automatically generated from PPL source file ../src/checked.inlines.hh line 1
/* Abstract checked arithmetic functions: fall-backs.
*/

// Automatically generated from PPL source file ../src/globals.types.hh line 1


#include <cstddef>

namespace Parma_Polyhedra_Library {

//! An unsigned integral type for representing space dimensions.
/*! \ingroup PPL_CXX_interface */
typedef size_t dimension_type;

//! An unsigned integral type for representing memory size in bytes.
/*! \ingroup PPL_CXX_interface */
typedef size_t memory_size_type;

//! Kinds of degenerate abstract elements.
/*! \ingroup PPL_CXX_interface */
enum Degenerate_Element {
  //! The universe element, i.e., the whole vector space.
  UNIVERSE,
  //! The empty element, i.e., the empty set.
  EMPTY
};

//! Relation symbols.
/*! \ingroup PPL_CXX_interface */
enum Relation_Symbol {
  //! Less than.
  LESS_THAN,
  //! Less than or equal to.
  LESS_THAN_OR_EQUAL,
  //! Equal to.
  EQUAL,
  //! Greater than or equal to.
  GREATER_THAN_OR_EQUAL,
  //! Greater than.
  GREATER_THAN
};

//! Complexity pseudo-classes.
/*! \ingroup PPL_CXX_interface */
enum Complexity_Class {
  //! Worst-case polynomial complexity.
  POLYNOMIAL_COMPLEXITY,
  //! Worst-case exponential complexity but typically polynomial behavior.
  SIMPLEX_COMPLEXITY,
  //! Any complexity.
  ANY_COMPLEXITY
};

//! Possible optimization modes.
/*! \ingroup PPL_CXX_interface */
enum Optimization_Mode {
  //! Minimization is requested.
  MINIMIZATION,
  //! Maximization is requested.
  MAXIMIZATION
};

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/checked.inlines.hh line 25
#include <cassert>

namespace Parma_Polyhedra_Library {

namespace Checked {

template <typename Policy, typename Type>
struct FUNCTION_CLASS(construct)<Policy, Type, Type> {
  static inline Result function(Type& to, const Type& from, Rounding_Dir) {
    new (&to) Type(from);
    return V_EQ;
  }
};

template <typename Policy, typename To, typename From>
struct FUNCTION_CLASS(construct) {
  static inline Result function(To& to, const From& from, Rounding_Dir dir) {
    new (&to) To();
    return assign<Policy>(to, from, dir);
  }
};

template <typename Policy, typename Type>
struct FUNCTION_CLASS(assign)<Policy, Type, Type> {
  static inline Result function(Type& to, const Type& from, Rounding_Dir) {
    to = from;
    return V_EQ;
  }
};

template <typename Policy, typename Type>
inline void
copy_generic(Type& to, const Type& from) {
  to = from;
}

template <typename Policy, typename To, typename From>
inline Result
abs_generic(To& to, const From& from, Rounding_Dir dir) {
  if (from < 0)
    return neg<Policy>(to, from, dir);
  to = from;
  return V_EQ;
}

inline Result
neg(Result r) {
  assert(!is_special(r));
  Result ret = static_cast<Result>(r & V_EQ);
  if (r & V_LT)
    ret = static_cast<Result>(ret | V_GT);
  if (r & V_GT)
    ret = static_cast<Result>(ret | V_LT);
  return ret;
}

inline Result
add(Result r1, Result r2) {
  assert(!is_special(r1));
  assert(!is_special(r2));
  if (r1 == V_EQ)
    return r2;
  if (r2 == V_EQ)
    return r1;
  if (((r1 & V_LT) && (r2 & V_GT))
      || ((r1 & V_GT) && (r2 & V_LT)))
    return V_LGE;
  return static_cast<Result>((((r1 & r2) & V_EQ) ? V_EQ : 0) |
			       (r1 & (V_LT | V_GT)));
}

inline Result
sub(Result r1, Result r2) {
  return add(r1, neg(r2));
}

template <typename Policy, typename To, typename From>
inline void
gcd_exact_noabs(To& to, const From& x, const From& y) {
  To nx = x;
  To ny = y;
  To rm;
  while (ny != 0) {
    /* The following is derived from the assumption that x % y
       is always representable. This is true for both native integers
       and iec559 floating point numbers */
    rem<Policy>(rm, nx, ny, ROUND_NOT_NEEDED);
    nx = ny;
    ny = rm;
  }
  to = nx;
}

template <typename Policy, typename To, typename From1, typename From2>
inline Result
gcd_exact(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
  gcd_exact_noabs<Policy>(to, x, y);
  return abs<Policy>(to, to, dir);
}

template <typename Policy, typename To1,
	  typename From1, typename From2, typename To2, typename To3>
inline Result
gcdext_exact(To1& to, const From1& x, const From2& y, To2& s, To3& t,
	     Rounding_Dir dir) {
  if (y == 0) {
    if (x == 0) {
      s = 0;
      t = 1;
      return V_EQ;
    }
    else {
      if (x < 0)
	s = -1;
      else
	s = 1;
      t = 0;
      return abs<Policy>(to, x, dir);
    }
  }

  s = 1;
  t = 0;
  bool negative_x = x < 0;
  bool negative_y = y < 0;

  Result r;
  r = abs<Policy>(to, x, dir);
  if (r != V_EQ)
    return r;

  From2 ay;
  r = abs<Policy>(ay, y, dir);
  if (r != V_EQ)
    return r;

  // If COPY_GMP is defined then s is favoured when the absolute
  // values of the given numbers are equal.  For instance if x and y
  // are both 5 then s will be 1 and t will be 0, instead of the other
  // way round.  This is to match the behaviour of GMP.
#define COPY_GMP
#ifdef COPY_GMP
  if (to == ay)
    goto sign_check;
#endif

  {
    To2 v1 = 0;
    To3 v2 = 1;
    To1 v3 = static_cast<To1>(ay);
    while (true) {
      To1 q = to / v3;
      // Remainder, next candidate GCD.
      To1 t3 = to - q*v3;
      To2 t1 = s - static_cast<To2>(q)*v1;
      To3 t2 = t - static_cast<To3>(q)*v2;
      s = v1;
      t = v2;
      to = v3;
      if (t3 == 0)
	break;
      v1 = t1;
      v2 = t2;
      v3 = t3;
    }
  }

#ifdef COPY_GMP
 sign_check:
#endif
  if (negative_x) {
    r = neg<Policy>(s, s, dir);
    if (r != V_EQ)
      return r;
  }
  if (negative_y)
    return neg<Policy>(t, t, dir);
  return V_EQ;
}

template <typename Policy, typename To, typename From1, typename From2>
inline Result
lcm_gcd_exact(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
  if (x == 0 || y == 0) {
    to = 0;
    return V_EQ;
  }
  To nx, ny;
  Result r;
  r = abs<Policy>(nx, x, dir);
  if (r != V_EQ)
    return r;
  r = abs<Policy>(ny, y, dir);
  if (r != V_EQ)
    return r;
  To gcd;
  gcd_exact_noabs<Policy>(gcd, nx, ny);
  /* The following is derived from the assumption that x / gcd(x, y)
     is always representable. This is true for both native integers
     and iec559 floating point numbers */
  div<Policy>(to, nx, gcd, ROUND_NOT_NEEDED);
  return mul<Policy>(to, to, ny, dir);
}

template <typename Policy, typename Type>
inline Result
sgn_generic(const Type& x) {
  if (x > 0)
    return V_GT;
  if (x == 0)
    return V_EQ;
  return V_LT;
}

template <typename Policy, typename Type>
inline Result
cmp_generic(const Type& x, const Type& y) {
  if (x > y)
    return V_GT;
  if (x < y)
    return V_LT;
  return V_EQ;
}

template <typename Policy, typename Type>
inline Result
input_generic(Type& to, std::istream& is, Rounding_Dir dir) {
  mpq_class q;
  Result r = input_mpq(q, is);
  if (r == VC_MINUS_INFINITY)
    return assign<Policy>(to, MINUS_INFINITY, dir);
  if (r == VC_PLUS_INFINITY)
    return assign<Policy>(to, PLUS_INFINITY, dir);
  if (r == V_EQ)
    return assign<Policy>(to, q, dir);
  return set_special<Policy>(to, r);
}

template <typename T>
inline memory_size_type
external_memory_in_bytes(T) {
  return 0;
}

template <typename T>
inline memory_size_type
total_memory_in_bytes(T& x) {
  return sizeof(x) + external_memory_in_bytes(x);
}

} // namespace Checked

} // namespace Parma_Polyhedra_Library
// Automatically generated from PPL source file ../src/checked_int.inlines.hh line 1
/* Specialized "checked" functions for native integer numbers.
*/


// Automatically generated from PPL source file ../src/Limits.hh line 1
/* Limits for native integer types.
*/


#include <climits>

// C99 defines LLONG_MIN, LLONG_MAX and ULLONG_MAX, but this part of
// C99 is not yet included into the C++ standard.
// GCC defines LONG_LONG_MIN, LONG_LONG_MAX and ULONG_LONG_MAX.
// Some compilers (such as Comeau C++ up to and including version 4.3.3)
// define nothing.  In this last case we make a reasonable guess.
#ifndef LLONG_MIN
#if defined(LONG_LONG_MIN)
#define LLONG_MIN LONG_LONG_MIN
#elif SIZEOF_LONG_LONG == 8
#define LLONG_MIN 0x8000000000000000LL
#endif
#endif

#ifndef LLONG_MAX
#if defined(LONG_LONG_MAX)
#define LLONG_MAX LONG_LONG_MAX
#elif SIZEOF_LONG_LONG == 8
#define LLONG_MAX 0x7fffffffffffffffLL
#endif
#endif

#ifndef ULLONG_MAX
#if defined(ULONG_LONG_MAX)
#define ULLONG_MAX ULONG_LONG_MAX
#elif SIZEOF_UNSIGNED_LONG_LONG == 8
#define ULLONG_MAX 0xffffffffffffffffULL
#endif
#endif

namespace Parma_Polyhedra_Library {

/*
  The only reason to use these definitions instead of std::numeric_limits
  is a missing optimization in GCC 3.4.1.
*/

template <typename T>
struct Limits;

#define signed_limits(type, prefix) \
template <> \
struct Limits<type> { \
	static const type min = prefix ## _MIN; \
	static const type max = prefix ## _MAX; \
}

#define unsigned_limits(type, prefix) \
template <> \
struct Limits<type> { \
	static const type min = 0; \
	static const type max = prefix ## _MAX; \
}

signed_limits(signed char, SCHAR);
signed_limits(short, SHRT);
signed_limits(int, INT);
signed_limits(long, LONG);
signed_limits(long long, LLONG);

unsigned_limits(unsigned char, UCHAR);
unsigned_limits(unsigned short, USHRT);
unsigned_limits(unsigned int, UINT);
unsigned_limits(unsigned long, ULONG);
unsigned_limits(unsigned long long, ULLONG);

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/checked_int.inlines.hh line 27
#include <cerrno>
#include <cstdlib>
#include <climits>
#include <string>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif

#if !HAVE_DECL_STRTOLL
signed long long
strtoll(const char* nptr, char** endptr, int base);
#endif

#if !HAVE_DECL_STRTOULL
unsigned long long
strtoull(const char* nptr, char** endptr, int base);
#endif

namespace Parma_Polyhedra_Library {

namespace Checked {

#ifndef HAVE_INT_FAST16_T
typedef int16_t int_fast16_t;
#endif

#ifndef HAVE_INT_FAST32_T
typedef int32_t int_fast32_t;
#endif

#ifndef HAVE_INT_FAST64_T
typedef int64_t int_fast64_t;
#endif

#ifndef HAVE_UINT_FAST16_T
typedef uint16_t uint_fast16_t;
#endif

#ifndef HAVE_UINT_FAST32_T
typedef uint32_t uint_fast32_t;
#endif

#ifndef HAVE_UINT_FAST64_T
typedef uint64_t uint_fast64_t;
#endif

template <typename Policy, typename Type>
struct Extended_Int {
  static const Type plus_infinity = Limits<Type>::max;
  static const Type minus_infinity = (Limits<Type>::min >= 0
				      ? Limits<Type>::max - 1
				      : Limits<Type>::min);
  static const Type not_a_number = (Limits<Type>::min >= 0
				    ? Limits<Type>::max - Policy::handle_infinity * 2
				    : Limits<Type>::min + Policy::handle_infinity);
  static const Type min = (Limits<Type>::min
			   + (Limits<Type>::min >= 0 ? 0
			      : (Policy::handle_infinity + Policy::handle_nan)));
  static const Type max = (Limits<Type>::max
			   - (Limits<Type>::min >= 0
			      ? (2 * Policy::handle_infinity + Policy::handle_nan)
			      : Policy::handle_infinity));
};

template <typename Policy, typename To>
inline Result
set_neg_overflow_int(To& to, Rounding_Dir dir) {
  if (dir == ROUND_UP) {
    to = Extended_Int<Policy, To>::min;
    return V_LT;
  }
  else {
    if (Policy::handle_infinity) {
      to = Extended_Int<Policy, To>::minus_infinity;
      return V_GT;
    }
    return V_NEG_OVERFLOW;
  }
}

template <typename Policy, typename To>
inline Result
set_pos_overflow_int(To& to, Rounding_Dir dir) {
  if (dir == ROUND_DOWN) {
    to = Extended_Int<Policy, To>::max;
    return V_GT;
  }
  else {
    if (Policy::handle_infinity) {
      to = Extended_Int<Policy, To>::plus_infinity;
      return V_LT;
    }
    return V_POS_OVERFLOW;
  }
}

template <typename Policy, typename To>
inline Result
round_lt_int_no_overflow(To& to, Rounding_Dir dir) {
  if (dir == ROUND_DOWN) {
    to--;
    return V_GT;
  }
  return V_LT;
}

template <typename Policy, typename To>
inline Result
round_gt_int_no_overflow(To& to, Rounding_Dir dir) {
  if (dir == ROUND_UP) {
    to++;
    return V_LT;
  }
  return V_GT;
}

template <typename Policy, typename To>
inline Result
round_lt_int(To& to, Rounding_Dir dir) {
  if (dir == ROUND_DOWN) {
    if (to == Extended_Int<Policy, To>::min) {
      if (Policy::handle_infinity) {
	to = Extended_Int<Policy, To>::minus_infinity;
	return V_GT;
      }
      return V_NEG_OVERFLOW;
    } else {
      to--;
      return V_GT;
    }
  }
  return V_LT;
}

template <typename Policy, typename To>
inline Result
round_gt_int(To& to, Rounding_Dir dir) {
  if (dir == ROUND_UP) {
    if (to == Extended_Int<Policy, To>::max) {
      if (Policy::handle_infinity) {
	to = Extended_Int<Policy, To>::plus_infinity;
	return V_LT;
      }
      return V_POS_OVERFLOW;
    } else {
      to++;
      return V_LT;
    }
  }
  return V_GT;
}

SPECIALIZE_COPY(generic, signed char)
SPECIALIZE_COPY(generic, signed short)
SPECIALIZE_COPY(generic, signed int)
SPECIALIZE_COPY(generic, signed long)
SPECIALIZE_COPY(generic, signed long long)
SPECIALIZE_COPY(generic, unsigned char)
SPECIALIZE_COPY(generic, unsigned short)
SPECIALIZE_COPY(generic, unsigned int)
SPECIALIZE_COPY(generic, unsigned long)
SPECIALIZE_COPY(generic, unsigned long long)

template <typename Policy, typename Type>
inline Result
classify_int(const Type v, bool nan, bool inf, bool sign) {
  if (Policy::handle_nan
      && (nan || sign)
      && v == Extended_Int<Policy, Type>::not_a_number)
    return VC_NAN;
  if (!inf & !sign)
    return VC_NORMAL;
  if (Policy::handle_infinity) {
    if (v == Extended_Int<Policy, Type>::minus_infinity)
      return inf ? VC_MINUS_INFINITY : V_LT;
    if (v == Extended_Int<Policy, Type>::plus_infinity)
      return inf ? VC_PLUS_INFINITY : V_GT;
  }
  if (sign) {
    if (v < 0)
      return V_LT;
    if (v > 0)
      return V_GT;
    return V_EQ;
  }
  return VC_NORMAL;
}

SPECIALIZE_CLASSIFY(int, signed char)
SPECIALIZE_CLASSIFY(int, signed short)
SPECIALIZE_CLASSIFY(int, signed int)
SPECIALIZE_CLASSIFY(int, signed long)
SPECIALIZE_CLASSIFY(int, signed long long)
SPECIALIZE_CLASSIFY(int, unsigned char)
SPECIALIZE_CLASSIFY(int, unsigned short)
SPECIALIZE_CLASSIFY(int, unsigned int)
SPECIALIZE_CLASSIFY(int, unsigned long)
SPECIALIZE_CLASSIFY(int, unsigned long long)

template <typename Policy, typename Type>
inline bool
is_nan_int(const Type v) {
  return Policy::handle_nan && v == Extended_Int<Policy, Type>::not_a_number;
}

SPECIALIZE_IS_NAN(int, signed char)
SPECIALIZE_IS_NAN(int, signed short)
SPECIALIZE_IS_NAN(int, signed int)
SPECIALIZE_IS_NAN(int, signed long)
SPECIALIZE_IS_NAN(int, signed long long)
SPECIALIZE_IS_NAN(int, unsigned char)
SPECIALIZE_IS_NAN(int, unsigned short)
SPECIALIZE_IS_NAN(int, unsigned int)
SPECIALIZE_IS_NAN(int, unsigned long)
SPECIALIZE_IS_NAN(int, unsigned long long)

template <typename Policy, typename Type>
inline bool
is_minf_int(const Type v) {
  return Policy::handle_infinity
    && v == Extended_Int<Policy, Type>::minus_infinity;
}

SPECIALIZE_IS_MINF(int, signed char)
SPECIALIZE_IS_MINF(int, signed short)
SPECIALIZE_IS_MINF(int, signed int)
SPECIALIZE_IS_MINF(int, signed long)
SPECIALIZE_IS_MINF(int, signed long long)
SPECIALIZE_IS_MINF(int, unsigned char)
SPECIALIZE_IS_MINF(int, unsigned short)
SPECIALIZE_IS_MINF(int, unsigned int)
SPECIALIZE_IS_MINF(int, unsigned long)
SPECIALIZE_IS_MINF(int, unsigned long long)

template <typename Policy, typename Type>
inline bool
is_pinf_int(const Type v) {
  return Policy::handle_infinity
    && v == Extended_Int<Policy, Type>::plus_infinity;
}

SPECIALIZE_IS_PINF(int, signed char)
SPECIALIZE_IS_PINF(int, signed short)
SPECIALIZE_IS_PINF(int, signed int)
SPECIALIZE_IS_PINF(int, signed long)
SPECIALIZE_IS_PINF(int, signed long long)
SPECIALIZE_IS_PINF(int, unsigned char)
SPECIALIZE_IS_PINF(int, unsigned short)
SPECIALIZE_IS_PINF(int, unsigned int)
SPECIALIZE_IS_PINF(int, unsigned long)
SPECIALIZE_IS_PINF(int, unsigned long long)

template <typename Policy, typename Type>
inline bool
is_int_int(const Type v) {
  return !is_nan<Policy>(v);
}

SPECIALIZE_IS_INT(int, signed char)
SPECIALIZE_IS_INT(int, signed short)
SPECIALIZE_IS_INT(int, signed int)
SPECIALIZE_IS_INT(int, signed long)
SPECIALIZE_IS_INT(int, signed long long)
SPECIALIZE_IS_INT(int, unsigned char)
SPECIALIZE_IS_INT(int, unsigned short)
SPECIALIZE_IS_INT(int, unsigned int)
SPECIALIZE_IS_INT(int, unsigned long)
SPECIALIZE_IS_INT(int, unsigned long long)

template <typename Policy, typename Type>
inline Result
set_special_int(Type& v, Result r) {
  Result t = classify(r);
  if (Policy::handle_nan && t == VC_NAN)
    v = Extended_Int<Policy, Type>::not_a_number;
  else if (Policy::handle_infinity) {
    switch (t) {
    case VC_MINUS_INFINITY:
      v = Extended_Int<Policy, Type>::minus_infinity;
      break;
    case VC_PLUS_INFINITY:
      v = Extended_Int<Policy, Type>::plus_infinity;
      break;
    default:
      break;
    }
  }
  return r;
}

SPECIALIZE_SET_SPECIAL(int, signed char)
SPECIALIZE_SET_SPECIAL(int, signed short)
SPECIALIZE_SET_SPECIAL(int, signed int)
SPECIALIZE_SET_SPECIAL(int, signed long)
SPECIALIZE_SET_SPECIAL(int, signed long long)
SPECIALIZE_SET_SPECIAL(int, unsigned char)
SPECIALIZE_SET_SPECIAL(int, unsigned short)
SPECIALIZE_SET_SPECIAL(int, unsigned int)
SPECIALIZE_SET_SPECIAL(int, unsigned long)
SPECIALIZE_SET_SPECIAL(int, unsigned long long)

template <typename Policy, typename To, typename From>
inline Result
assign_signed_int_signed_int(To& to, const From from, Rounding_Dir dir) {
  if (sizeof(To) <= sizeof(From)) {
    if (CHECK_P(Policy::check_overflow,
		from < static_cast<From>(Extended_Int<Policy, To>::min)))
      return set_neg_overflow_int<Policy>(to, dir);
    if (CHECK_P(Policy::check_overflow,
		from > static_cast<From>(Extended_Int<Policy, To>::max)))
      return set_pos_overflow_int<Policy>(to, dir);
  }
  to = To(from);
  return V_EQ;
}

template <typename Policy, typename To, typename From>
inline Result
assign_signed_int_unsigned_int(To& to, const From from, Rounding_Dir dir) {
  if (sizeof(To) <= sizeof(From)) {
    if (CHECK_P(Policy::check_overflow,
		from > static_cast<From>(Extended_Int<Policy, To>::max)))
      return set_pos_overflow_int<Policy>(to, dir);
  }
  to = To(from);
  return V_EQ;
}

template <typename Policy, typename To, typename From>
inline Result
assign_unsigned_int_signed_int(To& to, const From from, Rounding_Dir dir) {
  if (CHECK_P(Policy::check_overflow, from < 0))
    return set_neg_overflow_int<Policy>(to, dir);
  if (sizeof(To) < sizeof(From)) {
    if (CHECK_P(Policy::check_overflow,
		from > static_cast<From>(Extended_Int<Policy, To>::max)))
      return set_pos_overflow_int<Policy>(to, dir);
  }
  to = To(from);
  return V_EQ;
}

template <typename Policy, typename To, typename From>
inline Result
assign_unsigned_int_unsigned_int(To& to, const From from, Rounding_Dir dir) {
  if (sizeof(To) <= sizeof(From)) {
    if (CHECK_P(Policy::check_overflow,
		from > static_cast<From>(Extended_Int<Policy, To>::max)))
      return set_pos_overflow_int<Policy>(to, dir);
  }
  to = To(from);
  return V_EQ;
}


#define ASSIGN2_SIGNED_SIGNED(Smaller, Larger) \
SPECIALIZE_ASSIGN(signed_int_signed_int, Smaller, Larger) \
SPECIALIZE_ASSIGN(signed_int_signed_int, Larger, Smaller)

#define ASSIGN2_UNSIGNED_UNSIGNED(Smaller, Larger) \
SPECIALIZE_ASSIGN(unsigned_int_unsigned_int, Smaller, Larger) \
SPECIALIZE_ASSIGN(unsigned_int_unsigned_int, Larger, Smaller)

#define ASSIGN2_UNSIGNED_SIGNED(Smaller, Larger) \
SPECIALIZE_ASSIGN(unsigned_int_signed_int, Smaller, Larger) \
SPECIALIZE_ASSIGN(signed_int_unsigned_int, Larger, Smaller)

#define ASSIGN2_SIGNED_UNSIGNED(Smaller, Larger) \
SPECIALIZE_ASSIGN(signed_int_unsigned_int, Smaller, Larger) \
SPECIALIZE_ASSIGN(unsigned_int_signed_int, Larger, Smaller)

#define ASSIGN_SIGNED(Type) \
SPECIALIZE_ASSIGN(signed_int_signed_int, Type, Type)
#define ASSIGN_UNSIGNED(Type) \
SPECIALIZE_ASSIGN(unsigned_int_unsigned_int, Type, Type)

ASSIGN_SIGNED(signed char)
ASSIGN_SIGNED(signed short)
ASSIGN_SIGNED(signed int)
ASSIGN_SIGNED(signed long)
ASSIGN_SIGNED(signed long long)
ASSIGN_UNSIGNED(unsigned char)
ASSIGN_UNSIGNED(unsigned short)
ASSIGN_UNSIGNED(unsigned int)
ASSIGN_UNSIGNED(unsigned long)
ASSIGN_UNSIGNED(unsigned long long)

ASSIGN2_SIGNED_SIGNED(signed char, signed short)
ASSIGN2_SIGNED_SIGNED(signed char, signed int)
ASSIGN2_SIGNED_SIGNED(signed char, signed long)
ASSIGN2_SIGNED_SIGNED(signed char, signed long long)
ASSIGN2_SIGNED_SIGNED(signed short, signed int)
ASSIGN2_SIGNED_SIGNED(signed short, signed long)
ASSIGN2_SIGNED_SIGNED(signed short, signed long long)
ASSIGN2_SIGNED_SIGNED(signed int, signed long)
ASSIGN2_SIGNED_SIGNED(signed int, signed long long)
ASSIGN2_SIGNED_SIGNED(signed long, signed long long)
ASSIGN2_UNSIGNED_UNSIGNED(unsigned char, unsigned short)
ASSIGN2_UNSIGNED_UNSIGNED(unsigned char, unsigned int)
ASSIGN2_UNSIGNED_UNSIGNED(unsigned char, unsigned long)
ASSIGN2_UNSIGNED_UNSIGNED(unsigned char, unsigned long long)
ASSIGN2_UNSIGNED_UNSIGNED(unsigned short, unsigned int)
ASSIGN2_UNSIGNED_UNSIGNED(unsigned short, unsigned long)
ASSIGN2_UNSIGNED_UNSIGNED(unsigned short, unsigned long long)
ASSIGN2_UNSIGNED_UNSIGNED(unsigned int, unsigned long)
ASSIGN2_UNSIGNED_UNSIGNED(unsigned int, unsigned long long)
ASSIGN2_UNSIGNED_UNSIGNED(unsigned long, unsigned long long)
ASSIGN2_UNSIGNED_SIGNED(unsigned char, signed short)
ASSIGN2_UNSIGNED_SIGNED(unsigned char, signed int)
ASSIGN2_UNSIGNED_SIGNED(unsigned char, signed long)
ASSIGN2_UNSIGNED_SIGNED(unsigned char, signed long long)
ASSIGN2_UNSIGNED_SIGNED(unsigned short, signed int)
ASSIGN2_UNSIGNED_SIGNED(unsigned short, signed long)
ASSIGN2_UNSIGNED_SIGNED(unsigned short, signed long long)
ASSIGN2_UNSIGNED_SIGNED(unsigned int, signed long)
ASSIGN2_UNSIGNED_SIGNED(unsigned int, signed long long)
ASSIGN2_UNSIGNED_SIGNED(unsigned long, signed long long)
ASSIGN2_SIGNED_UNSIGNED(signed char, unsigned char)
ASSIGN2_SIGNED_UNSIGNED(signed char, unsigned short)
ASSIGN2_SIGNED_UNSIGNED(signed char, unsigned int)
ASSIGN2_SIGNED_UNSIGNED(signed char, unsigned long)
ASSIGN2_SIGNED_UNSIGNED(signed char, unsigned long long)
ASSIGN2_SIGNED_UNSIGNED(signed short, unsigned short)
ASSIGN2_SIGNED_UNSIGNED(signed short, unsigned int)
ASSIGN2_SIGNED_UNSIGNED(signed short, unsigned long)
ASSIGN2_SIGNED_UNSIGNED(signed short, unsigned long long)
ASSIGN2_SIGNED_UNSIGNED(signed int, unsigned int)
ASSIGN2_SIGNED_UNSIGNED(signed int, unsigned long)
ASSIGN2_SIGNED_UNSIGNED(signed int, unsigned long long)
ASSIGN2_SIGNED_UNSIGNED(signed long, unsigned long)
ASSIGN2_SIGNED_UNSIGNED(signed long, unsigned long long)
ASSIGN2_SIGNED_UNSIGNED(signed long long, unsigned long long)

template <typename Policy, typename To, typename From>
inline Result
assign_int_float(To& to, const From from, Rounding_Dir dir) {
  if (CHECK_P(Policy::check_overflow, (from < Extended_Int<Policy, To>::min)))
    return set_neg_overflow_int<Policy>(to, dir);
  if (CHECK_P(Policy::check_overflow, (from > Extended_Int<Policy, To>::max)))
    return set_pos_overflow_int<Policy>(to, dir);
  to = static_cast<To>(from);
  if (dir == ROUND_IGNORE)
    return V_LGE;
  if (from < to)
    return round_lt_int<Policy>(to, dir);
  else if (from > to)
    return round_gt_int<Policy>(to, dir);
  else
    return V_EQ;
}

SPECIALIZE_ASSIGN(int_float, signed char, float)
SPECIALIZE_ASSIGN(int_float, signed short, float)
SPECIALIZE_ASSIGN(int_float, signed int, float)
SPECIALIZE_ASSIGN(int_float, signed long, float)
SPECIALIZE_ASSIGN(int_float, signed long long, float)
SPECIALIZE_ASSIGN(int_float, unsigned char, float)
SPECIALIZE_ASSIGN(int_float, unsigned short, float)
SPECIALIZE_ASSIGN(int_float, unsigned int, float)
SPECIALIZE_ASSIGN(int_float, unsigned long, float)
SPECIALIZE_ASSIGN(int_float, unsigned long long, float)

SPECIALIZE_ASSIGN(int_float, signed char, double)
SPECIALIZE_ASSIGN(int_float, signed short, double)
SPECIALIZE_ASSIGN(int_float, signed int, double)
SPECIALIZE_ASSIGN(int_float, signed long, double)
SPECIALIZE_ASSIGN(int_float, signed long long, double)
SPECIALIZE_ASSIGN(int_float, unsigned char, double)
SPECIALIZE_ASSIGN(int_float, unsigned short, double)
SPECIALIZE_ASSIGN(int_float, unsigned int, double)
SPECIALIZE_ASSIGN(int_float, unsigned long, double)
SPECIALIZE_ASSIGN(int_float, unsigned long long, double)

SPECIALIZE_ASSIGN(int_float, signed char, long double)
SPECIALIZE_ASSIGN(int_float, signed short, long double)
SPECIALIZE_ASSIGN(int_float, signed int, long double)
SPECIALIZE_ASSIGN(int_float, signed long, long double)
SPECIALIZE_ASSIGN(int_float, signed long long, long double)
SPECIALIZE_ASSIGN(int_float, unsigned char, long double)
SPECIALIZE_ASSIGN(int_float, unsigned short, long double)
SPECIALIZE_ASSIGN(int_float, unsigned int, long double)
SPECIALIZE_ASSIGN(int_float, unsigned long, long double)
SPECIALIZE_ASSIGN(int_float, unsigned long long, long double)

#undef ASSIGN2_SIGNED_SIGNED
#undef ASSIGN2_UNSIGNED_UNSIGNED
#undef ASSIGN2_UNSIGNED_SIGNED
#undef ASSIGN2_SIGNED_UNSIGNED

template <typename Policy, typename To>
inline Result
assign_signed_int_mpz(To& to, const mpz_class& from, Rounding_Dir dir) {
  if (sizeof(To) <= sizeof(signed long)) {
    if (!Policy::check_overflow) {
      to = from.get_si();
      return V_EQ;
    }
    if (from.fits_slong_p()) {
      signed long v = from.get_si();
      if (v < Limits<To>::min)
	return set_neg_overflow_int<Policy>(to, dir);
      if (v > Limits<To>::max)
	return set_pos_overflow_int<Policy>(to, dir);
      to = v;
      return V_EQ;
    }
  }
  else {
    mpz_srcptr m = from.get_mpz_t();
    size_t sz = mpz_size(m);
    if (sz <= sizeof(To) / sizeof(mp_limb_t)) {
      if (sz == 0) {
	to = 0;
	return V_EQ;
      }
      To v;
      mpz_export(&v, 0, -1, sizeof(To), 0, 0, m);
      if (v >= 0) {
	if (::sgn(from) < 0)
	  return neg<Policy>(to, v, dir);
	to = v;
	return V_EQ;
      }
    }
  }
  return ::sgn(from) < 0
    ? set_neg_overflow_int<Policy>(to, dir)
    : set_pos_overflow_int<Policy>(to, dir);
}

SPECIALIZE_ASSIGN(signed_int_mpz, signed char, mpz_class)
SPECIALIZE_ASSIGN(signed_int_mpz, signed short, mpz_class)
SPECIALIZE_ASSIGN(signed_int_mpz, signed int, mpz_class)
SPECIALIZE_ASSIGN(signed_int_mpz, signed long, mpz_class)
SPECIALIZE_ASSIGN(signed_int_mpz, signed long long, mpz_class)

template <typename Policy, typename To>
inline Result
assign_unsigned_int_mpz(To& to, const mpz_class& from, Rounding_Dir dir) {
  if (CHECK_P(Policy::check_overflow, ::sgn(from) < 0))
    return set_neg_overflow_int<Policy>(to, dir);
  if (sizeof(To) <= sizeof(unsigned long)) {
    if (!Policy::check_overflow) {
      to = from.get_ui();
      return V_EQ;
    }
    if (from.fits_ulong_p()) {
      unsigned long v = from.get_ui();
      if (v > Limits<To>::max)
	return set_pos_overflow_int<Policy>(to, dir);
      to = v;
      return V_EQ;
    }
  }
  else {
    mpz_srcptr m = from.get_mpz_t();
    size_t sz = mpz_size(m);
    if (sz <= sizeof(To) / sizeof(mp_limb_t)) {
      if (sz == 0)
	to = 0;
      else
	mpz_export(&to, 0, -1, sizeof(To), 0, 0, m);
      return V_EQ;
    }
  }
  return set_pos_overflow_int<Policy>(to, dir);
}

SPECIALIZE_ASSIGN(unsigned_int_mpz, unsigned char, mpz_class)
SPECIALIZE_ASSIGN(unsigned_int_mpz, unsigned short, mpz_class)
SPECIALIZE_ASSIGN(unsigned_int_mpz, unsigned int, mpz_class)
SPECIALIZE_ASSIGN(unsigned_int_mpz, unsigned long, mpz_class)
SPECIALIZE_ASSIGN(unsigned_int_mpz, unsigned long long, mpz_class)

template <typename Policy, typename To>
inline Result
assign_int_mpq(To& to, const mpq_class& from, Rounding_Dir dir) {
  mpz_srcptr n = from.get_num().get_mpz_t();
  mpz_srcptr d = from.get_den().get_mpz_t();
  mpz_class q;
  mpz_ptr _q = q.get_mpz_t();
  if (dir == ROUND_IGNORE) {
    mpz_tdiv_q(_q, n, d);
    Result r = assign<Policy>(to, q, dir);
    if (r != V_EQ)
      return r;
    return V_LGE;
  }
  mpz_t rem;
  int sign;
  mpz_init(rem);
  mpz_tdiv_qr(_q, rem, n, d);
  sign = mpz_sgn(rem);
  mpz_clear(rem);
  Result r = assign<Policy>(to, q, dir);
  if (r != V_EQ)
    return r;
  switch (sign) {
  case -1:
    return round_lt_int<Policy>(to, dir);
  case 1:
    return round_gt_int<Policy>(to, dir);
  default:
    return V_EQ;
  }
}

SPECIALIZE_ASSIGN(int_mpq, signed char, mpq_class)
SPECIALIZE_ASSIGN(int_mpq, signed short, mpq_class)
SPECIALIZE_ASSIGN(int_mpq, signed int, mpq_class)
SPECIALIZE_ASSIGN(int_mpq, signed long, mpq_class)
SPECIALIZE_ASSIGN(int_mpq, signed long long, mpq_class)
SPECIALIZE_ASSIGN(int_mpq, unsigned char, mpq_class)
SPECIALIZE_ASSIGN(int_mpq, unsigned short, mpq_class)
SPECIALIZE_ASSIGN(int_mpq, unsigned int, mpq_class)
SPECIALIZE_ASSIGN(int_mpq, unsigned long, mpq_class)
SPECIALIZE_ASSIGN(int_mpq, unsigned long long, mpq_class)

template <typename Policy, typename To>
inline Result
assign_int_minf(To& to, const Minus_Infinity&, Rounding_Dir dir) {
  if (Policy::handle_infinity) {
    to = Extended_Int<Policy, To>::minus_infinity;
    return V_EQ;
  }
  if (dir == ROUND_UP) {
    to = Extended_Int<Policy, To>::min;
    return V_LT;
  }
  return VC_MINUS_INFINITY;
}

template <typename Policy, typename To>
inline Result
assign_int_pinf(To& to, const Plus_Infinity&, Rounding_Dir dir) {
  if (Policy::handle_infinity) {
    to = Extended_Int<Policy, To>::plus_infinity;
    return V_EQ;
  }
  if (dir == ROUND_DOWN) {
    to = Extended_Int<Policy, To>::max;
    return V_GT;
  }
  return VC_PLUS_INFINITY;
}

template <typename Policy, typename To>
inline Result
assign_int_nan(To& to, const Not_A_Number&, Rounding_Dir) {
  if (Policy::handle_nan) {
    to = Extended_Int<Policy, To>::not_a_number;
    return V_EQ;
  }
  return VC_NAN;
}

SPECIALIZE_ASSIGN(int_minf, signed char, Minus_Infinity)
SPECIALIZE_ASSIGN(int_minf, signed short, Minus_Infinity)
SPECIALIZE_ASSIGN(int_minf, signed int, Minus_Infinity)
SPECIALIZE_ASSIGN(int_minf, signed long, Minus_Infinity)
SPECIALIZE_ASSIGN(int_minf, signed long long, Minus_Infinity)
SPECIALIZE_ASSIGN(int_minf, unsigned char, Minus_Infinity)
SPECIALIZE_ASSIGN(int_minf, unsigned short, Minus_Infinity)
SPECIALIZE_ASSIGN(int_minf, unsigned int, Minus_Infinity)
SPECIALIZE_ASSIGN(int_minf, unsigned long, Minus_Infinity)
SPECIALIZE_ASSIGN(int_minf, unsigned long long, Minus_Infinity)

SPECIALIZE_ASSIGN(int_pinf, signed char, Plus_Infinity)
SPECIALIZE_ASSIGN(int_pinf, signed short, Plus_Infinity)
SPECIALIZE_ASSIGN(int_pinf, signed int, Plus_Infinity)
SPECIALIZE_ASSIGN(int_pinf, signed long, Plus_Infinity)
SPECIALIZE_ASSIGN(int_pinf, signed long long, Plus_Infinity)
SPECIALIZE_ASSIGN(int_pinf, unsigned char, Plus_Infinity)
SPECIALIZE_ASSIGN(int_pinf, unsigned short, Plus_Infinity)
SPECIALIZE_ASSIGN(int_pinf, unsigned int, Plus_Infinity)
SPECIALIZE_ASSIGN(int_pinf, unsigned long, Plus_Infinity)
SPECIALIZE_ASSIGN(int_pinf, unsigned long long, Plus_Infinity)

SPECIALIZE_ASSIGN(int_nan, signed char, Not_A_Number)
SPECIALIZE_ASSIGN(int_nan, signed short, Not_A_Number)
SPECIALIZE_ASSIGN(int_nan, signed int, Not_A_Number)
SPECIALIZE_ASSIGN(int_nan, signed long, Not_A_Number)
SPECIALIZE_ASSIGN(int_nan, signed long long, Not_A_Number)
SPECIALIZE_ASSIGN(int_nan, unsigned char, Not_A_Number)
SPECIALIZE_ASSIGN(int_nan, unsigned short, Not_A_Number)
SPECIALIZE_ASSIGN(int_nan, unsigned int, Not_A_Number)
SPECIALIZE_ASSIGN(int_nan, unsigned long, Not_A_Number)
SPECIALIZE_ASSIGN(int_nan, unsigned long long, Not_A_Number)

#if UCHAR_MAX == 0xff
#define CHAR_BITS 8
#else
#error "Unexpected max for unsigned char"
#endif

#if USHRT_MAX == 0xffff
#define SHRT_BITS 16
#else
#error "Unexpected max for unsigned short"
#endif

#if UINT_MAX == 0xffffffff
#define INT_BITS 32
#else
#error "Unexpected max for unsigned int"
#endif

#if ULONG_MAX == 0xffffffffUL
#define LONG_BITS 32
#elif ULONG_MAX == 0xffffffffffffffffULL
#define LONG_BITS 64
#else
#error "Unexpected max for unsigned long"
#endif

#if ULLONG_MAX == 0xffffffffffffffffULL
#define LONG_LONG_BITS 64
#else
#error "Unexpected max for unsigned long long"
#endif


template <typename T>
struct Larger;

// The following may be tuned for performance on specific architecture.
//
// Current guidelines:
//   - avoid division where possible (larger type variant for mul)
//   - use larger type variant for types smaller than architecture bit size

template <>
struct Larger<signed char> {
  static const bool use_for_neg = true;
  static const bool use_for_add = true;
  static const bool use_for_sub = true;
  static const bool use_for_mul = true;
  typedef int_fast16_t Type_For_Neg;
  typedef int_fast16_t  Type_For_Add;
  typedef int_fast16_t  Type_For_Sub;
  typedef int_fast16_t  Type_For_Mul;
};

template <>
struct Larger<unsigned char> {
  static const bool use_for_neg = true;
  static const bool use_for_add = true;
  static const bool use_for_sub = true;
  static const bool use_for_mul = true;
  typedef int_fast16_t Type_For_Neg;
  typedef uint_fast16_t Type_For_Add;
  typedef int_fast16_t Type_For_Sub;
  typedef uint_fast16_t Type_For_Mul;
};

template <>
struct Larger<signed short> {
  static const bool use_for_neg = true;
  static const bool use_for_add = true;
  static const bool use_for_sub = true;
  static const bool use_for_mul = true;
  typedef int_fast32_t Type_For_Neg;
  typedef int_fast32_t Type_For_Add;
  typedef int_fast32_t Type_For_Sub;
  typedef int_fast32_t Type_For_Mul;
};

template <>
struct Larger<unsigned short> {
  static const bool use_for_neg = true;
  static const bool use_for_add = true;
  static const bool use_for_sub = true;
  static const bool use_for_mul = true;
  typedef int_fast32_t Type_For_Neg;
  typedef uint_fast32_t Type_For_Add;
  typedef int_fast32_t Type_For_Sub;
  typedef uint_fast32_t Type_For_Mul;
};

template <>
struct Larger<signed int> {
  static const bool use_for_neg = (LONG_BITS == 64);
  static const bool use_for_add = (LONG_BITS == 64);
  static const bool use_for_sub = (LONG_BITS == 64);
  static const bool use_for_mul = true;
  typedef int_fast64_t Type_For_Neg;
  typedef int_fast64_t Type_For_Add;
  typedef int_fast64_t Type_For_Sub;
  typedef int_fast64_t Type_For_Mul;
};

template <>
struct Larger<unsigned int> {
  static const bool use_for_neg = (LONG_BITS == 64);
  static const bool use_for_add = (LONG_BITS == 64);
  static const bool use_for_sub = (LONG_BITS == 64);
  static const bool use_for_mul = true;
  typedef int_fast64_t Type_For_Neg;
  typedef uint_fast64_t Type_For_Add;
  typedef int_fast64_t Type_For_Sub;
  typedef uint_fast64_t Type_For_Mul;
};

template <>
struct Larger<signed long> {
  static const bool use_for_neg = false;
  static const bool use_for_add = false;
  static const bool use_for_sub = false;
  static const bool use_for_mul = (LONG_BITS == 32);
  typedef int_fast64_t Type_For_Neg;
  typedef int_fast64_t Type_For_Add;
  typedef int_fast64_t Type_For_Sub;
  typedef int_fast64_t Type_For_Mul;
};

template <>
struct Larger<unsigned long> {
  static const bool use_for_neg = false;
  static const bool use_for_add = false;
  static const bool use_for_sub = false;
  static const bool use_for_mul = (LONG_BITS == 32);
  typedef int_fast64_t Type_For_Neg;
  typedef uint_fast64_t Type_For_Add;
  typedef int_fast64_t Type_For_Sub;
  typedef uint_fast64_t Type_For_Mul;
};

template <>
struct Larger<signed long long> {
  static const bool use_for_neg = false;
  static const bool use_for_add = false;
  static const bool use_for_sub = false;
  static const bool use_for_mul = false;
  typedef int_fast64_t Type_For_Neg;
  typedef int_fast64_t Type_For_Add;
  typedef int_fast64_t Type_For_Sub;
  typedef int_fast64_t Type_For_Mul;
};

template <>
struct Larger<unsigned long long> {
  static const bool use_for_neg = false;
  static const bool use_for_add = false;
  static const bool use_for_sub = false;
  static const bool use_for_mul = false;
  typedef int_fast64_t Type_For_Neg;
  typedef uint_fast64_t Type_For_Add;
  typedef int_fast64_t Type_For_Sub;
  typedef uint_fast64_t Type_For_Mul;
};

template <typename Policy, typename Type>
inline Result
neg_int_larger(Type& to, const Type x, Rounding_Dir dir) {
  typename Larger<Type>::Type_For_Neg l = x;
  l = -l;
  return assign<Policy>(to, l, dir);
}

template <typename Policy, typename Type>
inline Result
add_int_larger(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  typename Larger<Type>::Type_For_Add l = x;
  l += y;
  return assign<Policy>(to, l, dir);
}

template <typename Policy, typename Type>
inline Result
sub_int_larger(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  typename Larger<Type>::Type_For_Sub l = x;
  l -= y;
  return assign<Policy>(to, l, dir);
}

template <typename Policy, typename Type>
inline Result
mul_int_larger(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  typename Larger<Type>::Type_For_Mul l = x;
  l *= y;
  return assign<Policy>(to, l, dir);
}

template <typename Policy, typename Type>
inline Result
neg_signed_int(Type& to, const Type from, Rounding_Dir dir) {
  if (Policy::check_overflow && Larger<Type>::use_for_neg)
    return neg_int_larger<Policy>(to, from, dir);
  if (CHECK_P(Policy::check_overflow,
	      (from < -Extended_Int<Policy, Type>::max)))
    return set_pos_overflow_int<Policy>(to, dir);
  to = -from;
  return V_EQ;
}

template <typename Policy, typename Type>
inline Result
neg_unsigned_int(Type& to, const Type from, Rounding_Dir dir) {
  if (Policy::check_overflow && Larger<Type>::use_for_neg)
    return neg_int_larger<Policy>(to, from, dir);
  if (CHECK_P(Policy::check_overflow, from != 0))
    return set_neg_overflow_int<Policy>(to, dir);
  to = from;
  return V_EQ;
}

template <typename Policy, typename Type>
inline Result
add_signed_int(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (Policy::check_overflow && Larger<Type>::use_for_add)
    return add_int_larger<Policy>(to, x, y, dir);
  if (Policy::check_overflow) {
    if (y >= 0) {
      if (x > Extended_Int<Policy, Type>::max - y)
	return set_pos_overflow_int<Policy>(to, dir);
    }
    else if (x < Extended_Int<Policy, Type>::min - y)
	return set_neg_overflow_int<Policy>(to, dir);
  }
  to = x + y;
  return V_EQ;
}

template <typename Policy, typename Type>
inline Result
add_unsigned_int(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (Policy::check_overflow && Larger<Type>::use_for_add)
    return add_int_larger<Policy>(to, x, y, dir);
  if (CHECK_P(Policy::check_overflow,
	      (x > Extended_Int<Policy, Type>::max - y)))
    return set_pos_overflow_int<Policy>(to, dir);
  to = x + y;
  return V_EQ;
}

template <typename Policy, typename Type>
inline Result
sub_signed_int(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (Policy::check_overflow && Larger<Type>::use_for_sub)
    return sub_int_larger<Policy>(to, x, y, dir);
  if (Policy::check_overflow) {
    if (y >= 0) {
      if (x < Extended_Int<Policy, Type>::min + y)
	return set_neg_overflow_int<Policy>(to, dir);
    }
    else if (x > Extended_Int<Policy, Type>::max + y)
	return set_pos_overflow_int<Policy>(to, dir);
  }
  to = x - y;
  return V_EQ;
}

template <typename Policy, typename Type>
inline Result
sub_unsigned_int(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (Policy::check_overflow && Larger<Type>::use_for_sub)
    return sub_int_larger<Policy>(to, x, y, dir);
  if (CHECK_P(Policy::check_overflow,
	      (x < Extended_Int<Policy, Type>::min + y)))
    return set_neg_overflow_int<Policy>(to, dir);
  to = x - y;
  return V_EQ;
}

template <typename Policy, typename Type>
inline Result
mul_signed_int(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (Policy::check_overflow && Larger<Type>::use_for_mul)
    return mul_int_larger<Policy>(to, x, y, dir);
  if (!Policy::check_overflow) {
    to = x * y;
    return V_EQ;
  }
  if (y == 0) {
    to = 0;
    return V_EQ;
  }
  if (y == -1)
    return neg_signed_int<Policy>(to, x, dir);
  if (x >= 0) {
    if (y > 0) {
      if (x > Extended_Int<Policy, Type>::max / y)
	return set_pos_overflow_int<Policy>(to, dir);
    }
    else {
      if (x > Extended_Int<Policy, Type>::min / y)
	return set_neg_overflow_int<Policy>(to, dir);
    }
  }
  else {
    if (y < 0) {
      if (x < Extended_Int<Policy, Type>::max / y)
	return set_pos_overflow_int<Policy>(to, dir);
    }
    else {
      if (x < Extended_Int<Policy, Type>::min / y)
	return set_neg_overflow_int<Policy>(to, dir);
    }
  }
  to = x * y;
  return V_EQ;
}

template <typename Policy, typename Type>
inline Result
mul_unsigned_int(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (Policy::check_overflow && Larger<Type>::use_for_mul)
    return mul_int_larger<Policy>(to, x, y, dir);
  if (!Policy::check_overflow) {
    to = x * y;
    return V_EQ;
  }
  if (y == 0) {
    to = 0;
    return V_EQ;
  }
  if (x > Extended_Int<Policy, Type>::max / y)
    return set_pos_overflow_int<Policy>(to, dir);
  to = x * y;
  return V_EQ;
}

template <typename Policy, typename Type>
inline Result
div_signed_int(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (CHECK_P(Policy::check_div_zero, y == 0))
    return set_special<Policy>(to, V_DIV_ZERO);
  if (Policy::check_overflow && y == -1)
    return neg_signed_int<Policy>(to, x, dir);
  to = x / y;
  if (dir == ROUND_IGNORE)
    return V_LGE;
  Type m = x % y;
  if (m < 0)
    return round_lt_int_no_overflow<Policy>(to, dir);
  else if (m > 0)
    return round_gt_int_no_overflow<Policy>(to, dir);
  else
    return V_EQ;
}

template <typename Policy, typename Type>
inline Result
div_unsigned_int(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (CHECK_P(Policy::check_div_zero, y == 0))
    return set_special<Policy>(to, V_DIV_ZERO);
  to = x / y;
  if (dir == ROUND_IGNORE)
    return V_GE;
  Type m = x % y;
  if (m == 0)
    return V_EQ;
  return round_gt_int<Policy>(to, dir);
}

template <typename Policy, typename Type>
inline Result
rem_int(Type& to, const Type x, const Type y, Rounding_Dir) {
  if (CHECK_P(Policy::check_div_zero, y == 0))
    return set_special<Policy>(to, V_MOD_ZERO);
  to = x % y;
  return V_EQ;
}

template <typename Policy, typename Type>
inline Result
div2exp_unsigned_int(Type& to, const Type x, int exp, Rounding_Dir dir) {
  if (exp < 0)
    return mul2exp<Policy>(to, x, -exp, dir);
  if (static_cast<unsigned int>(exp) >= sizeof(Type) * 8) {
    to = 0;
    if (dir == ROUND_IGNORE)
      return V_GE;
    if (x == 0)
      return V_EQ;
    return round_gt_int_no_overflow<Policy>(to, dir);
  }
  to = x >> exp;
  if (dir == ROUND_IGNORE)
    return V_GE;
  if (x & ((static_cast<Type>(1) << exp) - 1))
    return round_gt_int_no_overflow<Policy>(to, dir);
  else
    return V_EQ;
}

template <typename Policy, typename Type>
inline Result
div2exp_signed_int(Type& to, const Type x, int exp, Rounding_Dir dir) {
  if (exp < 0)
    return mul2exp<Policy>(to, x, -exp, dir);
  if (static_cast<unsigned int>(exp) >= sizeof(Type) * 8) {
  zero:
    to = 0;
    if (dir == ROUND_IGNORE)
      return V_LGE;
    if (x < 0)
      return round_lt_int_no_overflow<Policy>(to, dir);
    else if (x > 0)
      return round_gt_int_no_overflow<Policy>(to, dir);
    else
      return V_EQ;
  }
  if (static_cast<unsigned int>(exp) >= sizeof(Type) * 8 - 1) {
    if (x == Limits<Type>::min) {
      to = -1;
      return V_EQ;
    }
    goto zero;
  }
#if 0
  to = x / (static_cast<Type>(1) << exp);
  if (dir == ROUND_IGNORE)
    return V_GE;
  Type r = x % (static_cast<Type>(1) << exp);
  if (r < 0)
    return round_lt_int_no_overflow<Policy>(to, dir);
  else if (r > 0)
    return round_gt_int_no_overflow<Policy>(to, dir);
  else
    return V_EQ;
#else
  // Faster but compiler implementation dependent (see C++98 5.8.3)
  to = x >> exp;
  if (dir == ROUND_IGNORE)
    return V_GE;
  if (x & ((static_cast<Type>(1) << exp) - 1))
    return round_gt_int_no_overflow<Policy>(to, dir);
  return V_EQ;
#endif
}

template <typename Policy, typename Type>
inline Result
mul2exp_unsigned_int(Type& to, const Type x, int exp, Rounding_Dir dir) {
  if (exp < 0)
    return div2exp<Policy>(to, x, -exp, dir);
  if (!Policy::check_overflow) {
    to = x << exp;
    return V_EQ;
  }
  if (static_cast<unsigned int>(exp) >= sizeof(Type) * 8) {
    if (x == 0) {
      to = 0;
      return V_EQ;
    }
    return set_pos_overflow_int<Policy>(to, dir);
  }
  if (x & (((static_cast<Type>(1) << exp) - 1) << (sizeof(Type) * 8 - exp)))
    return set_pos_overflow_int<Policy>(to, dir);
  Type n = x << exp;
  if (n > Extended_Int<Policy, Type>::max)
    return set_pos_overflow_int<Policy>(to, dir);
  to = n;
  return V_EQ;
}

template <typename Policy, typename Type>
inline Result
mul2exp_signed_int(Type& to, const Type x, int exp, Rounding_Dir dir) {
  if (exp < 0)
    return div2exp<Policy>(to, x, -exp, dir);
  if (!Policy::check_overflow) {
    to = x << exp;
    return V_EQ;
  }
  if (static_cast<unsigned int>(exp) >= sizeof(Type) * 8 - 1) {
    if (x < 0)
      return set_neg_overflow_int<Policy>(to, dir);
    else if (x > 0)
      return set_pos_overflow_int<Policy>(to, dir);
    else {
      to = 0;
      return V_EQ;
    }
  }
  Type mask = ((static_cast<Type>(1) << exp) - 1)
    << (sizeof(Type) * 8 - 1 - exp);
  Type n;
  if (x < 0) {
    if ((x & mask) != mask)
      return set_neg_overflow_int<Policy>(to, dir);
    n = x << exp;
    if (n < Extended_Int<Policy, Type>::min)
      return set_neg_overflow_int<Policy>(to, dir);
  }
  else {
    if (x & mask)
      return set_pos_overflow_int<Policy>(to, dir);
    n = x << exp;
    if (n > Extended_Int<Policy, Type>::max)
      return set_pos_overflow_int<Policy>(to, dir);
  }
  to = n;
  return V_EQ;
}

template <typename Type>
inline void
isqrtrem_(Type& q, Type& r, const Type from) {
  q = 0;
  r = from;
  Type t(1);
  for (t <<= 8 * sizeof(Type) - 2; t != 0; t >>= 2) {
    Type s = q + t;
    if (s <= r) {
      r -= s;
      q = s + t;
    }
    q >>= 1;
  }
}

template <typename Policy, typename Type>
inline Result
sqrt_unsigned_int(Type& to, const Type from, Rounding_Dir dir) {
  Type rem;
  isqrtrem_(to, rem, from);
  if (dir == ROUND_IGNORE)
    return V_GE;
  if (rem == 0)
    return V_EQ;
  return round_gt_int<Policy>(to, dir);
}

template <typename Policy, typename Type>
inline Result
sqrt_signed_int(Type& to, const Type from, Rounding_Dir dir) {
  if (CHECK_P(Policy::check_sqrt_neg, from < 0))
    return set_special<Policy>(to, V_SQRT_NEG);
  return sqrt_unsigned_int<Policy>(to, from, dir);
}

template <typename Policy, typename Type>
inline Result
add_mul_int(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  Type z;
  Result r = mul<Policy>(z, x, y, dir);
  switch (r) {
  case V_NEG_OVERFLOW:
  case V_LT:
    if (to <= 0) {
      to = z;
      return r;
    }
    return set_special<Policy>(to, V_UNKNOWN_NEG_OVERFLOW);
  case V_POS_OVERFLOW:
  case V_GT:
    if (to >= 0) {
      to = z;
      return r;
    }
    return set_special<Policy>(to, V_UNKNOWN_POS_OVERFLOW);
  default:
    return add<Policy>(to, to, z, dir);
  }
}

template <typename Policy, typename Type>
inline Result
sub_mul_int(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  Type z;
  Result r = mul<Policy>(z, x, y, dir);
  switch (r) {
  case V_NEG_OVERFLOW:
  case V_LT:
    if (to >= 0)
      return set_pos_overflow_int<Policy>(to, dir);
    return V_UNKNOWN_NEG_OVERFLOW;
  case V_POS_OVERFLOW:
  case V_GT:
    if (to <= 0)
      return set_neg_overflow_int<Policy>(to, dir);
    return V_UNKNOWN_POS_OVERFLOW;
  default:
    return sub<Policy>(to, to, z, dir);
  }
}

template <typename Policy, typename Type>
inline Result
output_char(std::ostream& os, Type& from,
	    const Numeric_Format&, Rounding_Dir) {
  os << (int) from;
  return V_EQ;
}

template <typename Policy, typename Type>
inline Result
output_int(std::ostream& os, Type& from, const Numeric_Format&, Rounding_Dir) {
  os << from;
  return V_EQ;
}

SPECIALIZE_NEG(signed_int, signed char, signed char)
SPECIALIZE_NEG(signed_int, signed short, signed short)
SPECIALIZE_NEG(signed_int, signed int, signed int)
SPECIALIZE_NEG(signed_int, signed long, signed long)
SPECIALIZE_NEG(signed_int, signed long long, signed long long)
SPECIALIZE_NEG(unsigned_int, unsigned char, unsigned char)
SPECIALIZE_NEG(unsigned_int, unsigned short, unsigned short)
SPECIALIZE_NEG(unsigned_int, unsigned int, unsigned int)
SPECIALIZE_NEG(unsigned_int, unsigned long, unsigned long)
SPECIALIZE_NEG(unsigned_int, unsigned long long, unsigned long long)

SPECIALIZE_ADD(signed_int, signed char, signed char, signed char)
SPECIALIZE_ADD(signed_int, signed short, signed short, signed short)
SPECIALIZE_ADD(signed_int, signed int, signed int, signed int)
SPECIALIZE_ADD(signed_int, signed long, signed long, signed long)
SPECIALIZE_ADD(signed_int, signed long long, signed long long, signed long long)
SPECIALIZE_ADD(unsigned_int, unsigned char, unsigned char, unsigned char)
SPECIALIZE_ADD(unsigned_int, unsigned short, unsigned short, unsigned short)
SPECIALIZE_ADD(unsigned_int, unsigned int, unsigned int, unsigned int)
SPECIALIZE_ADD(unsigned_int, unsigned long, unsigned long, unsigned long)
SPECIALIZE_ADD(unsigned_int, unsigned long long, unsigned long long, unsigned long long)

SPECIALIZE_SUB(signed_int, signed char, signed char, signed char)
SPECIALIZE_SUB(signed_int, signed short, signed short, signed short)
SPECIALIZE_SUB(signed_int, signed int, signed int, signed int)
SPECIALIZE_SUB(signed_int, signed long, signed long, signed long)
SPECIALIZE_SUB(signed_int, signed long long, signed long long, signed long long)
SPECIALIZE_SUB(unsigned_int, unsigned char, unsigned char, unsigned char)
SPECIALIZE_SUB(unsigned_int, unsigned short, unsigned short, unsigned short)
SPECIALIZE_SUB(unsigned_int, unsigned int, unsigned int, unsigned int)
SPECIALIZE_SUB(unsigned_int, unsigned long, unsigned long, unsigned long)
SPECIALIZE_SUB(unsigned_int, unsigned long long, unsigned long long, unsigned long long)

SPECIALIZE_MUL(signed_int, signed char, signed char, signed char)
SPECIALIZE_MUL(signed_int, signed short, signed short, signed short)
SPECIALIZE_MUL(signed_int, signed int, signed int, signed int)
SPECIALIZE_MUL(signed_int, signed long, signed long, signed long)
SPECIALIZE_MUL(signed_int, signed long long, signed long long, signed long long)
SPECIALIZE_MUL(unsigned_int, unsigned char, unsigned char, unsigned char)
SPECIALIZE_MUL(unsigned_int, unsigned short, unsigned short, unsigned short)
SPECIALIZE_MUL(unsigned_int, unsigned int, unsigned int, unsigned int)
SPECIALIZE_MUL(unsigned_int, unsigned long, unsigned long, unsigned long)
SPECIALIZE_MUL(unsigned_int, unsigned long long, unsigned long long, unsigned long long)

SPECIALIZE_DIV(signed_int, signed char, signed char, signed char)
SPECIALIZE_DIV(signed_int, signed short, signed short, signed short)
SPECIALIZE_DIV(signed_int, signed int, signed int, signed int)
SPECIALIZE_DIV(signed_int, signed long, signed long, signed long)
SPECIALIZE_DIV(signed_int, signed long long, signed long long, signed long long)
SPECIALIZE_DIV(unsigned_int, unsigned char, unsigned char, unsigned char)
SPECIALIZE_DIV(unsigned_int, unsigned short, unsigned short, unsigned short)
SPECIALIZE_DIV(unsigned_int, unsigned int, unsigned int, unsigned int)
SPECIALIZE_DIV(unsigned_int, unsigned long, unsigned long, unsigned long)
SPECIALIZE_DIV(unsigned_int, unsigned long long, unsigned long long, unsigned long long)

SPECIALIZE_REM(int, signed char, signed char, signed char)
SPECIALIZE_REM(int, signed short, signed short, signed short)
SPECIALIZE_REM(int, signed int, signed int, signed int)
SPECIALIZE_REM(int, signed long, signed long, signed long)
SPECIALIZE_REM(int, signed long long, signed long long, signed long long)
SPECIALIZE_REM(int, unsigned char, unsigned char, unsigned char)
SPECIALIZE_REM(int, unsigned short, unsigned short, unsigned short)
SPECIALIZE_REM(int, unsigned int, unsigned int, unsigned int)
SPECIALIZE_REM(int, unsigned long, unsigned long, unsigned long)
SPECIALIZE_REM(int, unsigned long long, unsigned long long, unsigned long long)

SPECIALIZE_MUL2EXP(signed_int, signed char, signed char)
SPECIALIZE_MUL2EXP(signed_int, signed short, signed short)
SPECIALIZE_MUL2EXP(signed_int, signed int, signed int)
SPECIALIZE_MUL2EXP(signed_int, signed long, signed long)
SPECIALIZE_MUL2EXP(signed_int, signed long long, signed long long)
SPECIALIZE_MUL2EXP(unsigned_int, unsigned char, unsigned char)
SPECIALIZE_MUL2EXP(unsigned_int, unsigned short, unsigned short)
SPECIALIZE_MUL2EXP(unsigned_int, unsigned int, unsigned int)
SPECIALIZE_MUL2EXP(unsigned_int, unsigned long, unsigned long)
SPECIALIZE_MUL2EXP(unsigned_int, unsigned long long, unsigned long long)

SPECIALIZE_DIV2EXP(signed_int, signed char, signed char)
SPECIALIZE_DIV2EXP(signed_int, signed short, signed short)
SPECIALIZE_DIV2EXP(signed_int, signed int, signed int)
SPECIALIZE_DIV2EXP(signed_int, signed long, signed long)
SPECIALIZE_DIV2EXP(signed_int, signed long long, signed long long)
SPECIALIZE_DIV2EXP(unsigned_int, unsigned char, unsigned char)
SPECIALIZE_DIV2EXP(unsigned_int, unsigned short, unsigned short)
SPECIALIZE_DIV2EXP(unsigned_int, unsigned int, unsigned int)
SPECIALIZE_DIV2EXP(unsigned_int, unsigned long, unsigned long)
SPECIALIZE_DIV2EXP(unsigned_int, unsigned long long, unsigned long long)

SPECIALIZE_SQRT(signed_int, signed char, signed char)
SPECIALIZE_SQRT(signed_int, signed short, signed short)
SPECIALIZE_SQRT(signed_int, signed int, signed int)
SPECIALIZE_SQRT(signed_int, signed long, signed long)
SPECIALIZE_SQRT(signed_int, signed long long, signed long long)
SPECIALIZE_SQRT(unsigned_int, unsigned char, unsigned char)
SPECIALIZE_SQRT(unsigned_int, unsigned short, unsigned short)
SPECIALIZE_SQRT(unsigned_int, unsigned int, unsigned int)
SPECIALIZE_SQRT(unsigned_int, unsigned long, unsigned long)
SPECIALIZE_SQRT(unsigned_int, unsigned long long, unsigned long long)

SPECIALIZE_ABS(generic, signed char, signed char)
SPECIALIZE_ABS(generic, signed short, signed short)
SPECIALIZE_ABS(generic, signed int, signed int)
SPECIALIZE_ABS(generic, signed long, signed long)
SPECIALIZE_ABS(generic, signed long long, signed long long)
SPECIALIZE_ABS(generic, unsigned char, unsigned char)
SPECIALIZE_ABS(generic, unsigned short, unsigned short)
SPECIALIZE_ABS(generic, unsigned int, unsigned int)
SPECIALIZE_ABS(generic, unsigned long, unsigned long)
SPECIALIZE_ABS(generic, unsigned long long, unsigned long long)

SPECIALIZE_GCD(exact, signed char, signed char, signed char)
SPECIALIZE_GCD(exact, signed short, signed short, signed short)
SPECIALIZE_GCD(exact, signed int, signed int, signed int)
SPECIALIZE_GCD(exact, signed long, signed long, signed long)
SPECIALIZE_GCD(exact, signed long long, signed long long, signed long long)
SPECIALIZE_GCD(exact, unsigned char, unsigned char, unsigned char)
SPECIALIZE_GCD(exact, unsigned short, unsigned short, unsigned short)
SPECIALIZE_GCD(exact, unsigned int, unsigned int, unsigned int)
SPECIALIZE_GCD(exact, unsigned long, unsigned long, unsigned long)
SPECIALIZE_GCD(exact, unsigned long long, unsigned long long, unsigned long long)

SPECIALIZE_GCDEXT(exact, signed char, signed char, signed char, signed char, signed char)
SPECIALIZE_GCDEXT(exact, signed short, signed short, signed short, signed short, signed short)
SPECIALIZE_GCDEXT(exact, signed int, signed int, signed int, signed int, signed int)
SPECIALIZE_GCDEXT(exact, signed long, signed long, signed long, signed long, signed long)
SPECIALIZE_GCDEXT(exact, signed long long, signed long long, signed long long, signed long long, signed long long)
SPECIALIZE_GCDEXT(exact, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char)
SPECIALIZE_GCDEXT(exact, unsigned short, unsigned short, unsigned short, unsigned short, unsigned short)
SPECIALIZE_GCDEXT(exact, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int)
SPECIALIZE_GCDEXT(exact, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long)
SPECIALIZE_GCDEXT(exact, unsigned long long, unsigned long long, unsigned long long, unsigned long long, unsigned long long)

SPECIALIZE_LCM(gcd_exact, signed char, signed char, signed char)
SPECIALIZE_LCM(gcd_exact, signed short, signed short, signed short)
SPECIALIZE_LCM(gcd_exact, signed int, signed int, signed int)
SPECIALIZE_LCM(gcd_exact, signed long, signed long, signed long)
SPECIALIZE_LCM(gcd_exact, signed long long, signed long long, signed long long)
SPECIALIZE_LCM(gcd_exact, unsigned char, unsigned char, unsigned char)
SPECIALIZE_LCM(gcd_exact, unsigned short, unsigned short, unsigned short)
SPECIALIZE_LCM(gcd_exact, unsigned int, unsigned int, unsigned int)
SPECIALIZE_LCM(gcd_exact, unsigned long, unsigned long, unsigned long)
SPECIALIZE_LCM(gcd_exact, unsigned long long, unsigned long long, unsigned long long)

SPECIALIZE_SGN(generic, signed char)
SPECIALIZE_SGN(generic, signed short)
SPECIALIZE_SGN(generic, signed int)
SPECIALIZE_SGN(generic, signed long)
SPECIALIZE_SGN(generic, signed long long)
SPECIALIZE_SGN(generic, unsigned char)
SPECIALIZE_SGN(generic, unsigned short)
SPECIALIZE_SGN(generic, unsigned int)
SPECIALIZE_SGN(generic, unsigned long)
SPECIALIZE_SGN(generic, unsigned long long)

SPECIALIZE_CMP(generic, signed char, signed char)
SPECIALIZE_CMP(generic, signed short, signed short)
SPECIALIZE_CMP(generic, signed int, signed int)
SPECIALIZE_CMP(generic, signed long, signed long)
SPECIALIZE_CMP(generic, signed long long, signed long long)
SPECIALIZE_CMP(generic, unsigned char, unsigned char)
SPECIALIZE_CMP(generic, unsigned short, unsigned short)
SPECIALIZE_CMP(generic, unsigned int, unsigned int)
SPECIALIZE_CMP(generic, unsigned long, unsigned long)
SPECIALIZE_CMP(generic, unsigned long long, unsigned long long)

SPECIALIZE_ADD_MUL(int, signed char, signed char, signed char)
SPECIALIZE_ADD_MUL(int, signed short, signed short, signed short)
SPECIALIZE_ADD_MUL(int, signed int, signed int, signed int)
SPECIALIZE_ADD_MUL(int, signed long, signed long, signed long)
SPECIALIZE_ADD_MUL(int, signed long long, signed long long, signed long long)
SPECIALIZE_ADD_MUL(int, unsigned char, unsigned char, unsigned char)
SPECIALIZE_ADD_MUL(int, unsigned short, unsigned short, unsigned short)
SPECIALIZE_ADD_MUL(int, unsigned int, unsigned int, unsigned int)
SPECIALIZE_ADD_MUL(int, unsigned long, unsigned long, unsigned long)
SPECIALIZE_ADD_MUL(int, unsigned long long, unsigned long long, unsigned long long)

SPECIALIZE_SUB_MUL(int, signed char, signed char, signed char)
SPECIALIZE_SUB_MUL(int, signed short, signed short, signed short)
SPECIALIZE_SUB_MUL(int, signed int, signed int, signed int)
SPECIALIZE_SUB_MUL(int, signed long, signed long, signed long)
SPECIALIZE_SUB_MUL(int, signed long long, signed long long, signed long long)
SPECIALIZE_SUB_MUL(int, unsigned char, unsigned char, unsigned char)
SPECIALIZE_SUB_MUL(int, unsigned short, unsigned short, unsigned short)
SPECIALIZE_SUB_MUL(int, unsigned int, unsigned int, unsigned int)
SPECIALIZE_SUB_MUL(int, unsigned long, unsigned long, unsigned long)
SPECIALIZE_SUB_MUL(int, unsigned long long, unsigned long long, unsigned long long)

SPECIALIZE_INPUT(generic, signed char)
SPECIALIZE_INPUT(generic, signed short)
SPECIALIZE_INPUT(generic, signed int)
SPECIALIZE_INPUT(generic, signed long)
SPECIALIZE_INPUT(generic, signed long long)
SPECIALIZE_INPUT(generic, unsigned char)
SPECIALIZE_INPUT(generic, unsigned short)
SPECIALIZE_INPUT(generic, unsigned int)
SPECIALIZE_INPUT(generic, unsigned long)
SPECIALIZE_INPUT(generic, unsigned long long)

SPECIALIZE_OUTPUT(char, signed char)
SPECIALIZE_OUTPUT(int, signed short)
SPECIALIZE_OUTPUT(int, signed int)
SPECIALIZE_OUTPUT(int, signed long)
SPECIALIZE_OUTPUT(int, signed long long)
SPECIALIZE_OUTPUT(char, unsigned char)
SPECIALIZE_OUTPUT(int, unsigned short)
SPECIALIZE_OUTPUT(int, unsigned int)
SPECIALIZE_OUTPUT(int, unsigned long)
SPECIALIZE_OUTPUT(int, unsigned long long)

} // namespace Checked

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/checked_float.inlines.hh line 1
/* Specialized "checked" functions for native floating-point numbers.
*/


// Automatically generated from PPL source file ../src/Float.defs.hh line 1
/* IEC 559 floating point format related functions.
*/


// Automatically generated from PPL source file ../src/Float.defs.hh line 27
#include <gmp.h>
#include <cassert>
#include <cmath>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif

#ifndef NAN
#define NAN (HUGE_VAL - HUGE_VAL)
#endif

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS

struct float_ieee754_single {
  uint32_t word;
  static const uint32_t SGN_MASK = 0x80000000;
  static const uint32_t EXP_MASK = 0x7f800000;
  static const uint32_t POS_INF = 0x7f800000;
  static const uint32_t NEG_INF = 0xff800000;
  static const uint32_t POS_ZERO = 0x00000000;
  static const uint32_t NEG_ZERO = 0x80000000;
  static const unsigned int EXPONENT_BITS = 8;
  static const unsigned int MANTISSA_BITS = 23;
  static const int EXPONENT_MAX = (1 << (EXPONENT_BITS - 1)) - 1;
  static const int EXPONENT_BIAS = EXPONENT_MAX;
  static const int EXPONENT_MIN = -EXPONENT_MAX + 1;
  static const int EXPONENT_MIN_DENORM = EXPONENT_MIN
					- static_cast<int>(MANTISSA_BITS);
  int is_inf() const;
  int is_nan() const;
  int is_zero() const;
  int sign_bit() const;
  void negate();
  void dec();
  void inc();
  void set_max(bool negative);
  void build(bool negative, mpz_t mantissa, int exponent);
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS

struct float_ieee754_double {
#ifdef WORDS_BIGENDIAN
  uint32_t msp;
  uint32_t lsp;
#else
  uint32_t lsp;
  uint32_t msp;
#endif
  static const uint32_t MSP_SGN_MASK = 0x80000000;
  static const uint32_t MSP_POS_INF = 0x7ff00000;
  static const uint32_t MSP_NEG_INF = 0xfff00000;
  static const uint32_t MSP_POS_ZERO = 0x00000000;
  static const uint32_t MSP_NEG_ZERO = 0x80000000;
  static const uint32_t LSP_INF = 0;
  static const uint32_t LSP_ZERO = 0;
  static const uint32_t LSP_MAX = 0xffffffff;
  static const unsigned int EXPONENT_BITS = 11;
  static const unsigned int MANTISSA_BITS = 52;
  static const int EXPONENT_MAX = (1 << (EXPONENT_BITS - 1)) - 1;
  static const int EXPONENT_BIAS = EXPONENT_MAX;
  static const int EXPONENT_MIN = -EXPONENT_MAX + 1;
  static const int EXPONENT_MIN_DENORM = EXPONENT_MIN
					- static_cast<int>(MANTISSA_BITS);
  int is_inf() const;
  int is_nan() const;
  int is_zero() const;
  int sign_bit() const;
  void negate();
  void dec();
  void inc();
  void set_max(bool negative);
  void build(bool negative, mpz_t mantissa, int exponent);
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS

struct float_intel_double_extended {
#ifdef WORDS_BIGENDIAN
  uint32_t msp;
  uint64_t lsp;
#else
  uint64_t lsp;
  uint32_t msp;
#endif
  static const uint32_t MSP_SGN_MASK = 0x00008000;
  static const uint32_t MSP_POS_INF = 0x00007fff;
  static const uint32_t MSP_NEG_INF = 0x0000ffff;
  static const uint32_t MSP_POS_ZERO = 0x00000000;
  static const uint32_t MSP_NEG_ZERO = 0x00008000;
  static const uint64_t LSP_INF = 0x8000000000000000ULL;
  static const uint64_t LSP_ZERO = 0;
  static const uint64_t LSP_DMAX = 0x7fffffffffffffffULL;
  static const uint64_t LSP_NMAX = 0xffffffffffffffffULL;
  static const unsigned int EXPONENT_BITS = 15;
  static const unsigned int MANTISSA_BITS = 63;
  static const int EXPONENT_MAX = (1 << (EXPONENT_BITS - 1)) - 1;
  static const int EXPONENT_BIAS = EXPONENT_MAX;
  static const int EXPONENT_MIN = -EXPONENT_MAX + 1;
  static const int EXPONENT_MIN_DENORM = EXPONENT_MIN
					- static_cast<int>(MANTISSA_BITS);
  int is_inf() const;
  int is_nan() const;
  int is_zero() const;
  int sign_bit() const;
  void negate();
  void dec();
  void inc();
  void set_max(bool negative);
  void build(bool negative, mpz_t mantissa, int exponent);
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS

struct float_ieee754_quad {
#ifdef WORDS_BIGENDIAN
  uint64_t msp;
  uint64_t lsp;
#else
  uint64_t lsp;
  uint64_t msp;
#endif
  static const uint64_t MSP_SGN_MASK = 0x8000000000000000ULL;
  static const uint64_t MSP_POS_INF = 0x7fff000000000000ULL;
  static const uint64_t MSP_NEG_INF = 0xffff000000000000ULL;
  static const uint64_t MSP_POS_ZERO = 0x0000000000000000ULL;
  static const uint64_t MSP_NEG_ZERO = 0x8000000000000000ULL;
  static const uint64_t LSP_INF = 0;
  static const uint64_t LSP_ZERO = 0;
  static const uint64_t LSP_MAX = 0xffffffffffffffffULL;
  static const unsigned int EXPONENT_BITS = 15;
  static const unsigned int MANTISSA_BITS = 112;
  static const int EXPONENT_MAX = (1 << (EXPONENT_BITS - 1)) - 1;
  static const int EXPONENT_BIAS = EXPONENT_MAX;
  static const int EXPONENT_MIN = -EXPONENT_MAX + 1;
  static const int EXPONENT_MIN_DENORM = EXPONENT_MIN
					- static_cast<int>(MANTISSA_BITS);
  int is_inf() const;
  int is_nan() const;
  int is_zero() const;
  int sign_bit() const;
  void negate();
  void dec();
  void inc();
  void set_max(bool negative);
  void build(bool negative, mpz_t mantissa, int exponent);
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename T>
class Float {
public:
  static const bool fpu_related = false;
};

#if PPL_SUPPORTED_FLOAT
template <>
class Float<float> {
public:
  typedef CXX_FLOAT_BINARY_FORMAT Binary;
  union {
    float number;
    Binary binary;
  } u;
  Float();
  Float(float v);
  float value();
  static const bool fpu_related = true;
};
#endif

#if PPL_SUPPORTED_DOUBLE
template <>
class Float<double> {
public:
  typedef CXX_DOUBLE_BINARY_FORMAT Binary;
  union {
    double number;
    Binary binary;
  } u;
  Float();
  Float(double v);
  double value();
  static const bool fpu_related = true;
};
#endif

#if PPL_SUPPORTED_LONG_DOUBLE
template <>
class Float<long double> {
public:
  typedef CXX_LONG_DOUBLE_BINARY_FORMAT Binary;
  union {
    long double number;
    Binary binary;
  } u;
  Float();
  Float(long double v);
  long double value();
  static const bool fpu_related = true;
};
#endif

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Float.inlines.hh line 1
/* IEC 559 floating point format related functions.
*/


#include <climits>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif

namespace Parma_Polyhedra_Library {

inline int
float_ieee754_single::is_inf() const {
  if (word == NEG_INF)
    return -1;
  if (word == POS_INF)
    return 1;
  return 0;
}

inline int
float_ieee754_single::is_nan() const {
  return (word & ~SGN_MASK) > POS_INF;
}

inline int
float_ieee754_single::is_zero() const {
  if (word == NEG_ZERO)
    return -1;
  if (word == POS_ZERO)
    return 1;
  return 0;
}

inline void
float_ieee754_single::negate() {
  word ^= SGN_MASK;
}

inline int
float_ieee754_single::sign_bit() const {
  return !!(word & SGN_MASK);
}

inline void
float_ieee754_single::dec() {
  word--;
}

inline void
float_ieee754_single::inc() {
  word++;
}

inline void
float_ieee754_single::set_max(bool negative) {
  word = 0x7f7fffff;
  if (negative)
    word |= SGN_MASK;
}

inline void
float_ieee754_single::build(bool negative, mpz_t mantissa, int exponent) {
  word = mpz_get_ui(mantissa) & ((1UL << MANTISSA_BITS) - 1);
  if (negative)
    word |= SGN_MASK;
  word |= static_cast<uint32_t>(exponent + EXPONENT_BIAS) << MANTISSA_BITS;
}

inline int
float_ieee754_double::is_inf() const {
  if (lsp != LSP_INF)
    return 0;
  if (msp == MSP_NEG_INF)
    return -1;
  if (msp == MSP_POS_INF)
    return 1;
  return 0;
}

inline int
float_ieee754_double::is_nan() const {
  uint32_t a = msp & ~MSP_SGN_MASK;
  return a > MSP_POS_INF || (a == MSP_POS_INF && lsp != LSP_INF);
}

inline int
float_ieee754_double::is_zero() const {
  if (lsp != LSP_ZERO)
    return 0;
  if (msp == MSP_NEG_ZERO)
    return -1;
  if (msp == MSP_POS_ZERO)
    return 1;
  return 0;
}

inline void
float_ieee754_double::negate() {
  msp ^= MSP_SGN_MASK;
}

inline int
float_ieee754_double::sign_bit() const {
  return !!(msp & MSP_SGN_MASK);
}

inline void
float_ieee754_double::dec() {
  if (lsp == 0) {
    msp--;
    lsp = LSP_MAX;
  }
  else
    lsp--;
}

inline void
float_ieee754_double::inc() {
  if (lsp == LSP_MAX) {
    msp++;
    lsp = 0;
  }
  else
    lsp++;
}

inline void
float_ieee754_double::set_max(bool negative) {
  msp = 0x7fefffff;
  lsp = 0xffffffff;
  if (negative)
    msp |= MSP_SGN_MASK;
}

inline void
float_ieee754_double::build(bool negative, mpz_t mantissa, int exponent) {
#if ULONG_MAX == 0xffffffffUL
  lsp = mpz_get_ui(mantissa);
  mpz_tdiv_q_2exp(mantissa, mantissa, 32);
  unsigned long m = mpz_get_ui(mantissa);
#else
  unsigned long m = mpz_get_ui(mantissa);
  lsp = m;
  m >>= 32;
#endif
  msp = m & ((1UL << (MANTISSA_BITS - 32)) - 1);
  if (negative)
    msp |= MSP_SGN_MASK;
  msp |= static_cast<uint32_t>(exponent + EXPONENT_BIAS)
    << (MANTISSA_BITS - 32);
}

inline int
float_intel_double_extended::is_inf() const {
  if (lsp != LSP_INF)
    return 0;
  uint32_t a = msp & MSP_NEG_INF;
  if (a == MSP_NEG_INF)
    return -1;
  if (a == MSP_POS_INF)
    return 1;
  return 0;
}

inline int
float_intel_double_extended::is_nan() const {
  return (msp & MSP_POS_INF) == MSP_POS_INF
    && lsp != LSP_INF;
}

inline int
float_intel_double_extended::is_zero() const {
  if (lsp != LSP_ZERO)
    return 0;
  uint32_t a = msp & MSP_NEG_INF;
  if (a == MSP_NEG_ZERO)
    return -1;
  if (a == MSP_POS_ZERO)
    return 1;
  return 0;
}

inline void
float_intel_double_extended::negate() {
  msp ^= MSP_SGN_MASK;
}

inline int
float_intel_double_extended::sign_bit() const {
  return !!(msp & MSP_SGN_MASK);
}

inline void
float_intel_double_extended::dec() {
  if ((lsp & LSP_DMAX) == 0) {
    msp--;
    lsp = (msp & MSP_NEG_INF) == 0 ? LSP_DMAX : LSP_NMAX;
  }
  else
    lsp--;
}

inline void
float_intel_double_extended::inc() {
  if ((lsp & LSP_DMAX) == LSP_DMAX) {
    msp++;
    lsp = LSP_DMAX + 1;
  }
  else
    lsp++;
}

inline void
float_intel_double_extended::set_max(bool negative) {
  msp = 0x00007ffe;
  lsp = 0xffffffffffffffffULL;
  if (negative)
    msp |= MSP_SGN_MASK;
}

inline void
float_intel_double_extended::build(bool negative,
				   mpz_t mantissa, int exponent) {
#if ULONG_MAX == 0xffffffffUL
  mpz_export(&lsp, 0, -1, 8, 0, 0, mantissa);
#else
  lsp = mpz_get_ui(mantissa);
#endif
  msp = (negative ? MSP_SGN_MASK : 0);
  msp |= static_cast<uint32_t>(exponent + EXPONENT_BIAS);
}

inline int
float_ieee754_quad::is_inf() const {
  if (lsp != LSP_INF)
    return 0;
  if (msp == MSP_NEG_INF)
    return -1;
  if (msp == MSP_POS_INF)
    return 1;
  return 0;
}

inline int
float_ieee754_quad::is_nan() const {
  return (msp & ~MSP_SGN_MASK) == MSP_POS_INF
    && lsp != LSP_INF;
}

inline int
float_ieee754_quad::is_zero() const {
  if (lsp != LSP_ZERO)
    return 0;
  if (msp == MSP_NEG_ZERO)
    return -1;
  if (msp == MSP_POS_ZERO)
    return 1;
  return 0;
}

inline void
float_ieee754_quad::negate() {
  msp ^= MSP_SGN_MASK;
}

inline int
float_ieee754_quad::sign_bit() const {
  return !!(msp & MSP_SGN_MASK);
}

inline void
float_ieee754_quad::dec() {
  if (lsp == 0) {
    msp--;
    lsp = LSP_MAX;
  }
  else
    lsp--;
}

inline void
float_ieee754_quad::inc() {
  if (lsp == LSP_MAX) {
    msp++;
    lsp = 0;
  }
  else
    lsp++;
}

inline void
float_ieee754_quad::set_max(bool negative) {
  msp = 0x7ffeffffffffffffULL;
  lsp = 0xffffffffffffffffULL;
  if (negative)
    msp |= MSP_SGN_MASK;
}

inline void
float_ieee754_quad::build(bool negative, mpz_t mantissa, int exponent) {
  uint64_t parts[2];
  mpz_export(parts, 0, -1, 8, 0, 0, mantissa);
  lsp = parts[0];
  msp = parts[1];
  msp &= ((1ULL << (MANTISSA_BITS - 64)) - 1);
  if (negative)
    msp |= MSP_SGN_MASK;
  msp |= static_cast<uint64_t>(exponent + EXPONENT_BIAS)
    << (MANTISSA_BITS - 64);
}

#ifdef CXX_FLOAT_BINARY_FORMAT
inline
Float<float>::Float() {
}

inline
Float<float>::Float(float v) {
  u.number = v;
}

inline float
Float<float>::value() {
  return u.number;
}
#endif

#ifdef CXX_DOUBLE_BINARY_FORMAT
inline
Float<double>::Float() {
}

inline
Float<double>::Float(double v) {
  u.number = v;
}

inline double
Float<double>::value() {
  return u.number;
}
#endif

#ifdef CXX_LONG_DOUBLE_BINARY_FORMAT
inline
Float<long double>::Float() {
}

inline
Float<long double>::Float(long double v) {
  u.number = v;
}

inline long double
Float<long double>::value() {
  return u.number;
}
#endif


} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Float.defs.hh line 248

// Automatically generated from PPL source file ../src/checked_float.inlines.hh line 27
#ifndef __alpha
#include <cmath>
#endif

namespace Parma_Polyhedra_Library {

namespace Checked {

inline float
fma(float x, float y, float z) {
#if HAVE_DECL_FMAF && !defined(__alpha)
  return ::fmaf(x, y, z);
#else
  return x*y + z;
#endif
}

#if HAVE_DECL_RINTF
inline float
rint(float x) {
  return ::rintf(x);
}
#endif

inline double
fma(double x, double y, double z) {
#if HAVE_DECL_FMA && !defined(__alpha)
  return ::fma(x, y, z);
#else
  return x*y + z;
#endif
}

inline double
rint(double x) {
  return ::rint(x);
}

inline long double
fma(long double x, long double y, long double z) {
#if HAVE_DECL_FMAL && !defined(__alpha)
  return ::fmal(x, y, z);
#else
  return x*y + z;
#endif
}

#if HAVE_DECL_RINTL
inline long double
rint(long double x) {
  return ::rintl(x);
}
#endif

inline bool
fpu_direct_rounding(Rounding_Dir dir) {
  return dir == ROUND_DIRECT || dir == ROUND_IGNORE;
}

inline bool
fpu_inverse_rounding(Rounding_Dir dir) {
  return dir == ROUND_INVERSE;
}

// The FPU mode is "round down".
//
// The result of the rounded down multiplication is thus computed directly.
//
//   a = 0.3
//   b = 0.1
//   c_i = a * b = 0.03
//   c = c_i = 0.0
//
// To obtain the result of the rounded up multiplication
// we do -(-a * b).
//
//   a = 0.3
//   b = 0.1
//   c_i = -a * b = -0.03
//
// Here c_i should be forced to lose excess precision, otherwise the
// FPU will truncate using the rounding mode in force, which is "round down".
//
//   c_i = -c_i = 0.03
//   c = c_i = 0.0
//
// Wrong result: we should have obtained c = 0.1.

inline float
limit_precision(float v) {
  volatile float x = v;
  return x;
}

inline double
limit_precision(double v) {
  volatile double x = v;
  return x;
}

inline long double
limit_precision(long double v) {
#if __GNUC__ >= 4
  return v;
#else
  // Not really needed for floating point operations done with the
  // maximum available precision, but this avoids a bug in GCC 3.4.3
  // that causes excessive optimization compiling -(-a * b).
  // See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21032
  // and http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21067.
  volatile long double x = v;
  return x;
#endif
}

template <typename Policy, typename T>
inline Result
classify_float(const T v, bool nan, bool inf, bool sign) {
  Float<T> f(v);
  if ((nan || sign) && f.u.binary.is_nan())
    return VC_NAN;
  if (inf) {
    int i = f.u.binary.is_inf();
    if (i < 0)
      return VC_MINUS_INFINITY;
    if (i > 0)
      return VC_PLUS_INFINITY;
  }
  if (sign) {
    if (v < 0)
      return V_LT;
    if (v > 0)
      return V_GT;
    return V_EQ;
  }
  return VC_NORMAL;
}

template <typename Policy, typename T>
inline bool
is_nan_float(const T v) {
  Float<T> f(v);
  return f.u.binary.is_nan();
}

template <typename Policy, typename T>
inline bool
is_minf_float(const T v) {
  Float<T> f(v);
  return f.u.binary.is_inf() < 0;
}

template <typename Policy, typename T>
inline bool
is_pinf_float(const T v) {
  Float<T> f(v);
  return f.u.binary.is_inf() > 0;
}

template <typename T>
inline bool
is_inf_float(const T v) {
  Float<T> f(v);
  return f.u.binary.is_inf() != 0;
}

template <typename Policy, typename T>
inline bool
is_int_float(const T v) {
  return rint(v) == v;
}

template <typename Policy, typename T>
inline Result
set_special_float(T& v, Result r) {
  switch (classify(r)) {
  case VC_MINUS_INFINITY:
    v = -HUGE_VAL;
    break;
  case VC_PLUS_INFINITY:
    v = HUGE_VAL;
    break;
  case VC_NAN:
    v = NAN;
    break;
  default:
    break;
  }
  return r;
}

template <typename T>
inline void
pred_float(T& v) {
  Float<T> f(v);
  assert(!f.u.binary.is_nan());
  assert(f.u.binary.is_inf() >= 0);
  if (f.u.binary.is_zero() > 0) {
    f.u.binary.negate();
    f.u.binary.inc();
  }
  else if (f.u.binary.sign_bit()) {
    f.u.binary.inc();
  }
  else {
    f.u.binary.dec();
  }
  v = f.value();
}

template <typename T>
inline void
succ_float(T& v) {
  Float<T> f(v);
  assert(!f.u.binary.is_nan());
  assert(f.u.binary.is_inf() <= 0);
  if (f.u.binary.is_zero() < 0) {
    f.u.binary.negate();
    f.u.binary.inc();
  }
  else if (!f.u.binary.sign_bit()) {
    f.u.binary.inc();
  }
  else {
    f.u.binary.dec();
  }
  v = f.value();
}

template <typename Policy, typename To>
inline Result
round_lt_float(To& to, Rounding_Dir dir) {
  if (dir == ROUND_DOWN) {
    pred_float(to);
    return V_GT;
  }
  return V_LT;
}

template <typename Policy, typename To>
inline Result
round_gt_float(To& to, Rounding_Dir dir) {
  if (dir == ROUND_UP) {
    succ_float(to);
    return V_LT;
  }
  return V_GT;
}

template <typename Policy>
inline void
prepare_inexact(Rounding_Dir dir) {
  if (Policy::fpu_check_inexact && dir != ROUND_IGNORE)
    fpu_reset_inexact();
}

template <typename Policy>
inline Result
result_relation(Rounding_Dir dir) {
  if (Policy::fpu_check_inexact) {
    if (!fpu_check_inexact())
      return V_EQ;
    switch (dir) {
    case ROUND_DOWN:
      return V_GT;
    case ROUND_UP:
      return V_LT;
    default:
      return V_NE;
    }
  }
  else {
    switch (dir) {
    case ROUND_DOWN:
      return V_GE;
    case ROUND_UP:
      return V_LE;
    default:
      return V_LGE;
    }
  }
}

template <typename Policy, typename From, typename To>
inline Result
assign_float_float_exact(To& to, const From from, Rounding_Dir) {
  if (CHECK_P(Policy::check_nan_args, is_nan<Policy>(from)))
    return VC_NAN;
  to = from;
  return V_EQ;
}

template <typename Policy, typename To, typename From>
inline Result
assign_float_float_inexact(To& to, const From from, Rounding_Dir dir) {
  if (CHECK_P(Policy::check_nan_args, is_nan<Policy>(from)))
    return VC_NAN;
  prepare_inexact<Policy>(dir);
  if (fpu_direct_rounding(dir))
    to = from;
  else if (fpu_inverse_rounding(dir))
    to = -limit_precision(-from);
  else {
    fpu_rounding_control_word_type old = fpu_save_rounding_direction(dir);
    to = from;
    fpu_restore_rounding_direction(old);
  }
  return result_relation<Policy>(dir);
}

template <typename Policy, typename From, typename To>
inline Result
assign_float_float(To& to, const From from, Rounding_Dir dir) {
  if (sizeof(From) > sizeof(To))
    return assign_float_float_inexact<Policy>(to, from, dir);
  else
    return assign_float_float_exact<Policy>(to, from, dir);
}

template <typename Policy, typename Type>
inline Result
neg_float(Type& to, const Type from, Rounding_Dir) {
  if (CHECK_P(Policy::check_nan_args, is_nan<Policy>(from)))
    return VC_NAN;
  to = -from;
  return V_EQ;
}

template <typename Policy, typename Type>
inline Result
add_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (CHECK_P(Policy::check_nan_args, is_nan<Policy>(x))
      || CHECK_P(Policy::check_nan_args, is_nan<Policy>(y)))
    return VC_NAN;
  if (CHECK_P(Policy::check_inf_add_inf, is_inf_float(x) && x == -y))
    return V_INF_ADD_INF;
  prepare_inexact<Policy>(dir);
  if (fpu_direct_rounding(dir))
    to = x + y;
  else if (fpu_inverse_rounding(dir))
    to = -limit_precision(-x - y);
  else {
    fpu_rounding_control_word_type old = fpu_save_rounding_direction(dir);
    to = x + y;
    fpu_restore_rounding_direction(old);
  }
  return result_relation<Policy>(dir);
}

template <typename Policy, typename Type>
inline Result
sub_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (CHECK_P(Policy::check_nan_args, is_nan<Policy>(x))
      || CHECK_P(Policy::check_nan_args, is_nan<Policy>(y)))
    return VC_NAN;
  if (CHECK_P(Policy::check_inf_sub_inf, is_inf_float(x) && x == y))
    return V_INF_SUB_INF;
  prepare_inexact<Policy>(dir);
  if (fpu_direct_rounding(dir))
    to = x - y;
  else if (fpu_inverse_rounding(dir))
    to = -limit_precision(y - x);
  else {
    fpu_rounding_control_word_type old = fpu_save_rounding_direction(dir);
    to = x - y;
    fpu_restore_rounding_direction(old);
  }
  return result_relation<Policy>(dir);
}

template <typename Policy, typename Type>
inline Result
mul_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (CHECK_P(Policy::check_nan_args, is_nan<Policy>(x))
      || CHECK_P(Policy::check_nan_args, is_nan<Policy>(y)))
    return VC_NAN;
  if (CHECK_P(Policy::check_inf_mul_zero, (x == 0 && is_inf_float(y)) ||
	    (y == 0 && is_inf_float(x))))
      return V_INF_MUL_ZERO;
  prepare_inexact<Policy>(dir);
  if (fpu_direct_rounding(dir))
    to = x * y;
  else if (fpu_inverse_rounding(dir))
    to = -limit_precision(x * -y);
  else {
    fpu_rounding_control_word_type old = fpu_save_rounding_direction(dir);
    to = x * y;
    fpu_restore_rounding_direction(old);
  }
  return result_relation<Policy>(dir);
}

template <typename Policy, typename Type>
inline Result
div_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (CHECK_P(Policy::check_nan_args, is_nan<Policy>(x))
      || CHECK_P(Policy::check_nan_args, is_nan<Policy>(y)))
    return VC_NAN;
  if (CHECK_P(Policy::check_inf_div_inf, is_inf_float(x) && is_inf_float(y)))
      return V_INF_DIV_INF;
  if (CHECK_P(Policy::check_div_zero, y == 0)) {
    to = NAN;
    return V_DIV_ZERO;
  }
  prepare_inexact<Policy>(dir);
  if (fpu_direct_rounding(dir))
    to = x / y;
  else if (fpu_inverse_rounding(dir))
    to = -limit_precision(x / -y);
  else {
    fpu_rounding_control_word_type old = fpu_save_rounding_direction(dir);
    to = x / y;
    fpu_restore_rounding_direction(old);
  }
  return result_relation<Policy>(dir);
}

template <typename Policy, typename Type>
inline Result
rem_float(Type& to, const Type x, const Type y, Rounding_Dir) {
  if (CHECK_P(Policy::check_nan_args, is_nan<Policy>(x))
      || CHECK_P(Policy::check_nan_args, is_nan<Policy>(y)))
    return VC_NAN;
  if (CHECK_P(Policy::check_inf_mod, is_inf_float(x)))
    return V_INF_MOD;
  if (CHECK_P(Policy::check_div_zero, y == 0)) {
    to = NAN;
    return V_MOD_ZERO;
  }
  to = std::fmod(x, y);
  return V_EQ;
}

template <typename Policy, typename Type>
inline Result
mul2exp_float(Type& to, const Type x, int exp, Rounding_Dir dir) {
  if (exp < 0)
    return div2exp<Policy>(to, x, -exp, dir);
  assert(static_cast<unsigned int>(exp) < sizeof(unsigned long long) * 8);
  return mul<Policy>(to, x, static_cast<Type>(1ULL << exp), dir);
}

template <typename Policy, typename Type>
inline Result
div2exp_float(Type& to, const Type x, int exp, Rounding_Dir dir) {
  if (exp < 0)
    return mul2exp<Policy>(to, x, -exp, dir);
  assert(static_cast<unsigned int>(exp) < sizeof(unsigned long long) * 8);
  return div<Policy>(to, x, static_cast<Type>(1ULL << exp), dir);
}

template <typename Policy, typename Type>
inline Result
abs_float(Type& to, const Type from, Rounding_Dir) {
  if (CHECK_P(Policy::check_nan_args, is_nan<Policy>(from)))
    return VC_NAN;
  to = from < 0 ? -from : from;
  return V_EQ;
}

template <typename Policy, typename Type>
inline Result
sqrt_float(Type& to, const Type from, Rounding_Dir dir) {
  if (CHECK_P(Policy::check_nan_args, is_nan<Policy>(from)))
    return VC_NAN;
  if (CHECK_P(Policy::check_sqrt_neg, from < 0)) {
    to = NAN;
    return V_SQRT_NEG;
  }
  prepare_inexact<Policy>(dir);
  if (fpu_direct_rounding(dir))
    to = std::sqrt(from);
  else {
    fpu_rounding_control_word_type old = fpu_save_rounding_direction(dir);
    to = std::sqrt(from);
    fpu_restore_rounding_direction(old);
  }
  return result_relation<Policy>(dir);
}

template <typename Policy, typename Type>
inline Result
sgn_float(const Type x) {
  return classify<Policy>(x, false, false, true);
}

template <typename Policy, typename Type>
inline Result
cmp_float(const Type x, const Type y) {
  if (x > y)
    return V_GT;
  if (x < y)
    return V_LT;
  if (x == y)
    return V_EQ;
  return V_UNORD_COMP;
}

template <typename Policy, typename To, typename From>
inline Result
assign_float_int_exact(To& to, const From from, Rounding_Dir) {
  to = from;
  return V_EQ;
}

template <typename Policy, typename To, typename From>
inline Result
assign_float_int_inexact(To& to, const From from, Rounding_Dir dir) {
  prepare_inexact<Policy>(dir);
  if (fpu_direct_rounding(dir))
    to = from;
  else {
    fpu_rounding_control_word_type old = fpu_save_rounding_direction(dir);
    to = from;
    fpu_restore_rounding_direction(old);
  }
  return result_relation<Policy>(dir);
}

template <typename Policy, typename To, typename From>
inline Result
assign_float_int(To& to, const From from, Rounding_Dir dir) {
  if (sizeof(From) * 8 > Float<To>::Binary::MANTISSA_BITS)
    return assign_float_int_inexact<Policy>(to, from, dir);
  else
    return assign_float_int_exact<Policy>(to, from, dir);
}

template <typename Policy, typename T>
inline Result
set_neg_overflow_float(T& to, Rounding_Dir dir) {
  switch (dir) {
  case ROUND_UP:
    {
      Float<T> f;
      f.u.binary.set_max(true);
      to = f.value();
      return V_LT;
    }
  default:
    to = -HUGE_VAL;
    return V_GT;
  }
}

template <typename Policy, typename T>
inline Result
set_pos_overflow_float(T& to, Rounding_Dir dir) {
  switch (dir) {
  case ROUND_DOWN:
    {
      Float<T> f;
      f.u.binary.set_max(false);
      to = f.value();
      return V_GT;
    }
  default:
    to = HUGE_VAL;
    return V_LT;
  }
}

template <typename Policy, typename T>
inline Result
assign_float_mpz(T& to, const mpz_class& _from, Rounding_Dir dir)
{
  mpz_srcptr from = _from.get_mpz_t();
  int sign = mpz_sgn(from);
  if (sign == 0) {
    to = 0;
    return V_EQ;
  }
  size_t exponent = mpz_sizeinbase(from, 2) - 1;
  if (exponent > (size_t) Float<T>::Binary::EXPONENT_MAX) {
    if (sign < 0)
      return set_neg_overflow_float<Policy>(to, dir);
    else
      return set_pos_overflow_float<Policy>(to, dir);
  }
  unsigned long zeroes = mpn_scan1(from->_mp_d, 0);
  size_t meaningful_bits = exponent - zeroes;
  mpz_t mantissa;
  mpz_init(mantissa);
  if (exponent > Float<T>::Binary::MANTISSA_BITS)
    mpz_tdiv_q_2exp(mantissa,
		    from,
		    exponent - Float<T>::Binary::MANTISSA_BITS);
  else
    mpz_mul_2exp(mantissa, from, Float<T>::Binary::MANTISSA_BITS - exponent);
  Float<T> f(to);
  f.u.binary.build(sign < 0, mantissa, exponent);
  mpz_clear(mantissa);
  to = f.value();
  if (meaningful_bits > Float<T>::Binary::MANTISSA_BITS) {
    if (sign < 0)
      return round_lt_float<Policy>(to, dir);
    else
      return round_gt_float<Policy>(to, dir);
  }
  return V_EQ;
}

template <typename Policy, typename T>
inline Result
assign_float_mpq(T& to, const mpq_class& from, Rounding_Dir dir)
{
  const mpz_class& _num = from.get_num();
  const mpz_class& _den = from.get_den();
  if (_den == 1)
    return assign_float_mpz<Policy>(to, _num, dir);
  mpz_srcptr num = _num.get_mpz_t();
  mpz_srcptr den = _den.get_mpz_t();
  int sign = mpz_sgn(num);
  signed long exponent = mpz_sizeinbase(num, 2) - mpz_sizeinbase(den, 2);
  if (exponent < Float<T>::Binary::EXPONENT_MIN_DENORM) {
    to = 0;
  inexact:
    if (sign < 0)
      return round_lt_float<Policy>(to, dir);
    else
      return round_gt_float<Policy>(to, dir);
  }
  if (exponent > (signed int) Float<T>::Binary::EXPONENT_MAX + 1) {
  overflow:
    if (sign < 0)
      return set_neg_overflow_float<Policy>(to, dir);
    else
      return set_pos_overflow_float<Policy>(to, dir);
  }
  unsigned int needed_bits = Float<T>::Binary::MANTISSA_BITS + 1;
  if (exponent < Float<T>::Binary::EXPONENT_MIN)
    needed_bits -= Float<T>::Binary::EXPONENT_MIN - exponent;
  mpz_t mantissa;
  mpz_init(mantissa);
  signed long shift = needed_bits - exponent;
  if (shift > 0) {
    mpz_mul_2exp(mantissa, num, shift);
    num = mantissa;
  }
  else if (shift < 0) {
    mpz_mul_2exp(mantissa, den, -shift);
    den = mantissa;
  }
  mpz_t r;
  mpz_init(r);
  mpz_tdiv_qr(mantissa, r, num, den);
  size_t bits = mpz_sizeinbase(mantissa, 2);
  bool inexact = (mpz_sgn(r) != 0);
  mpz_clear(r);
  if (bits == needed_bits + 1) {
    inexact = (inexact || mpz_odd_p(mantissa));
    mpz_div_2exp(mantissa, mantissa, 1);
  }
  else
    --exponent;
  if (exponent > (signed int)Float<T>::Binary::EXPONENT_MAX) {
    mpz_clear(mantissa);
    goto overflow;
  } else if (exponent < Float<T>::Binary::EXPONENT_MIN - 1) {
    /* Denormalized */
    exponent = Float<T>::Binary::EXPONENT_MIN - 1;
  }
  Float<T> f(to);
  f.u.binary.build(sign < 0, mantissa, exponent);
  mpz_clear(mantissa);
  to = f.value();
  if (inexact)
    goto inexact;
  return V_EQ;
}

template <typename Policy, typename Type>
inline Result
add_mul_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (CHECK_P(Policy::check_nan_args, is_nan<Policy>(to))
      || CHECK_P(Policy::check_nan_args, is_nan<Policy>(x))
      || CHECK_P(Policy::check_nan_args, is_nan<Policy>(y)))
    return VC_NAN;
  prepare_inexact<Policy>(dir);
  if (fpu_direct_rounding(dir))
    to = fma(x, y, to);
  else if (fpu_inverse_rounding(dir))
    to = -limit_precision(fma(-x, y, -to));
  else {
    fpu_rounding_control_word_type old = fpu_save_rounding_direction(dir);
    to = fma(x, y, to);
    fpu_restore_rounding_direction(old);
  }
  return result_relation<Policy>(dir);
}

template <typename Policy, typename Type>
inline Result
sub_mul_float(Type& to, const Type x, const Type y, Rounding_Dir dir) {
  if (CHECK_P(Policy::check_nan_args, is_nan<Policy>(to))
      || CHECK_P(Policy::check_nan_args, is_nan<Policy>(x))
      || CHECK_P(Policy::check_nan_args, is_nan<Policy>(y)))
    return VC_NAN;
  prepare_inexact<Policy>(dir);
  if (fpu_direct_rounding(dir))
    to = fma(x, -y, to);
  else if (fpu_inverse_rounding(dir))
    to = -limit_precision(fma(x, y, -to));
  else {
    fpu_rounding_control_word_type old = fpu_save_rounding_direction(dir);
    to = fma(x, -y, to);
    fpu_restore_rounding_direction(old);
  }
  return result_relation<Policy>(dir);
}

template <typename Policy, typename Type>
inline Result
output_float(std::ostream& os, const Type from, const Numeric_Format&,
	     Rounding_Dir) {
  if (from == 0)
    os << "0";
  else if (is_minf<Policy>(from))
    os << "-inf";
  else if (is_pinf<Policy>(from))
    os << "+inf";
  else if (is_nan<Policy>(from))
    os << "nan";
  else {
    int old_precision = os.precision(10000);
    os << from;
    os.precision(old_precision);
  }
  return V_EQ;
}

template <typename Policy, typename To>
inline Result
assign_float_minf(To& to, const Minus_Infinity&, Rounding_Dir) {
  to = -HUGE_VAL;
  return V_EQ;
}

template <typename Policy, typename To>
inline Result
assign_float_pinf(To& to, const Plus_Infinity&, Rounding_Dir) {
  to = HUGE_VAL;
  return V_EQ;
}

template <typename Policy, typename To>
inline Result
assign_float_nan(To& to, const Not_A_Number&, Rounding_Dir) {
  to = NAN;
  return V_EQ;
}

#if PPL_SUPPORTED_FLOAT
SPECIALIZE_ASSIGN(float_float_exact, float, float)
#if PPL_SUPPORTED_DOUBLE
SPECIALIZE_ASSIGN(float_float, float, double)
SPECIALIZE_ASSIGN(float_float_exact, double, float)
#endif
#if PPL_SUPPORTED_LONG_DOUBLE
SPECIALIZE_ASSIGN(float_float, float, long double)
SPECIALIZE_ASSIGN(float_float_exact, long double, float)
#endif
#endif

#if PPL_SUPPORTED_DOUBLE
SPECIALIZE_ASSIGN(float_float_exact, double, double)
#if PPL_SUPPORTED_LONG_DOUBLE
SPECIALIZE_ASSIGN(float_float, double, long double)
SPECIALIZE_ASSIGN(float_float_exact, long double, double)
#endif
#endif

#if PPL_SUPPORTED_LONG_DOUBLE
SPECIALIZE_ASSIGN(float_float_exact, long double, long double)
#endif

#if PPL_SUPPORTED_FLOAT
SPECIALIZE_CLASSIFY(float, float)
SPECIALIZE_IS_NAN(float, float)
SPECIALIZE_IS_MINF(float, float)
SPECIALIZE_IS_PINF(float, float)
SPECIALIZE_SET_SPECIAL(float, float)
SPECIALIZE_ASSIGN(float_int, float, signed char)
SPECIALIZE_ASSIGN(float_int, float, signed short)
SPECIALIZE_ASSIGN(float_int, float, signed int)
SPECIALIZE_ASSIGN(float_int, float, signed long)
SPECIALIZE_ASSIGN(float_int, float, signed long long)
SPECIALIZE_ASSIGN(float_int, float, unsigned char)
SPECIALIZE_ASSIGN(float_int, float, unsigned short)
SPECIALIZE_ASSIGN(float_int, float, unsigned int)
SPECIALIZE_ASSIGN(float_int, float, unsigned long)
SPECIALIZE_ASSIGN(float_int, float, unsigned long long)
SPECIALIZE_ASSIGN(float_mpz, float, mpz_class)
SPECIALIZE_ASSIGN(float_mpq, float, mpq_class)
SPECIALIZE_COPY(generic, float)
SPECIALIZE_IS_INT(float, float)
SPECIALIZE_ASSIGN(float_minf, float, Minus_Infinity)
SPECIALIZE_ASSIGN(float_pinf, float, Plus_Infinity)
SPECIALIZE_ASSIGN(float_nan, float, Not_A_Number)
SPECIALIZE_NEG(float, float, float)
SPECIALIZE_ABS(float, float, float)
SPECIALIZE_ADD(float, float, float, float)
SPECIALIZE_SUB(float, float, float, float)
SPECIALIZE_MUL(float, float, float, float)
SPECIALIZE_DIV(float, float, float, float)
SPECIALIZE_REM(float, float, float, float)
SPECIALIZE_MUL2EXP(float, float, float)
SPECIALIZE_DIV2EXP(float, float, float)
SPECIALIZE_SQRT(float, float, float)
SPECIALIZE_GCD(exact, float, float, float)
SPECIALIZE_GCDEXT(exact, float, float, float, float, float)
SPECIALIZE_LCM(gcd_exact, float, float, float)
SPECIALIZE_SGN(float, float)
SPECIALIZE_CMP(float, float, float)
SPECIALIZE_ADD_MUL(float, float, float, float)
SPECIALIZE_SUB_MUL(float, float, float, float)
SPECIALIZE_INPUT(generic, float)
SPECIALIZE_OUTPUT(float, float)
#endif

#if PPL_SUPPORTED_DOUBLE
SPECIALIZE_CLASSIFY(float, double)
SPECIALIZE_IS_NAN(float, double)
SPECIALIZE_IS_MINF(float, double)
SPECIALIZE_IS_PINF(float, double)
SPECIALIZE_SET_SPECIAL(float, double)
SPECIALIZE_ASSIGN(float_int, double, signed char)
SPECIALIZE_ASSIGN(float_int, double, signed short)
SPECIALIZE_ASSIGN(float_int, double, signed int)
SPECIALIZE_ASSIGN(float_int, double, signed long)
SPECIALIZE_ASSIGN(float_int, double, signed long long)
SPECIALIZE_ASSIGN(float_int, double, unsigned char)
SPECIALIZE_ASSIGN(float_int, double, unsigned short)
SPECIALIZE_ASSIGN(float_int, double, unsigned int)
SPECIALIZE_ASSIGN(float_int, double, unsigned long)
SPECIALIZE_ASSIGN(float_int, double, unsigned long long)
SPECIALIZE_ASSIGN(float_mpz, double, mpz_class)
SPECIALIZE_ASSIGN(float_mpq, double, mpq_class)
SPECIALIZE_COPY(generic, double)
SPECIALIZE_IS_INT(float, double)
SPECIALIZE_ASSIGN(float_minf, double, Minus_Infinity)
SPECIALIZE_ASSIGN(float_pinf, double, Plus_Infinity)
SPECIALIZE_ASSIGN(float_nan, double, Not_A_Number)
SPECIALIZE_NEG(float, double, double)
SPECIALIZE_ABS(float, double, double)
SPECIALIZE_ADD(float, double, double, double)
SPECIALIZE_SUB(float, double, double, double)
SPECIALIZE_MUL(float, double, double, double)
SPECIALIZE_DIV(float, double, double, double)
SPECIALIZE_REM(float, double, double, double)
SPECIALIZE_MUL2EXP(float, double, double)
SPECIALIZE_DIV2EXP(float, double, double)
SPECIALIZE_SQRT(float, double, double)
SPECIALIZE_GCD(exact, double, double, double)
SPECIALIZE_GCDEXT(exact, double, double, double, double, double)
SPECIALIZE_LCM(gcd_exact, double, double, double)
SPECIALIZE_SGN(float, double)
SPECIALIZE_CMP(float, double, double)
SPECIALIZE_ADD_MUL(float, double, double, double)
SPECIALIZE_SUB_MUL(float, double, double, double)
SPECIALIZE_INPUT(generic, double)
SPECIALIZE_OUTPUT(float, double)
#endif

#if PPL_SUPPORTED_LONG_DOUBLE
SPECIALIZE_CLASSIFY(float, long double)
SPECIALIZE_IS_NAN(float, long double)
SPECIALIZE_IS_MINF(float, long double)
SPECIALIZE_IS_PINF(float, long double)
SPECIALIZE_SET_SPECIAL(float, long double)
SPECIALIZE_ASSIGN(float_int, long double, signed char)
SPECIALIZE_ASSIGN(float_int, long double, signed short)
SPECIALIZE_ASSIGN(float_int, long double, signed int)
SPECIALIZE_ASSIGN(float_int, long double, signed long)
SPECIALIZE_ASSIGN(float_int, long double, signed long long)
SPECIALIZE_ASSIGN(float_int, long double, unsigned char)
SPECIALIZE_ASSIGN(float_int, long double, unsigned short)
SPECIALIZE_ASSIGN(float_int, long double, unsigned int)
SPECIALIZE_ASSIGN(float_int, long double, unsigned long)
SPECIALIZE_ASSIGN(float_int, long double, unsigned long long)
SPECIALIZE_ASSIGN(float_mpz, long double, mpz_class)
SPECIALIZE_ASSIGN(float_mpq, long double, mpq_class)
SPECIALIZE_COPY(generic, long double)
SPECIALIZE_IS_INT(float, long double)
SPECIALIZE_ASSIGN(float_minf, long double, Minus_Infinity)
SPECIALIZE_ASSIGN(float_pinf, long double, Plus_Infinity)
SPECIALIZE_ASSIGN(float_nan, long double, Not_A_Number)
SPECIALIZE_NEG(float, long double, long double)
SPECIALIZE_ABS(float, long double, long double)
SPECIALIZE_ADD(float, long double, long double, long double)
SPECIALIZE_SUB(float, long double, long double, long double)
SPECIALIZE_MUL(float, long double, long double, long double)
SPECIALIZE_DIV(float, long double, long double, long double)
SPECIALIZE_REM(float, long double, long double, long double)
SPECIALIZE_MUL2EXP(float, long double, long double)
SPECIALIZE_DIV2EXP(float, long double, long double)
SPECIALIZE_SQRT(float, long double, long double)
SPECIALIZE_GCD(exact, long double, long double, long double)
SPECIALIZE_GCDEXT(exact, long double, long double, long double,
		  long double, long double)
SPECIALIZE_LCM(gcd_exact, long double, long double, long double)
SPECIALIZE_SGN(float, long double)
SPECIALIZE_CMP(float, long double, long double)
SPECIALIZE_ADD_MUL(float, long double, long double, long double)
SPECIALIZE_SUB_MUL(float, long double, long double, long double)
SPECIALIZE_INPUT(generic, long double)
SPECIALIZE_OUTPUT(float, long double)
#endif

} // namespace Checked

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/checked_mpz.inlines.hh line 1
/* Specialized "checked" functions for GMP's mpz_class numbers.
*/


namespace Parma_Polyhedra_Library {

namespace Checked {

template <typename Policy>
inline Result
round_lt_mpz(mpz_class& to, Rounding_Dir dir) {
  if (dir == ROUND_DOWN) {
    --to;
    return V_GT;
  }
  return V_LT;
}

template <typename Policy>
inline Result
round_gt_mpz(mpz_class& to, Rounding_Dir dir) {
  if (dir == ROUND_UP) {
    ++to;
    return V_LT;
  }
  return V_GT;
}

// FIXME: change this when Autoconf will support AC_C_TYPEOF.
#ifdef __GNUC__
//! Type of the _mp_size field of GMP's __mpz_struct.
typedef __typeof__(__mpz_struct()._mp_size) mp_size_field_t;
#else
//! This is assumed to be the type of the _mp_size field of GMP's __mpz_struct.
typedef int mp_size_field_t;
#endif

inline mp_size_field_t
get_mp_size(const mpz_class &v) {
  return v.get_mpz_t()->_mp_size;
}

inline void
set_mp_size(mpz_class &v, mp_size_field_t size) {
  v.get_mpz_t()->_mp_size = size;
}

template <typename Policy>
inline Result
classify_mpz(const mpz_class& v, bool nan, bool inf, bool sign) {
  if (Policy::handle_nan || Policy::handle_infinity) {
    mp_size_field_t s = get_mp_size(v);
    if (Policy::handle_nan
	&& (nan || sign)
	&& s == Limits<mp_size_field_t>::min + 1)
      return VC_NAN;
    if (!inf && !sign)
      return VC_NORMAL;
    if (Policy::handle_infinity) {
      if (s == Limits<mp_size_field_t>::min)
	return inf ? VC_MINUS_INFINITY : V_LT;
      if (s == Limits<mp_size_field_t>::max)
	return inf ? VC_PLUS_INFINITY : V_GT;
    }
  }
  if (sign)
    return sgn<Policy>(v);
  return VC_NORMAL;
}

SPECIALIZE_CLASSIFY(mpz, mpz_class)

template <typename Policy>
inline bool
is_nan_mpz(const mpz_class& v) {
  return Policy::handle_nan
    && get_mp_size(v) == Limits<mp_size_field_t>::min + 1;
}

SPECIALIZE_IS_NAN(mpz, mpz_class)

template <typename Policy>
inline bool
is_minf_mpz(const mpz_class& v) {
  return Policy::handle_infinity
    && get_mp_size(v) == Limits<mp_size_field_t>::min;
}

SPECIALIZE_IS_MINF(mpz, mpz_class)

template <typename Policy>
inline bool
is_pinf_mpz(const mpz_class& v) {
  return Policy::handle_infinity
    && get_mp_size(v) == Limits<mp_size_field_t>::max;
}

SPECIALIZE_IS_PINF(mpz, mpz_class)

template <typename Policy>
inline bool
is_int_mpz(const mpz_class& v) {
  return !is_nan<Policy>(v);
}

SPECIALIZE_IS_INT(mpz, mpz_class)

template <typename Policy>
inline Result
set_special_mpz(mpz_class& v, Result r) {
  Result c = classify(r);
  if (Policy::handle_nan && c == VC_NAN)
    set_mp_size(v, Limits<mp_size_field_t>::min + 1);
  else if (Policy::handle_infinity) {
    switch (c) {
    case VC_MINUS_INFINITY:
      set_mp_size(v, Limits<mp_size_field_t>::min);
      break;
    case VC_PLUS_INFINITY:
      set_mp_size(v, Limits<mp_size_field_t>::max);
      break;
    default:
      break;
    }
  }
  return r;
}

SPECIALIZE_SET_SPECIAL(mpz, mpz_class)

template <typename Policy>
inline void
copy_mpz(mpz_class& to, const mpz_class& from) {
  if (is_nan_mpz<Policy>(from) ||
      is_minf_mpz<Policy>(from) || is_pinf_mpz<Policy>(from))
    set_mp_size(to, get_mp_size(from));
  else
    to = from;
}

SPECIALIZE_COPY(mpz, mpz_class)

template <typename Policy, typename From>
inline Result
construct_mpz_base(mpz_class& to, const From from, Rounding_Dir) {
    new (&to) mpz_class(from);
    return V_EQ;
}

SPECIALIZE_CONSTRUCT(mpz_base, mpz_class, signed char)
SPECIALIZE_CONSTRUCT(mpz_base, mpz_class, signed short)
SPECIALIZE_CONSTRUCT(mpz_base, mpz_class, signed int)
SPECIALIZE_CONSTRUCT(mpz_base, mpz_class, signed long)
SPECIALIZE_CONSTRUCT(mpz_base, mpz_class, unsigned char)
SPECIALIZE_CONSTRUCT(mpz_base, mpz_class, unsigned short)
SPECIALIZE_CONSTRUCT(mpz_base, mpz_class, unsigned int)
SPECIALIZE_CONSTRUCT(mpz_base, mpz_class, unsigned long)

template <typename Policy, typename From>
inline Result
assign_mpz_base(mpz_class& to, const From from, Rounding_Dir) {
    to = static_cast<signed long>(from);
    return V_EQ;
}

SPECIALIZE_ASSIGN(mpz_base, mpz_class, signed char)
SPECIALIZE_ASSIGN(mpz_base, mpz_class, signed short)
SPECIALIZE_ASSIGN(mpz_base, mpz_class, signed int)
SPECIALIZE_ASSIGN(mpz_base, mpz_class, signed long)
SPECIALIZE_ASSIGN(mpz_base, mpz_class, unsigned char)
SPECIALIZE_ASSIGN(mpz_base, mpz_class, unsigned short)
SPECIALIZE_ASSIGN(mpz_base, mpz_class, unsigned int)
SPECIALIZE_ASSIGN(mpz_base, mpz_class, unsigned long)

template <typename Policy, typename From>
inline Result
assign_mpz_signed_int(mpz_class& to, const From from, Rounding_Dir) {
  if (sizeof(From) <= sizeof(signed long))
    to = static_cast<signed long>(from);
  else {
    mpz_ptr m = to.get_mpz_t();
    if (from >= 0)
      mpz_import(m, 1, 1, sizeof(From), 0, 0, &from);
    else {
      From n = -from;
      mpz_import(m, 1, 1, sizeof(From), 0, 0, &n);
      mpz_neg(m, m);
    }
  }
  return V_EQ;
}

SPECIALIZE_ASSIGN(mpz_signed_int, mpz_class, signed long long)

template <typename Policy, typename From>
inline Result
assign_mpz_unsigned_int(mpz_class& to, const From from, Rounding_Dir) {
  if (sizeof(From) <= sizeof(unsigned long))
    to = static_cast<unsigned long>(from);
  else
    mpz_import(to.get_mpz_t(), 1, 1, sizeof(From), 0, 0, &from);
  return V_EQ;
}

SPECIALIZE_ASSIGN(mpz_unsigned_int, mpz_class, unsigned long long)

template <typename Policy, typename From>
inline Result
assign_mpz_float(mpz_class& to, const From from, Rounding_Dir dir) {
  if (dir == ROUND_IGNORE) {
    to = from;
    return V_LGE;
  }
  From n = rint(from);
  to = n;
  if (from < n)
    return round_lt_mpz<Policy>(to, dir);
  else if (from > n)
    return round_gt_mpz<Policy>(to, dir);
  else
    return V_EQ;
}

SPECIALIZE_ASSIGN(mpz_float, mpz_class, float)
SPECIALIZE_ASSIGN(mpz_float, mpz_class, double)

template <typename Policy>
inline Result
assign_mpz_mpq(mpz_class& to, const mpq_class& from, Rounding_Dir dir) {
  if (dir == ROUND_IGNORE) {
    to = from;
    return V_LGE;
  }
  mpz_srcptr n = from.get_num().get_mpz_t();
  mpz_srcptr d = from.get_den().get_mpz_t();
  if (dir == ROUND_DOWN) {
    mpz_fdiv_q(to.get_mpz_t(), n, d);
    return mpz_divisible_p(n, d) ? V_EQ : V_GT;
  }
  else {
    assert(dir == ROUND_UP);
    mpz_cdiv_q(to.get_mpz_t(), n, d);
    return mpz_divisible_p(n, d) ? V_EQ : V_LT;
  }
}

SPECIALIZE_ASSIGN(mpz_mpq, mpz_class, mpq_class)

template <typename Policy, typename To>
inline Result
assign_mp_minf(To& to, const Minus_Infinity&, Rounding_Dir) {
  if (Policy::handle_infinity) {
    set_special<Policy>(to, VC_MINUS_INFINITY);
    return V_EQ;
  }
  return VC_MINUS_INFINITY;
}

template <typename Policy, typename To>
inline Result
assign_mp_pinf(To& to, const Plus_Infinity&, Rounding_Dir) {
  if (Policy::handle_infinity) {
    set_special<Policy>(to, VC_PLUS_INFINITY);
    return V_EQ;
  }
  return VC_PLUS_INFINITY;
}

template <typename Policy, typename To>
inline Result
assign_mp_nan(To& to, const Not_A_Number&, Rounding_Dir) {
  if (Policy::handle_nan) {
    set_special<Policy>(to, VC_NAN);
    return V_EQ;
  }
  return VC_NAN;
}

SPECIALIZE_ASSIGN(mp_minf, mpz_class, Minus_Infinity)
SPECIALIZE_ASSIGN(mp_pinf, mpz_class, Plus_Infinity)
SPECIALIZE_ASSIGN(mp_nan, mpz_class, Not_A_Number)
SPECIALIZE_ASSIGN(mp_minf, mpq_class, Minus_Infinity)
SPECIALIZE_ASSIGN(mp_pinf, mpq_class, Plus_Infinity)
SPECIALIZE_ASSIGN(mp_nan, mpq_class, Not_A_Number)

template <typename Policy>
inline Result
neg_mpz(mpz_class& to, const mpz_class& from, Rounding_Dir) {
  mpz_neg(to.get_mpz_t(), from.get_mpz_t());
  return V_EQ;
}

SPECIALIZE_NEG(mpz, mpz_class, mpz_class)

template <typename Policy>
inline Result
add_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y, Rounding_Dir) {
  to = x + y;
  return V_EQ;
}

SPECIALIZE_ADD(mpz, mpz_class, mpz_class, mpz_class)

template <typename Policy>
inline Result
sub_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y, Rounding_Dir) {
  to = x - y;
  return V_EQ;
}

SPECIALIZE_SUB(mpz, mpz_class, mpz_class, mpz_class)

template <typename Policy>
inline Result
mul_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y, Rounding_Dir) {
  to = x * y;
  return V_EQ;
}

SPECIALIZE_MUL(mpz, mpz_class, mpz_class, mpz_class)

template <typename Policy>
inline Result
div_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y,
	Rounding_Dir dir) {
  if (CHECK_P(Policy::check_div_zero, ::sgn(y) == 0))
    return set_special<Policy>(to, V_DIV_ZERO);
  mpz_srcptr n = x.get_mpz_t();
  mpz_srcptr d = y.get_mpz_t();
  if (dir == ROUND_IGNORE) {
    mpz_divexact(to.get_mpz_t(), n, d);
    return V_LGE;
  }
  if (dir == ROUND_DOWN) {
    mpz_fdiv_q(to.get_mpz_t(), n, d);
    return mpz_divisible_p(n, d) ? V_EQ : V_GT;
  }
  else {
    assert(dir == ROUND_UP);
    mpz_cdiv_q(to.get_mpz_t(), n, d);
    return mpz_divisible_p(n, d) ? V_EQ : V_LT;
  }
}

SPECIALIZE_DIV(mpz, mpz_class, mpz_class, mpz_class)

template <typename Policy>
inline Result
rem_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y, Rounding_Dir) {
  if (CHECK_P(Policy::check_div_zero, ::sgn(y) == 0))
    return set_special<Policy>(to, V_MOD_ZERO);
  to = x % y;
  return V_EQ;
}

SPECIALIZE_REM(mpz, mpz_class, mpz_class, mpz_class)

template <typename Policy>
inline Result
mul2exp_mpz(mpz_class& to, const mpz_class& x, int exp, Rounding_Dir dir) {
  if (exp < 0)
    return div2exp<Policy>(to, x, -exp, dir);
  mpz_mul_2exp(to.get_mpz_t(), x.get_mpz_t(), exp);
  return V_EQ;
}

SPECIALIZE_MUL2EXP(mpz, mpz_class, mpz_class)

template <typename Policy>
inline Result
div2exp_mpz(mpz_class& to, const mpz_class& x, int exp, Rounding_Dir dir) {
  if (exp < 0)
    return mul2exp<Policy>(to, x, -exp, dir);
  mpz_srcptr n = x.get_mpz_t();
  if (dir == ROUND_IGNORE) {
    mpz_tdiv_q_2exp(to.get_mpz_t(), x.get_mpz_t(), exp);
    return V_LGE;
  }
  if (dir == ROUND_DOWN) {
    mpz_fdiv_q_2exp(to.get_mpz_t(), n, exp);
    return mpz_divisible_2exp_p(n, exp) ? V_EQ : V_GT;
  }
  else {
    assert(dir == ROUND_UP);
    mpz_cdiv_q_2exp(to.get_mpz_t(), n, exp);
    return mpz_divisible_2exp_p(n, exp) ? V_EQ : V_LT;
  }
}

SPECIALIZE_DIV2EXP(mpz, mpz_class, mpz_class)

template <typename Policy>
inline Result
abs_mpz(mpz_class& to, const mpz_class& from, Rounding_Dir) {
  to = abs(from);
  return V_EQ;
}

SPECIALIZE_ABS(mpz, mpz_class, mpz_class)

template <typename Policy>
inline Result
add_mul_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y,
	    Rounding_Dir) {
  mpz_addmul(to.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t());
  return V_EQ;
}

SPECIALIZE_ADD_MUL(mpz, mpz_class, mpz_class, mpz_class)

template <typename Policy>
inline Result
sub_mul_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y,
	    Rounding_Dir) {
  mpz_submul(to.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t());
  return V_EQ;
}

SPECIALIZE_SUB_MUL(mpz, mpz_class, mpz_class, mpz_class)

template <typename Policy>
inline Result
gcd_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y, Rounding_Dir) {
  mpz_gcd(to.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t());
  return V_EQ;
}

SPECIALIZE_GCD(mpz, mpz_class, mpz_class, mpz_class)

template <typename Policy>
inline Result
gcdext_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y,
	   mpz_class& s, mpz_class& t, Rounding_Dir) {
  mpz_gcdext(to.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t(),
	     s.get_mpz_t(), t.get_mpz_t());
  return V_EQ;
}

SPECIALIZE_GCDEXT(mpz, mpz_class, mpz_class, mpz_class, mpz_class, mpz_class)

template <typename Policy>
inline Result
lcm_mpz(mpz_class& to, const mpz_class& x, const mpz_class& y, Rounding_Dir) {
  mpz_lcm(to.get_mpz_t(), x.get_mpz_t(), y.get_mpz_t());
  return V_EQ;
}

SPECIALIZE_LCM(mpz, mpz_class, mpz_class, mpz_class)

template <typename Policy>
inline Result
sqrt_mpz(mpz_class& to, const mpz_class& from, Rounding_Dir dir) {
  if (CHECK_P(Policy::check_sqrt_neg, from < 0))
    return set_special<Policy>(to, V_SQRT_NEG);
  if (dir == ROUND_IGNORE) {
    to = sqrt(from);
    return V_GE;
  }
  mpz_class r;
  mpz_sqrtrem(to.get_mpz_t(), r.get_mpz_t(), from.get_mpz_t());
  if (r == 0)
    return V_EQ;
  return round_gt_mpz<Policy>(to, dir);
}

SPECIALIZE_SQRT(mpz, mpz_class, mpz_class)

template <typename Policy, typename Type>
inline Result
sgn_mp(const Type& x) {
  int i = ::sgn(x);
  return i > 0 ? V_GT : i == 0 ? V_EQ : V_LT;
}

SPECIALIZE_SGN(mp, mpz_class)
SPECIALIZE_SGN(mp, mpq_class)

template <typename Policy, typename Type>
inline Result
cmp_mp(const Type& x, const Type& y) {
  int i = ::cmp(x, y);
  return i > 0 ? V_GT : i == 0 ? V_EQ : V_LT;
}

SPECIALIZE_CMP(mp, mpz_class, mpz_class)
SPECIALIZE_CMP(mp, mpq_class, mpq_class)

template <typename Policy>
inline Result
output_mpz(std::ostream& os, const mpz_class& from, const Numeric_Format&,
	   Rounding_Dir) {
  os << from;
  return V_EQ;
}

SPECIALIZE_INPUT(generic, mpz_class)
SPECIALIZE_OUTPUT(mpz, mpz_class)

inline memory_size_type
external_memory_in_bytes(const mpz_class& x) {
  return x.get_mpz_t()[0]._mp_alloc * SIZEOF_MP_LIMB_T;
}

} // namespace Checked

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/checked_mpq.inlines.hh line 1
/* Specialized "checked" functions for GMP's mpq_class numbers.
*/


#include <sstream>
#include <climits>
#include <stdexcept>

namespace Parma_Polyhedra_Library {

namespace Checked {

template <typename Policy>
inline Result
classify_mpq(const mpq_class& v, bool nan, bool inf, bool sign) {
  if ((Policy::handle_nan || Policy::handle_infinity)
      && ::sgn(v.get_den()) == 0) {
    int s = ::sgn(v.get_num());
    if (Policy::handle_nan && (nan || sign) && s == 0)
      return VC_NAN;
    if (!inf && !sign)
      return VC_NORMAL;
    if (Policy::handle_infinity) {
      if (s < 0)
	return inf ? VC_MINUS_INFINITY : V_LT;
      if (s > 0)
	return inf ? VC_PLUS_INFINITY : V_GT;
    }
  }
  if (sign)
    return sgn<Policy>(v);
  return VC_NORMAL;
}

SPECIALIZE_CLASSIFY(mpq, mpq_class)

template <typename Policy>
inline bool
is_nan_mpq(const mpq_class& v) {
  return Policy::handle_nan
    && ::sgn(v.get_den()) == 0
    && ::sgn(v.get_num()) == 0;
}

SPECIALIZE_IS_NAN(mpq, mpq_class)

template <typename Policy>
inline bool
is_minf_mpq(const mpq_class& v) {
  return Policy::handle_infinity
    && ::sgn(v.get_den()) == 0
    && ::sgn(v.get_num()) < 0;
}

SPECIALIZE_IS_MINF(mpq, mpq_class)

template <typename Policy>
inline bool
is_pinf_mpq(const mpq_class& v) {
  return Policy::handle_infinity
    && ::sgn(v.get_den()) == 0
    && ::sgn(v.get_num()) > 0;
}

SPECIALIZE_IS_PINF(mpq, mpq_class)

template <typename Policy>
inline bool
is_int_mpq(const mpq_class& v) {
  return !is_nan<Policy>(v) && v.get_den() == 1;
}

SPECIALIZE_IS_INT(mpq, mpq_class)

template <typename Policy>
inline Result
set_special_mpq(mpq_class& v, Result r) {
  Result c = classify(r);
  if (Policy::handle_nan && c == VC_NAN) {
    v.get_num() = 0;
    v.get_den() = 0;
  }
  else if (Policy::handle_infinity) {
    switch (c) {
    case VC_MINUS_INFINITY:
      v.get_num() = -1;
      v.get_den() = 0;
      break;
    case VC_PLUS_INFINITY:
      v.get_num() = 1;
      v.get_den() = 0;
      break;
    default:
      break;
    }
  }
  return r;
}

SPECIALIZE_SET_SPECIAL(mpq, mpq_class)

SPECIALIZE_COPY(generic, mpq_class)

template <typename Policy, typename From>
inline Result
construct_mpq_base(mpq_class& to, const From& from, Rounding_Dir) {
  new (&to) mpq_class(from);
  return V_EQ;
}

SPECIALIZE_CONSTRUCT(mpq_base, mpq_class, mpz_class)
SPECIALIZE_CONSTRUCT(mpq_base, mpq_class, signed char)
SPECIALIZE_CONSTRUCT(mpq_base, mpq_class, signed short)
SPECIALIZE_CONSTRUCT(mpq_base, mpq_class, signed int)
SPECIALIZE_CONSTRUCT(mpq_base, mpq_class, signed long)
SPECIALIZE_CONSTRUCT(mpq_base, mpq_class, unsigned char)
SPECIALIZE_CONSTRUCT(mpq_base, mpq_class, unsigned short)
SPECIALIZE_CONSTRUCT(mpq_base, mpq_class, unsigned int)
SPECIALIZE_CONSTRUCT(mpq_base, mpq_class, unsigned long)
SPECIALIZE_CONSTRUCT(mpq_base, mpq_class, float)
SPECIALIZE_CONSTRUCT(mpq_base, mpq_class, double)

template <typename Policy, typename From>
inline Result
construct_mpq_long_double(mpq_class& to, const From& from, Rounding_Dir dir) {
  // FIXME: this is an incredibly inefficient implementation!
  new (&to) mpq_class;
  std::stringstream ss;
  output_float<Policy, long double>(ss, from, Numeric_Format(), dir);
  return input_mpq(to, ss);
}

SPECIALIZE_CONSTRUCT(mpq_long_double, mpq_class, long double)

template <typename Policy, typename From>
inline Result
assign_mpq_base(mpq_class& to, const From& from, Rounding_Dir) {
  to = from;
  return V_EQ;
}

SPECIALIZE_ASSIGN(mpq_base, mpq_class, mpz_class)
SPECIALIZE_ASSIGN(mpq_base, mpq_class, signed char)
SPECIALIZE_ASSIGN(mpq_base, mpq_class, signed short)
SPECIALIZE_ASSIGN(mpq_base, mpq_class, signed int)
SPECIALIZE_ASSIGN(mpq_base, mpq_class, signed long)
SPECIALIZE_ASSIGN(mpq_base, mpq_class, unsigned char)
SPECIALIZE_ASSIGN(mpq_base, mpq_class, unsigned short)
SPECIALIZE_ASSIGN(mpq_base, mpq_class, unsigned int)
SPECIALIZE_ASSIGN(mpq_base, mpq_class, unsigned long)
SPECIALIZE_ASSIGN(mpq_base, mpq_class, float)
SPECIALIZE_ASSIGN(mpq_base, mpq_class, double)

template <typename Policy, typename From>
inline Result
assign_mpq_signed_int(mpq_class& to, const From from, Rounding_Dir) {
  if (sizeof(From) <= sizeof(signed long))
    to = static_cast<signed long>(from);
  else {
    mpz_ptr m = to.get_num().get_mpz_t();
    if (from >= 0)
      mpz_import(m, 1, 1, sizeof(From), 0, 0, &from);
    else {
      From n = -from;
      mpz_import(m, 1, 1, sizeof(From), 0, 0, &n);
      mpz_neg(m, m);
    }
    to.get_den() = 1;
  }
  return V_EQ;
}

SPECIALIZE_ASSIGN(mpq_signed_int, mpq_class, signed long long)

template <typename Policy, typename From>
inline Result
assign_mpq_unsigned_int(mpq_class& to, const From from, Rounding_Dir) {
  if (sizeof(From) <= sizeof(unsigned long))
    to = static_cast<unsigned long>(from);
  else {
    mpz_import(to.get_num().get_mpz_t(), 1, 1, sizeof(From), 0, 0, &from);
    to.get_den() = 1;
  }
  return V_EQ;
}

SPECIALIZE_ASSIGN(mpq_unsigned_int, mpq_class, unsigned long long)

template <typename Policy, typename From>
inline Result
assign_mpq_long_double(mpq_class& to, const From& from, Rounding_Dir dir) {
  // FIXME: this is an incredibly inefficient implementation!
  std::stringstream ss;
  output_float<Policy, long double>(ss, from, Numeric_Format(), dir);
  return input_mpq(to, ss);
}

SPECIALIZE_ASSIGN(mpq_long_double, mpq_class, long double)

template <typename Policy>
inline Result
neg_mpq(mpq_class& to, const mpq_class& from, Rounding_Dir) {
  mpq_neg(to.get_mpq_t(), from.get_mpq_t());
  return V_EQ;
}

SPECIALIZE_NEG(mpq, mpq_class, mpq_class)

template <typename Policy>
inline Result
add_mpq(mpq_class& to, const mpq_class& x, const mpq_class& y, Rounding_Dir) {
  to = x + y;
  return V_EQ;
}

SPECIALIZE_ADD(mpq, mpq_class, mpq_class, mpq_class)

template <typename Policy>
inline Result
sub_mpq(mpq_class& to, const mpq_class& x, const mpq_class& y, Rounding_Dir) {
  to = x - y;
  return V_EQ;
}

SPECIALIZE_SUB(mpq, mpq_class, mpq_class, mpq_class)

template <typename Policy>
inline Result
mul_mpq(mpq_class& to, const mpq_class& x, const mpq_class& y, Rounding_Dir) {
  to = x * y;
  return V_EQ;
}

SPECIALIZE_MUL(mpq, mpq_class, mpq_class, mpq_class)

template <typename Policy>
inline Result
div_mpq(mpq_class& to, const mpq_class& x, const mpq_class& y, Rounding_Dir) {
  if (CHECK_P(Policy::check_div_zero, sgn(y) == 0))
    return set_special<Policy>(to, V_DIV_ZERO);
  to = x / y;
  return V_EQ;
}

SPECIALIZE_DIV(mpq, mpq_class, mpq_class, mpq_class)

template <typename Policy>
inline Result
rem_mpq(mpq_class& to, const mpq_class& x, const mpq_class& y, Rounding_Dir) {
  if (CHECK_P(Policy::check_div_zero, sgn(y) == 0))
    return set_special<Policy>(to, V_MOD_ZERO);
  to = x / y;
  to.get_num() %= to.get_den();
  return V_EQ;
}

SPECIALIZE_REM(mpq, mpq_class, mpq_class, mpq_class)

template <typename Policy>
inline Result
mul2exp_mpq(mpq_class& to, const mpq_class& x, int exp, Rounding_Dir dir) {
  if (exp < 0)
    return div2exp<Policy>(to, x, -exp, dir);
  mpz_mul_2exp(to.get_num().get_mpz_t(), x.get_num().get_mpz_t(), exp);
  to.get_den() = x.get_den();
  to.canonicalize();
  return V_EQ;
}

SPECIALIZE_MUL2EXP(mpq, mpq_class, mpq_class)

template <typename Policy>
inline Result
div2exp_mpq(mpq_class& to, const mpq_class& x, int exp, Rounding_Dir dir) {
  if (exp < 0)
    return mul2exp<Policy>(to, x, -exp, dir);
  to.get_num() = x.get_num();
  mpz_mul_2exp(to.get_den().get_mpz_t(), x.get_den().get_mpz_t(), exp);
  to.canonicalize();
  return V_EQ;
}

SPECIALIZE_DIV2EXP(mpq, mpq_class, mpq_class)

template <typename Policy>
inline Result
abs_mpq(mpq_class& to, const mpq_class& from, Rounding_Dir) {
  to = abs(from);
  return V_EQ;
}

SPECIALIZE_ABS(mpq, mpq_class, mpq_class)

template <typename Policy>
inline Result
add_mul_mpq(mpq_class& to, const mpq_class& x, const mpq_class& y,
	    Rounding_Dir) {
  to += x * y;
  return V_EQ;
}

SPECIALIZE_ADD_MUL(mpq, mpq_class, mpq_class, mpq_class)

template <typename Policy>
inline Result
sub_mul_mpq(mpq_class& to, const mpq_class& x, const mpq_class& y,
	    Rounding_Dir) {
  to -= x * y;
  return V_EQ;
}

SPECIALIZE_SUB_MUL(mpq, mpq_class, mpq_class, mpq_class)

extern unsigned long rational_sqrt_precision_parameter;

template <typename Policy>
inline Result
sqrt_mpq(mpq_class& to, const mpq_class& from, Rounding_Dir dir) {
  if (CHECK_P(Policy::check_sqrt_neg, from < 0))
    return set_special<Policy>(to, V_SQRT_NEG);
  const unsigned long k = rational_sqrt_precision_parameter;
  mpz_class& to_num = to.get_num();
  mul2exp<Policy>(to_num, from.get_num(), 2*k, dir);
  Result rdiv = div<Policy>(to_num, to_num, from.get_den(), dir);
  Result rsqrt = sqrt<Policy>(to_num, to_num, dir);
  mpz_class& to_den = to.get_den();
  to_den = 1;
  mul2exp<Policy>(to_den, to_den, k, dir);
  to.canonicalize();
  return rdiv != V_EQ ? rdiv : rsqrt;
}

SPECIALIZE_SQRT(mpq, mpq_class, mpq_class)

template <typename Policy>
inline Result
input_mpq(mpq_class& to, std::istream& is, Rounding_Dir dir) {
  Result r = input_mpq(to, is);
  if (r == VC_MINUS_INFINITY)
    return assign<Policy>(to, MINUS_INFINITY, dir);
  if (r == VC_PLUS_INFINITY)
    return assign<Policy>(to, PLUS_INFINITY, dir);
  return set_special<Policy>(to, r);
}

template <typename Policy>
inline Result
output_mpq(std::ostream& os,
	   const mpq_class& from,
	   const Numeric_Format&,
	   Rounding_Dir) {
  os << from;
  return V_EQ;
}

SPECIALIZE_INPUT(mpq, mpq_class)
SPECIALIZE_OUTPUT(mpq, mpq_class)

inline memory_size_type
external_memory_in_bytes(const mpq_class& x) {
  return external_memory_in_bytes(x.get_num())
    + external_memory_in_bytes(x.get_den());
}

} // namespace Checked

//! Returns the precision parameter used for rational square root calculations.
inline unsigned
rational_sqrt_precision_parameter() {
  return Checked::rational_sqrt_precision_parameter;
}

//! Sets the precision parameter used for rational square root calculations.
/*!
  If \p p is less than or equal to <CODE>INT_MAX</CODE>, sets the
  precision parameter used for rational square root calculations to \p p.

  \exception std::invalid_argument
  Thrown if \p p is greater than <CODE>INT_MAX</CODE>.
*/
inline void
set_rational_sqrt_precision_parameter(const unsigned p) {
  if (p <= INT_MAX)
    Checked::rational_sqrt_precision_parameter = p;
  else
    throw std::invalid_argument("PPL::set_rational_sqrt_precision_parameter(p)"
				" with p > INT_MAX");
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/checked_ext.inlines.hh line 1
/* Checked extended arithmetic functions.
*/

namespace Parma_Polyhedra_Library {

namespace Checked {

#define handle_ext_natively(T) (Float<T>::fpu_related)

template <typename Policy, typename Type>
inline Result
sgn_ext(const Type& x) {
  if (CHECK_P(Policy::check_nan_args, is_nan<Policy>(x)))
    return VC_NAN;
  else if (is_minf<Policy>(x))
    return V_LT;
  else if (is_pinf<Policy>(x))
    return V_GT;
  else
    return sgn<Policy>(x);
}

template <typename To_Policy, typename From_Policy,
	  typename To, typename From>
inline Result
construct_ext(To& to, const From& from, Rounding_Dir dir) {
  if (handle_ext_natively(To) && handle_ext_natively(From))
    goto native;
  if (CHECK_P(From_Policy::check_nan_args, is_nan<From_Policy>(from)))
    return construct<To_Policy>(to, NOT_A_NUMBER, dir);
  else if (is_minf<From_Policy>(from))
    return construct<To_Policy>(to, MINUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(from))
    return construct<To_Policy>(to, PLUS_INFINITY, dir);
  else {
  native:
    return construct<To_Policy>(to, from, dir);
  }
}

template <typename To_Policy, typename From_Policy,
	  typename To, typename From>
inline Result
assign_ext(To& to, const From& from, Rounding_Dir dir) {
  if (handle_ext_natively(To) && handle_ext_natively(From))
    goto native;
  if (CHECK_P(From_Policy::check_nan_args, is_nan<From_Policy>(from)))
    return set_special<To_Policy>(to, VC_NAN);
  else if (is_minf<From_Policy>(from))
    return assign<To_Policy>(to, MINUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(from))
    return assign<To_Policy>(to, PLUS_INFINITY, dir);
  else {
  native:
    return assign<To_Policy>(to, from, dir);
  }
}

template <typename To_Policy, typename From_Policy,
	  typename To, typename From>
inline Result
neg_ext(To& to, const From& x, Rounding_Dir dir) {
  if (handle_ext_natively(To) && handle_ext_natively(From))
    goto native;
  if (CHECK_P(From_Policy::check_nan_args, is_nan<From_Policy>(x)))
    return set_special<To_Policy>(to, VC_NAN);
  else if (is_minf<From_Policy>(x))
    return assign<To_Policy>(to, PLUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(x))
    return assign<To_Policy>(to, MINUS_INFINITY, dir);
  else {
  native:
    return neg<To_Policy>(to, x, dir);
  }
}

template <typename To_Policy, typename From_Policy,
	  typename To, typename From>
inline Result
abs_ext(To& to, const From& x, Rounding_Dir dir) {
  if (handle_ext_natively(To) && handle_ext_natively(From))
    goto native;
  if (CHECK_P(From_Policy::check_nan_args, is_nan<From_Policy>(x)))
    return set_special<To_Policy>(to, VC_NAN);
  else if (is_minf<From_Policy>(x) || is_pinf<From_Policy>(x))
    return assign<To_Policy>(to, PLUS_INFINITY, dir);
  else {
  native:
    return abs<To_Policy>(to, x, dir);
  }
}

template <typename To_Policy, typename From1_Policy, typename From2_Policy,
	  typename To, typename From1, typename From2>
inline Result
add_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
  if (handle_ext_natively(To)
      && handle_ext_natively(From1)
      && handle_ext_natively(From2))
    goto native;
  if (CHECK_P(From1_Policy::check_nan_args, is_nan<From1_Policy>(x))
      || CHECK_P(From2_Policy::check_nan_args, is_nan<From2_Policy>(y)))
    return set_special<To_Policy>(to, VC_NAN);
  else if (is_minf<From1_Policy>(x)) {
    if (CHECK_P(To_Policy::check_inf_add_inf, is_pinf<From2_Policy>(y)))
      goto inf_add_inf;
    else
      goto minf;
  }
  else if (is_pinf<From1_Policy>(x)) {
    if (CHECK_P(To_Policy::check_inf_add_inf, is_minf<From2_Policy>(y))) {
    inf_add_inf:
      return set_special<To_Policy>(to, V_INF_ADD_INF);
    }
    else
      goto pinf;
  }
  else {
    if (is_minf<From2_Policy>(y)) {
    minf:
      return assign<To_Policy>(to, MINUS_INFINITY, dir);
    }
    else if (is_pinf<From2_Policy>(y)) {
    pinf:
      return assign<To_Policy>(to, PLUS_INFINITY, dir);
    }
    else {
    native:
      return add<To_Policy>(to, x, y, dir);
    }
  }
}

template <typename To_Policy, typename From1_Policy, typename From2_Policy,
	  typename To, typename From1, typename From2>
inline Result
sub_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
  if (handle_ext_natively(To)
      && handle_ext_natively(From1)
      && handle_ext_natively(From2))
    goto native;
  if (CHECK_P(From1_Policy::check_nan_args, is_nan<From1_Policy>(x))
      || CHECK_P(From2_Policy::check_nan_args, is_nan<From2_Policy>(y)))
    return set_special<To_Policy>(to, VC_NAN);
  else if (is_minf<From1_Policy>(x)) {
    if (CHECK_P(To_Policy::check_inf_sub_inf, is_minf<From2_Policy>(y)))
      goto inf_sub_inf;
    else
      goto minf;
  }
  else if (is_pinf<From1_Policy>(x)) {
    if (CHECK_P(To_Policy::check_inf_sub_inf, is_pinf<From2_Policy>(y))) {
    inf_sub_inf:
      return set_special<To_Policy>(to, V_INF_SUB_INF);
    }
    else
      goto pinf;
  }
  else {
    if (is_pinf<From2_Policy>(y)) {
    minf:
      return assign<To_Policy>(to, MINUS_INFINITY, dir);
    }
    else if (is_minf<From2_Policy>(y)) {
    pinf:
      return assign<To_Policy>(to, PLUS_INFINITY, dir);
    }
    else {
    native:
      return sub<To_Policy>(to, x, y, dir);
    }
  }
}

template <typename To_Policy, typename From1_Policy, typename From2_Policy,
	  typename To, typename From1, typename From2>
inline Result
mul_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
  if (handle_ext_natively(To)
      && handle_ext_natively(From1)
      && handle_ext_natively(From2))
    goto native;
  if (CHECK_P(From1_Policy::check_nan_args, is_nan<From1_Policy>(x))
      || CHECK_P(From2_Policy::check_nan_args, is_nan<From2_Policy>(y)))
    return set_special<To_Policy>(to, VC_NAN);
  if (is_minf<From1_Policy>(x)) {
    switch (sgn_ext<From2_Policy>(y)) {
    case V_LT:
      goto pinf;
    case V_GT:
      goto minf;
    default:
      goto inf_mul_zero;
    }
  }
  else if (is_pinf<From1_Policy>(x)) {
    switch (sgn_ext<From2_Policy>(y)) {
    case V_LT:
      goto minf;
    case V_GT:
      goto pinf;
    default:
      goto inf_mul_zero;
    }
  }
  else {
    if (is_minf<From2_Policy>(y)) {
      switch (sgn<From1_Policy>(x)) {
      case V_LT:
	goto pinf;
      case V_GT:
	goto minf;
      default:
	goto inf_mul_zero;
      }
    } else if (is_pinf<From2_Policy>(y)) {
      switch (sgn<From1_Policy>(x)) {
      case V_LT:
      minf:
	return assign<To_Policy>(to, MINUS_INFINITY, dir);
      case V_GT:
      pinf:
	return assign<To_Policy>(to, PLUS_INFINITY, dir);
	goto pinf;
      default:
      inf_mul_zero:
	assert(To_Policy::check_inf_mul_zero);
	return set_special<To_Policy>(to, V_INF_MUL_ZERO);
      }
    }
    else {
    native:
      return mul<To_Policy>(to, x, y, dir);
    }
  }
}


template <typename To_Policy, typename From1_Policy, typename From2_Policy,
	  typename To, typename From1, typename From2>
inline Result
add_mul_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
  if (handle_ext_natively(To)
      && handle_ext_natively(From1)
      && handle_ext_natively(From2))
    goto native;
  if (CHECK_P(To_Policy::check_nan_args, is_nan<To_Policy>(to))
      || CHECK_P(From1_Policy::check_nan_args, is_nan<From1_Policy>(x))
      || CHECK_P(From2_Policy::check_nan_args, is_nan<From2_Policy>(y)))
    return set_special<To_Policy>(to, VC_NAN);
  if (is_minf<From1_Policy>(x)) {
    switch (sgn_ext<From2_Policy>(y)) {
    case V_LT:
      goto a_pinf;
    case V_GT:
      goto a_minf;
    default:
      goto inf_mul_zero;
    }
  }
  else if (is_pinf<From1_Policy>(x)) {
    switch (sgn_ext<From2_Policy>(y)) {
    case V_LT:
      goto a_minf;
    case V_GT:
      goto a_pinf;
    default:
      goto inf_mul_zero;
    }
  }
  else {
    if (is_minf<From2_Policy>(y)) {
      switch (sgn<From1_Policy>(x)) {
      case V_LT:
	goto a_pinf;
      case V_GT:
	goto a_minf;
      default:
	goto inf_mul_zero;
      }
    } else if (is_pinf<From2_Policy>(y)) {
      switch (sgn<From1_Policy>(x)) {
      case V_LT:
      a_minf:
	if (CHECK_P(To_Policy::check_inf_add_inf, is_pinf<To_Policy>(to)))
	  goto inf_add_inf;
	else
	  goto minf;
      case V_GT:
      a_pinf:
	if (CHECK_P(To_Policy::check_inf_add_inf, is_minf<To_Policy>(to))) {
	inf_add_inf:
	  return set_special<To_Policy>(to, V_INF_ADD_INF);
	}
	else
	  goto pinf;
      default:
      inf_mul_zero:
	assert(To_Policy::check_inf_mul_zero);
	return set_special<To_Policy>(to, V_INF_MUL_ZERO);
      }
    }
    else {
      if (is_minf<To_Policy>(to)) {
      minf:
	return assign<To_Policy>(to, MINUS_INFINITY, dir);
      }
      if (is_pinf<To_Policy>(to)) {
      pinf:
	return assign<To_Policy>(to, PLUS_INFINITY, dir);
      }
    native:
      return add_mul<To_Policy>(to, x, y, dir);
    }
  }
}

template <typename To_Policy, typename From1_Policy, typename From2_Policy,
	  typename To, typename From1, typename From2>
inline Result
sub_mul_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
  if (handle_ext_natively(To)
      && handle_ext_natively(From1)
      && handle_ext_natively(From2))
    goto native;
  if (CHECK_P(To_Policy::check_nan_args, is_nan<To_Policy>(to))
      || CHECK_P(From1_Policy::check_nan_args, is_nan<From1_Policy>(x))
      || CHECK_P(From2_Policy::check_nan_args, is_nan<From2_Policy>(y)))
    return set_special<To_Policy>(to, VC_NAN);
  if (is_minf<From1_Policy>(x)) {
    switch (sgn_ext<From2_Policy>(y)) {
    case V_LT:
      goto a_pinf;
    case V_GT:
      goto a_minf;
    default:
      goto inf_mul_zero;
    }
  }
  else if (is_pinf<From1_Policy>(x)) {
    switch (sgn_ext<From2_Policy>(y)) {
    case V_LT:
      goto a_minf;
    case V_GT:
      goto a_pinf;
    default:
      goto inf_mul_zero;
    }
  }
  else {
    if (is_minf<From2_Policy>(y)) {
      switch (sgn<From1_Policy>(x)) {
      case V_LT:
	goto a_pinf;
      case V_GT:
	goto a_minf;
      default:
	goto inf_mul_zero;
      }
    } else if (is_pinf<From2_Policy>(y)) {
      switch (sgn<From1_Policy>(x)) {
      case V_LT:
      a_minf:
	if (CHECK_P(To_Policy::check_inf_sub_inf, is_minf<To_Policy>(to)))
	  goto inf_sub_inf;
	else
	  goto pinf;
      case V_GT:
      a_pinf:
	if (CHECK_P(To_Policy::check_inf_sub_inf, is_pinf<To_Policy>(to))) {
	inf_sub_inf:
	  return set_special<To_Policy>(to, V_INF_SUB_INF);
	}
	else
	  goto minf;
      default:
      inf_mul_zero:
	assert(To_Policy::check_inf_mul_zero);
	return set_special<To_Policy>(to, V_INF_MUL_ZERO);
      }
    }
    else {
      if (is_minf<To_Policy>(to)) {
      minf:
	return assign<To_Policy>(to, MINUS_INFINITY, dir);
      }
      if (is_pinf<To_Policy>(to)) {
      pinf:
	return assign<To_Policy>(to, PLUS_INFINITY, dir);
      }
    native:
      return sub_mul<To_Policy>(to, x, y, dir);
    }
  }
}

template <typename To_Policy, typename From1_Policy, typename From2_Policy,
	  typename To, typename From1, typename From2>
inline Result
div_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
  if (handle_ext_natively(To)
      && handle_ext_natively(From1)
      && handle_ext_natively(From2))
    goto native;
  if (CHECK_P(From1_Policy::check_nan_args, is_nan<From1_Policy>(x))
      || CHECK_P(From2_Policy::check_nan_args, is_nan<From2_Policy>(y)))
    return set_special<To_Policy>(to, VC_NAN);
  if (is_minf<From1_Policy>(x)) {
    if (CHECK_P(To_Policy::check_inf_div_inf, is_minf<From2_Policy>(y)
		|| is_pinf<From2_Policy>(y)))
      goto inf_div_inf;
    else {
      switch (sgn<From2_Policy>(y)) {
      case V_LT:
	goto pinf;
      case V_GT:
	goto minf;
      default:
	goto div_zero;
      }
    }
  }
  else if (is_pinf<From1_Policy>(x)) {
    if (CHECK_P(To_Policy::check_inf_div_inf, is_minf<From2_Policy>(y)
		|| is_pinf<From2_Policy>(y))) {
    inf_div_inf:
      return set_special<To_Policy>(to, V_INF_DIV_INF);
    }
    else {
      switch (sgn<From2_Policy>(y)) {
      case V_LT:
      minf:
	return assign<To_Policy>(to, MINUS_INFINITY, dir);
      case V_GT:
      pinf:
	return assign<To_Policy>(to, PLUS_INFINITY, dir);
      default:
      div_zero:
	assert(To_Policy::check_div_zero);
	return set_special<To_Policy>(to, V_DIV_ZERO);
      }
    }
  }
  else {
    if (is_minf<From2_Policy>(y) || is_pinf<From2_Policy>(y)) {
      to = 0;
      return V_EQ;
    }
    else {
    native:
      return div<To_Policy>(to, x, y, dir);
    }
  }
}


template <typename To_Policy, typename From1_Policy, typename From2_Policy,
	  typename To, typename From1, typename From2>
inline Result
rem_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
  if (handle_ext_natively(To)
      && handle_ext_natively(From1)
      && handle_ext_natively(From2))
    goto native;
  if (CHECK_P(From1_Policy::check_nan_args, is_nan<From1_Policy>(x))
      || CHECK_P(From2_Policy::check_nan_args, is_nan<From2_Policy>(y)))
    return set_special<To_Policy>(to, VC_NAN);
  else if (CHECK_P(To_Policy::check_inf_mod, is_minf<From1_Policy>(x)
		   || is_pinf<From1_Policy>(x)))
    return set_special<To_Policy>(to, V_INF_MOD);
  else {
    if (is_minf<From1_Policy>(y) || is_pinf<From2_Policy>(y)) {
      to = x;
      return V_EQ;
    }
    else {
    native:
      return rem<To_Policy>(to, x, y, dir);
    }
  }
}

template <typename To_Policy, typename From_Policy,
	  typename To, typename From>
inline Result
mul2exp_ext(To& to, const From& x, int exp, Rounding_Dir dir) {
  if (handle_ext_natively(To) && handle_ext_natively(From))
    goto native;
  if (CHECK_P(From_Policy::check_nan_args, is_nan<From_Policy>(x)))
    return set_special<To_Policy>(to, VC_NAN);
  else if (is_minf<From_Policy>(x))
    return assign<To_Policy>(to, MINUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(x))
    return assign<To_Policy>(to, PLUS_INFINITY, dir);
  else {
  native:
    return mul2exp<To_Policy>(to, x, exp, dir);
  }
}

template <typename To_Policy, typename From_Policy,
	  typename To, typename From>
inline Result
div2exp_ext(To& to, const From& x, int exp, Rounding_Dir dir) {
  if (handle_ext_natively(To) && handle_ext_natively(From))
    goto native;
  if (CHECK_P(From_Policy::check_nan_args, is_nan<From_Policy>(x)))
    return set_special<To_Policy>(to, VC_NAN);
  else if (is_minf<From_Policy>(x))
    return assign<To_Policy>(to, MINUS_INFINITY, dir);
  else if (is_pinf<From_Policy>(x))
    return assign<To_Policy>(to, PLUS_INFINITY, dir);
  else {
  native:
    return div2exp<To_Policy>(to, x, exp, dir);
  }
}

template <typename To_Policy, typename From_Policy,
	  typename To, typename From>
inline Result
sqrt_ext(To& to, const From& x, Rounding_Dir dir) {
  if (handle_ext_natively(To) && handle_ext_natively(From))
    goto native;
  if (CHECK_P(From_Policy::check_nan_args, is_nan<From_Policy>(x)))
    return set_special<To_Policy>(to, VC_NAN);
  else if (is_minf<From_Policy>(x))
    return set_special<To_Policy>(to, V_SQRT_NEG);
  else if (is_pinf<From_Policy>(x))
    return assign<To_Policy>(to, PLUS_INFINITY, dir);
  else {
  native:
    return sqrt<To_Policy>(to, x, dir);
  }
}

template <typename To_Policy, typename From1_Policy, typename From2_Policy,
	  typename To, typename From1, typename From2>
inline Result
gcd_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
  if (CHECK_P(From1_Policy::check_nan_args, is_nan<From1_Policy>(x))
      || CHECK_P(From2_Policy::check_nan_args, is_nan<From2_Policy>(y)))
    return set_special<To_Policy>(to, VC_NAN);
  else if (is_minf<From1_Policy>(x) || is_pinf<From1_Policy>(x))
    return abs_ext<To_Policy, From2_Policy>(to, y, dir);
  else if (is_minf<From2_Policy>(y) || is_pinf<From2_Policy>(y))
    return abs_ext<To_Policy, From1_Policy>(to, x, dir);
  else
    return gcd<To_Policy>(to, x, y, dir);
}

template <typename To1_Policy, typename From1_Policy, typename From2_Policy,
	  typename To2_Policy, typename To3_Policy,
	  typename To1, typename From1, typename From2, typename To2, typename To3>
inline Result
gcdext_ext(To1& to, const From1& x, const From2& y,
	   To2& s, To3& t, Rounding_Dir dir) {
  if (CHECK_P(From1_Policy::check_nan_args, is_nan<From1_Policy>(x))
      || CHECK_P(From2_Policy::check_nan_args, is_nan<From2_Policy>(y)))
    return set_special<To1_Policy>(to, VC_NAN);
  else if (is_minf<From1_Policy>(x) || is_pinf<From1_Policy>(x)) {
    s = 0;
    t = y > 0 ? -1 : 1;
    return abs_ext<To1_Policy, From2_Policy>(to, y, dir);
  }
  else if (is_minf<From2_Policy>(y) || is_pinf<From2_Policy>(y)) {
    s = x > 0 ? -1 : 1;
    t = 0;
    return abs_ext<To1_Policy, From1_Policy>(to, x, dir);
  }
  else
    return gcdext<To1_Policy>(to, x, y, s, t, dir);
}

template <typename To_Policy, typename From1_Policy, typename From2_Policy,
	  typename To, typename From1, typename From2>
inline Result
lcm_ext(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
  if (CHECK_P(From1_Policy::check_nan_args, is_nan<From1_Policy>(x))
      || CHECK_P(From2_Policy::check_nan_args, is_nan<From2_Policy>(y)))
    return set_special<To_Policy>(to, VC_NAN);
  else if (is_minf<From1_Policy>(x) || is_pinf<From1_Policy>(x)
	   || is_minf<From2_Policy>(y) || is_pinf<From2_Policy>(y))
    return assign<To_Policy>(to, PLUS_INFINITY, dir);
  else
    return lcm<To_Policy>(to, x, y, dir);
}

template <typename Policy1, typename Policy2,
	  typename Type1, typename Type2>
inline Result
cmp_ext(const Type1& x, const Type2& y) {
  if (handle_ext_natively(Type1) && handle_ext_natively(Type2))
    goto native;
  if (CHECK_P(Policy1::check_nan_args, is_nan<Policy1>(x))
      || CHECK_P(Policy2::check_nan_args, is_nan<Policy2>(y)))
    return V_UNORD_COMP;
  else if (is_minf<Policy1>(x))
    return is_minf<Policy2>(y) ? V_EQ : V_LT;
  else if (is_pinf<Policy1>(x))
    return is_pinf<Policy2>(y) ? V_EQ : V_GT;
  else {
    if (is_minf<Policy2>(y))
      return V_GT;
    if (is_pinf<Policy2>(y))
      return V_LT;
  native:
    return cmp<Policy1>(x, y);
  }
}

template <typename Policy1, typename Policy2,
	  typename Type1, typename Type2>
inline bool
lt_ext(const Type1& x, const Type2& y) {
  if (handle_ext_natively(Type1) && handle_ext_natively(Type2))
    goto native;
  if (CHECK_P(Policy1::check_nan_args, is_nan<Policy1>(x))
      || CHECK_P(Policy2::check_nan_args, is_nan<Policy2>(y)))
    return false;
  if (is_pinf<Policy1>(x) || is_minf<Policy2>(y))
    return false;
  if (is_minf<Policy1>(x) || is_pinf<Policy2>(y))
    return true;
 native:
  return x < y;
}

template <typename Policy1, typename Policy2,
	  typename Type1, typename Type2>
inline bool
gt_ext(const Type1& x, const Type2& y) {
  if (handle_ext_natively(Type1) && handle_ext_natively(Type2))
    goto native;
  if (CHECK_P(Policy1::check_nan_args, is_nan<Policy1>(x))
      || CHECK_P(Policy2::check_nan_args, is_nan<Policy2>(y)))
    return false;
  if (is_minf<Policy1>(x) || is_pinf<Policy2>(y))
    return false;
  if (is_pinf<Policy1>(x) || is_minf<Policy2>(y))
    return true;
 native:
  return x > y;
}

template <typename Policy1, typename Policy2,
	  typename Type1, typename Type2>
inline bool
le_ext(const Type1& x, const Type2& y) {
  if (handle_ext_natively(Type1) && handle_ext_natively(Type2))
    goto native;
  if (CHECK_P(Policy1::check_nan_args, is_nan<Policy1>(x))
      || CHECK_P(Policy2::check_nan_args, is_nan<Policy2>(y)))
    return false;
  if (is_minf<Policy1>(x) || is_pinf<Policy2>(y))
    return true;
  if (is_pinf<Policy1>(x) || is_minf<Policy2>(y))
    return false;
 native:
  return x <= y;
}

template <typename Policy1, typename Policy2,
	  typename Type1, typename Type2>
inline bool
ge_ext(const Type1& x, const Type2& y) {
  if (handle_ext_natively(Type1) && handle_ext_natively(Type2))
    goto native;
  if (CHECK_P(Policy1::check_nan_args, is_nan<Policy1>(x))
      || CHECK_P(Policy2::check_nan_args, is_nan<Policy2>(y)))
    return false;
  if (is_pinf<Policy1>(x) || is_minf<Policy2>(y))
    return true;
  if (is_minf<Policy1>(x) || is_pinf<Policy2>(y))
    return false;
 native:
  return x >= y;
}

template <typename Policy1, typename Policy2,
	  typename Type1, typename Type2>
inline bool
eq_ext(const Type1& x, const Type2& y) {
  if (handle_ext_natively(Type1) && handle_ext_natively(Type2))
    goto native;
  if (CHECK_P(Policy1::check_nan_args, is_nan<Policy1>(x))
      || CHECK_P(Policy2::check_nan_args, is_nan<Policy2>(y)))
    return false;
  if (is_minf<Policy1>(x))
    return is_minf<Policy2>(y);
  if (is_pinf<Policy1>(x))
    return is_pinf<Policy2>(y);
 native:
  return x == y;
}

template <typename Policy1, typename Policy2,
	  typename Type1, typename Type2>
inline bool
ne_ext(const Type1& x, const Type2& y) {
  if (handle_ext_natively(Type1) && handle_ext_natively(Type2))
    goto native;
  if (CHECK_P(Policy1::check_nan_args, is_nan<Policy1>(x))
      || CHECK_P(Policy2::check_nan_args, is_nan<Policy2>(y)))
    return true;
  if (is_minf<Policy1>(x))
    return !is_minf<Policy2>(y);
  if (is_pinf<Policy1>(x))
    return !is_pinf<Policy2>(y);
 native:
  return x != y;
}

template <typename Policy, typename Type>
inline Result
output_ext(std::ostream& os, const Type& x,
	   const Numeric_Format& format, Rounding_Dir dir) {
  if (handle_ext_natively(Type))
    goto native;
  if (CHECK_P(Policy::check_nan_args, is_nan<Policy>(x))) {
    os << "nan";
    return VC_NAN;
  }
  if (is_minf<Policy>(x)) {
    os << "-inf";
    return V_EQ;
  }
  if (is_pinf<Policy>(x)) {
    os << "+inf";
    return V_EQ;
  }
 native:
  return output<Policy>(os, x, format, dir);
}

template <typename To_Policy, typename To>
inline Result
input_ext(To& to, std::istream& is, Rounding_Dir dir) {
  return input<To_Policy>(to, is, dir);
}

} // namespace Checked

} // namespace Parma_Polyhedra_Library
// Automatically generated from PPL source file ../src/checked.defs.hh line 391

// Automatically generated from PPL source file ../src/Checked_Number.defs.hh line 28

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
struct Checked_Number_Transparent_Policy {
  //! Checks for overflowed result.
  static const int check_overflow = 0;

  //! Checks for attempts to add infinities with different sign.
  static const int check_inf_add_inf = 0;

  //! Checks for attempts to sub infinities with same sign.
  static const int check_inf_sub_inf = 0;

  //! Checks for attempts to mul infinities by zero.
  static const int check_inf_mul_zero = 0;

  //! Checks for attempts to divide by zero.
  static const int check_div_zero = 0;

  //! Checks for attempts to divide infinities.
  static const int check_inf_div_inf = 0;

  //! Checks for attempts to compute remainder of infinities.
  static const int check_inf_mod = 0;

  //! Checks for attempts to take the square root of a negative number.
  static const int check_sqrt_neg = 0;

  //! Handles not-a-number special value.
  static const int handle_nan = 0;

  //! Handles infinity special values.
  static const int handle_infinity = 0;

  //! Representation is identical to primitive.
  static const int convertible = 1;

  //! Checks for FPU inexact result.
  static const int fpu_check_inexact = 0;

  //! Checks for NaN arguments
  static const int check_nan_args = 0;
  static const Rounding_Dir ROUND_DEFAULT_CONSTRUCTOR = ROUND_NATIVE;
  static const Rounding_Dir ROUND_DEFAULT_OPERATOR = ROUND_NATIVE;
  static const Rounding_Dir ROUND_DEFAULT_FUNCTION = ROUND_NATIVE;
  static const Rounding_Dir ROUND_DEFAULT_INPUT = ROUND_NATIVE;
  static const Rounding_Dir ROUND_DEFAULT_OUTPUT = ROUND_NATIVE;
  static void handle_result(Result r);
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
struct Checked_Number_Default_Policy {
  static const int check_overflow = 1;
  static const int check_inf_add_inf = 0;
  static const int check_inf_sub_inf = 0;
  static const int check_inf_mul_zero = 0;
  static const int check_div_zero = 0;
  static const int check_inf_div_inf = 0;
  static const int check_inf_mod = 0;
  static const int check_sqrt_neg = 0;
  static const int handle_nan = 0;
  static const int handle_infinity = 0;
  static const int convertible = 1;
  static const int fpu_check_inexact = 0;
  static const int check_nan_args = 1;
  static const Rounding_Dir ROUND_DEFAULT_CONSTRUCTOR = ROUND_NATIVE;
  static const Rounding_Dir ROUND_DEFAULT_OPERATOR = ROUND_NATIVE;
  static const Rounding_Dir ROUND_DEFAULT_FUNCTION = ROUND_NATIVE;
  static const Rounding_Dir ROUND_DEFAULT_INPUT = ROUND_NATIVE;
  static const Rounding_Dir ROUND_DEFAULT_OUTPUT = ROUND_NATIVE;
  static void handle_result(Result r);
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
struct Extended_Number_Policy {
  static const int check_overflow = 1;
  static const int check_inf_add_inf = 0;
  static const int check_inf_sub_inf = 0;
  static const int check_inf_mul_zero = 0;
  static const int check_div_zero = 0;
  static const int check_inf_div_inf = 0;
  static const int check_inf_mod = 0;
  static const int check_sqrt_neg = 0;
  static const int handle_nan = 1;
  static const int handle_infinity = 1;
  // Don't uncomment the following.
  // The compile time error on conversions is the expected behaviour.
  // static const int convertible = 0;
#ifdef DEBUG_ROUND_NOT_NEEDED
  static const int fpu_check_inexact = 1;
#else
  static const int fpu_check_inexact = 0;
#endif
  static const int check_nan_args = 1;
  static const Rounding_Dir ROUND_DEFAULT_CONSTRUCTOR_INF = ROUND_NOT_NEEDED;
  static const Rounding_Dir ROUND_DEFAULT_ASSIGN_INF = ROUND_NOT_NEEDED;
  // Don't uncomment the following.
  // The compile time error is the expected behaviour.
  // static const Rounding_Dir ROUND_DEFAULT_CONSTRUCTOR = ROUND_UP;
  // static const Rounding_Dir ROUND_DEFAULT_OPERATOR = ROUND_UP;
  // static const Rounding_Dir ROUND_DEFAULT_FUNCTION = ROUND_UP;
  // static const Rounding_Dir ROUND_DEFAULT_INPUT = ROUND_UP;
  // static const Rounding_Dir ROUND_DEFAULT_OUTPUT = ROUND_UP;
  static void handle_result(Result r);
};

typedef Checked::Check_Overflow_Policy Default_To_Policy;
typedef Checked_Number_Transparent_Policy Default_From_Policy;

template <typename T>
struct Native_Checked_From_Wrapper {
  typedef Default_From_Policy Policy;
  static const T& raw_value(const T& v) {
    return v;
  }
};

template <typename T, typename P>
struct Native_Checked_From_Wrapper<Checked_Number<T, P> > {
  typedef P Policy;
  static const T& raw_value(const Checked_Number<T, P>& v) {
    return v.raw_value();
  }
};

template <typename T>
struct Native_Checked_To_Wrapper {
  typedef Default_To_Policy Policy;
  static T& raw_value(T& v) {
    return v;
  }
};

template <typename T, typename P>
struct Native_Checked_To_Wrapper<Checked_Number<T, P> > {
  typedef P Policy;
  static T& raw_value(Checked_Number<T, P>& v) {
    return v.raw_value();
  }
};

//! A wrapper for numeric types implementing a given policy.
/*! \ingroup PPL_CXX_interface
  The wrapper and related functions implement an interface which is common
  to all kinds of coefficient types, therefore allowing for a uniform
  coding style. This class also implements the policy encoded by the
  second template parameter. The default policy is to perform the detection
  of overflow errors.
*/
template <typename T, typename Policy>
class Checked_Number {
public:

  //! \name Constructors
  //@{

  //! Default constructor.
  Checked_Number();

  //! Copy-constructor.
  Checked_Number(const Checked_Number& y);

  //! Direct initialization from a Checked_Number and rounding mode.
  template <typename From, typename From_Policy>
  Checked_Number(const Checked_Number<From, From_Policy>& y, Rounding_Dir dir);

  //! Direct initialization from a signed char and rounding mode.
  Checked_Number(const signed char y, Rounding_Dir dir);

  //! Direct initialization from a signed short and rounding mode.
  Checked_Number(const signed short y, Rounding_Dir dir);

  //! Direct initialization from a signed int and rounding mode.
  Checked_Number(const signed int y, Rounding_Dir dir);

  //! Direct initialization from a signed long and rounding mode.
  Checked_Number(const signed long y, Rounding_Dir dir);

  //! Direct initialization from a signed long long and rounding mode.
  Checked_Number(const signed long long y, Rounding_Dir dir);

  //! Direct initialization from an unsigned char and rounding mode.
  Checked_Number(const unsigned char y, Rounding_Dir dir);

  //! Direct initialization from an unsigned short and rounding mode.
  Checked_Number(const unsigned short y, Rounding_Dir dir);

  //! Direct initialization from an unsigned int and rounding mode.
  Checked_Number(const unsigned int y, Rounding_Dir dir);

  //! Direct initialization from an unsigned long and rounding mode.
  Checked_Number(const unsigned long y, Rounding_Dir dir);

  //! Direct initialization from an unsigned long long and rounding mode.
  Checked_Number(const unsigned long long y, Rounding_Dir dir);

#if PPL_SUPPORTED_FLOAT
  //! Direct initialization from a float and rounding mode.
  Checked_Number(const float y, Rounding_Dir dir);
#endif

#if PPL_SUPPORTED_DOUBLE
  //! Direct initialization from a double and rounding mode.
  Checked_Number(const double y, Rounding_Dir dir);
#endif

#if PPL_SUPPORTED_LONG_DOUBLE
  //! Direct initialization from a long double and rounding mode.
  Checked_Number(const long double y, Rounding_Dir dir);
#endif

  //! Direct initialization from a rational and rounding mode.
  Checked_Number(const mpq_class& y, Rounding_Dir dir);

  //! Direct initialization from an unbounded integer and rounding mode.
  Checked_Number(const mpz_class& y, Rounding_Dir dir);

  //! Direct initialization from a C string and rounding mode.
  Checked_Number(const char* y, Rounding_Dir dir);

  //! Direct initialization from minus infinity and rounding mode.
  Checked_Number(const Minus_Infinity& y, Rounding_Dir dir);

  //! Direct initialization from plus infinity and rounding mode.
  Checked_Number(const Plus_Infinity& y, Rounding_Dir dir);

  //! Direct initialization from NAN and rounding mode.
  Checked_Number(const Not_A_Number& y, Rounding_Dir dir);

  //! Direct initialization from a Checked_Number, default rounding mode.
  template <typename From, typename From_Policy>
  explicit Checked_Number(const Checked_Number<From, From_Policy>& y);

  //! Direct initialization from a signed char, default rounding mode.
  Checked_Number(const signed char y);

  //! Direct initialization from a signed short, default rounding mode.
  Checked_Number(const signed short y);

  //! Direct initialization from a signed int, default rounding mode.
  Checked_Number(const signed int y);

  //! Direct initialization from a signed long, default rounding mode.
  Checked_Number(const signed long y);

  //! Direct initialization from a signed long long, default rounding mode.
  Checked_Number(const signed long long y);

  //! Direct initialization from an unsigned char, default rounding mode.
  Checked_Number(const unsigned char y);

  //! Direct initialization from an unsigned short, default rounding mode.
  Checked_Number(const unsigned short y);

  //! Direct initialization from an unsigned int, default rounding mode.
  Checked_Number(const unsigned int y);

  //! Direct initialization from an unsigned long, default rounding mode.
  Checked_Number(const unsigned long y);

  //! Direct initialization from an unsigned long long, default rounding mode.
  Checked_Number(const unsigned long long y);

  //! Direct initialization from a float, default rounding mode.
  Checked_Number(const float y);

  //! Direct initialization from a double, default rounding mode.
  Checked_Number(const double y);

  //! Direct initialization from a long double, default rounding mode.
  Checked_Number(const long double y);

  //! Direct initialization from a rational, default rounding mode.
  Checked_Number(const mpq_class& y);

  //! Direct initialization from an unbounded integer, default rounding mode.
  Checked_Number(const mpz_class& y);

  //! Direct initialization from a C string, default rounding mode.
  Checked_Number(const char* y);

  //! Direct initialization from minus infinity, default rounding mode.
  Checked_Number(const Minus_Infinity& y);

  //! Direct initialization from plus infinity, default rounding mode.
  Checked_Number(const Plus_Infinity& y);

  //! Direct initialization from NAN, default rounding mode.
  Checked_Number(const Not_A_Number& y);

  //@} // Constructors

  //! \name Accessors and Conversions
  //@{

  //! Conversion operator: returns a copy of the underlying numeric value.
  operator T() const;

  //! Returns a reference to the underlying numeric value.
  T& raw_value();

  //! Returns a const reference to the underlying numeric value.
  const T& raw_value() const;

  //@} // Accessors and Conversions

  //! Checks if all the invariants are satisfied.
  bool OK() const;

  //! Classifies *this.
  /*!
    Returns the appropriate Result characterizing:
    - whether \p *this is NAN,
      if \p nan is <CODE>true</CODE>;
    - whether \p *this is a (positive or negative) infinity,
      if \p inf is <CODE>true</CODE>;
    - the sign of \p *this,
      if \p sign is <CODE>true</CODE>.
  */
  Result classify(bool nan = true, bool inf = true, bool sign = true) const;

  //! \name Assignment Operators
  //@{

  //! Assignment operator.
  Checked_Number& operator=(const Checked_Number& y);

  //! Assignment operator.
  template <typename From, typename From_Policy>
  Checked_Number& operator=(const Checked_Number<From, From_Policy>& y);

  //! Assignment operator.
  template <typename From>
  Checked_Number& operator=(const From& y);

  //! Assignment operator.
  Checked_Number& operator=(const Not_A_Number& y);

  //! Assignment operator.
  Checked_Number& operator=(const Minus_Infinity& y);

  //! Assignment operator.
  Checked_Number& operator=(const Plus_Infinity& y);

  //! Add and assign operator.
  template <typename From_Policy>
  Checked_Number& operator+=(const Checked_Number<T, From_Policy>& y);

  //! Add and assign operator.
  Checked_Number& operator+=(const T& y);

  //! Add and assign operator.
  template <typename From, typename From_Policy>
  Checked_Number& operator+=(const Checked_Number<From, From_Policy>& y);

  template <typename From>
  Checked_Number& operator+=(const From& y);

  //! Subtract and assign operator.
  template <typename From_Policy>
  Checked_Number& operator-=(const Checked_Number<T, From_Policy>& y);

  //! Subtract and assign operator.
  Checked_Number& operator-=(const T& y);

  //! Subtract and assign operator.
  template <typename From, typename From_Policy>
  Checked_Number& operator-=(const Checked_Number<From, From_Policy>& y);

  //! Subtract and assign operator.
  template <typename From>
  Checked_Number& operator-=(const From& y);

  //! Multiply and assign operator.
  template <typename From_Policy>
  Checked_Number& operator*=(const Checked_Number<T, From_Policy>& y);

  //! Multiply and assign operator.
  Checked_Number& operator*=(const T& y);
  template <typename From, typename From_Policy>

  //! Multiply and assign operator.
  Checked_Number& operator*=(const Checked_Number<From, From_Policy>& y);

  //! Multiply and assign operator.
  template <typename From>
  Checked_Number& operator*=(const From& y);

  //! Divide and assign operator.
  template <typename From_Policy>
  Checked_Number& operator/=(const Checked_Number<T, From_Policy>& y);

  //! Divide and assign operator.
  Checked_Number& operator/=(const T& y);

  //! Divide and assign operator.
  template <typename From, typename From_Policy>
  Checked_Number& operator/=(const Checked_Number<From, From_Policy>& y);

  //! Divide and assign operator.
  template <typename From>
  Checked_Number& operator/=(const From& y);

  //! Compute remainder and assign operator.
  template <typename From_Policy>
  Checked_Number& operator%=(const Checked_Number<T, From_Policy>& y);

  //! Compute remainder and assign operator.
  Checked_Number& operator%=(const T& y);

  //! Compute remainder and assign operator.
  template <typename From, typename From_Policy>
  Checked_Number& operator%=(const Checked_Number<From, From_Policy>& y);

  //! Compute remainder and assign operator.
  template <typename From>
  Checked_Number& operator%=(const From& y);

  //@} // Assignment Operators


  //! \name Increment and Decrement Operators
  //@{

  //! Pre-increment operator.
  Checked_Number& operator++();

  //! Post-increment operator.
  Checked_Number  operator++(int);

  //! Pre-decrement operator.
  Checked_Number& operator--();

  //! Post-decrement operator.
  Checked_Number  operator--(int);

  //@} // Increment and Decrement Operators

private:
  //! The underlying numeric value.
  T v;
};

template <typename T, typename Policy>
bool is_not_a_number(const Checked_Number<T, Policy>& x);
template <typename T, typename Policy>
bool is_minus_infinity(const Checked_Number<T, Policy>& x);
template <typename T, typename Policy>
bool is_plus_infinity(const Checked_Number<T, Policy>& x);

template <typename To>
Result assign_r(To& to, const Minus_Infinity& x, Rounding_Dir dir);
template <typename To>
Result assign_r(To& to, const Plus_Infinity& x, Rounding_Dir dir);
template <typename To>
Result assign_r(To& to, const Not_A_Number& x, Rounding_Dir dir);
template <typename To>
Result assign_r(To& to, const char* x, Rounding_Dir dir);
template <typename To, typename To_Policy>
Result assign_r(To& to, char* x, Rounding_Dir dir);

#define FUNC1(name) \
template <typename To, typename From> \
Result name(To& to, const From& x, Rounding_Dir dir);

FUNC1(assign_r)
FUNC1(neg_assign_r)
FUNC1(abs_assign_r)
FUNC1(sqrt_assign_r)

#undef FUNC1

#define FUNC1(name) \
template <typename To, typename From> \
Result name(To& to, const From& x, int exp, Rounding_Dir dir);

FUNC1(mul2exp_assign_r)
FUNC1(div2exp_assign_r)

#undef FUNC1

#define FUNC2(name) \
template <typename To, typename From1, typename From2> \
Result name(To& to, const From1& x, const From2& y, Rounding_Dir dir);

FUNC2(add_assign_r)
FUNC2(sub_assign_r)
FUNC2(mul_assign_r)
FUNC2(div_assign_r)
FUNC2(rem_assign_r)
FUNC2(gcd_assign_r)
FUNC2(lcm_assign_r)
FUNC2(add_mul_assign_r)
FUNC2(sub_mul_assign_r)

#undef FUNC2

#define FUNC4(name) \
template <typename To1, typename From1, typename From2,		\
	  typename To2, typename To3>				\
Result name(To1& to, const From1& x, const From2& y,		\
	    To2& s, To3& t, Rounding_Dir dir);

FUNC4(gcdext_assign_r)

#undef FUNC4

//! Swaps \p *this with \p y.
/*! \relates Checked_Number */
template <typename T, typename Policy>
void swap(Checked_Number<T, Policy>& x, Checked_Number<T, Policy>& y);

//! \name Accessor Functions
//@{

//! Returns a const reference to the underlying native integer value.
/*! \relates Checked_Number */
template <typename T, typename Policy>
const T&
raw_value(const Checked_Number<T, Policy>& x);

//! Returns a reference to the underlying native integer value.
/*! \relates Checked_Number */
template <typename T, typename Policy>
T&
raw_value(Checked_Number<T, Policy>& x);

//@} // Accessor Functions

//! \name Memory Size Inspection Functions
//@{

//! Returns the total size in bytes of the memory occupied by \p x.
/*! \relates Checked_Number */
template <typename T, typename Policy>
size_t
total_memory_in_bytes(const Checked_Number<T, Policy>& x);

//! Returns the size in bytes of the memory managed by \p x.
/*! \relates Checked_Number */
template <typename T, typename Policy>
size_t
external_memory_in_bytes(const Checked_Number<T, Policy>& x);

//@} // Memory Size Inspection Functions

//! \name Arithmetic Operators
//@{

//! Unary plus operator.
/*! \relates Checked_Number */
template <typename T, typename Policy>
Checked_Number<T, Policy>
operator+(const Checked_Number<T, Policy>& x);

//! Unary minus operator.
/*! \relates Checked_Number */
template <typename T, typename Policy>
Checked_Number<T, Policy>
operator-(const Checked_Number<T, Policy>& x);

//! Assigns to \p x its negation.
/*! \relates Checked_Number */
template <typename T, typename Policy>
void
neg_assign(Checked_Number<T, Policy>& x);

//! Assigns to \p x the value <CODE>x + y * z</CODE>.
/*! \relates Checked_Number */
template <typename T, typename Policy>
void
add_mul_assign(Checked_Number<T, Policy>& x,
	       const Checked_Number<T, Policy>& y,
	       const Checked_Number<T, Policy>& z);

//! Assigns to \p x the value <CODE>x - y * z</CODE>.
/*! \relates Checked_Number */
template <typename T, typename Policy>
void
sub_mul_assign(Checked_Number<T, Policy>& x,
	       const Checked_Number<T, Policy>& y,
	       const Checked_Number<T, Policy>& z);

//! Assigns to \p x the greatest common divisor of \p y and \p z.
/*! \relates Checked_Number */
template <typename T, typename Policy>
void
gcd_assign(Checked_Number<T, Policy>& x,
	   const Checked_Number<T, Policy>& y,
	   const Checked_Number<T, Policy>& z);

/*! \brief
  Assigns to \p x the greatest common divisor of \p y and \p z,
  setting \p s and \p t such that s*y + t*z = x = gcd(y, z).
*/
/*! \relates Checked_Number */
template <typename T, typename Policy>
void
gcdext_assign(Checked_Number<T, Policy>& x,
	      const Checked_Number<T, Policy>& y,
	      const Checked_Number<T, Policy>& z,
	      Checked_Number<T, Policy>& s,
	      Checked_Number<T, Policy>& t);

//! Assigns to \p x the least common multiple of \p y and \p z.
/*! \relates Checked_Number */
template <typename T, typename Policy>
void
lcm_assign(Checked_Number<T, Policy>& x,
	   const Checked_Number<T, Policy>& y,
	   const Checked_Number<T, Policy>& z);

/*! \brief
  If \p z divides \p y, assigns to \p x the quotient of the integer
  division of \p y and \p z.

  \relates Checked_Number
  The behavior is undefined if \p z does not divide \p y.
*/
template <typename T, typename Policy>
void
exact_div_assign(Checked_Number<T, Policy>& x,
		 const Checked_Number<T, Policy>& y,
		 const Checked_Number<T, Policy>& z);

//! Assigns to \p x the integer square root of \p y.
/*! \relates Checked_Number */
template <typename T, typename Policy>
void sqrt_assign(Checked_Number<T, Policy>& x,
		 const Checked_Number<T, Policy>& y);

//@} // Arithmetic Operators


//! \name Relational Operators and Comparison Functions
//@{

//! Equality operator.
/*! \relates Checked_Number */
template <typename T1, typename Policy1,
	  typename T2, typename Policy2>
bool
operator==(const Checked_Number<T1, Policy1>& x,
	   const Checked_Number<T2, Policy2>& y);

//! Disequality operator.
/*! \relates Checked_Number */
template <typename T1, typename Policy1,
	  typename T2, typename Policy2>
bool
operator!=(const Checked_Number<T1, Policy1>& x,
	   const Checked_Number<T2, Policy2>& y);

//! Greater than or equal to operator.
/*! \relates Checked_Number */
template <typename T1, typename Policy1,
	  typename T2, typename Policy2>
bool
operator>=(const Checked_Number<T1, Policy1>& x,
	   const Checked_Number<T2, Policy2>& y);

//! Greater than operator.
/*! \relates Checked_Number */
template <typename T1, typename Policy1,
	  typename T2, typename Policy2>
bool
operator>(const Checked_Number<T1, Policy1>& x,
	  const Checked_Number<T2, Policy2>& y);

//! Less than or equal to operator.
/*! \relates Checked_Number */
template <typename T1, typename Policy1,
	  typename T2, typename Policy2>
bool
operator<=(const Checked_Number<T1, Policy1>& x,
	   const Checked_Number<T2, Policy2>& y);

//! Less than operator.
/*! \relates Checked_Number */
template <typename T1, typename Policy1,
	  typename T2, typename Policy2>
bool
operator<(const Checked_Number<T1, Policy1>& x,
	  const Checked_Number<T2, Policy2>& y);

/*! \brief
  Returns \f$-1\f$, \f$0\f$ or \f$1\f$ depending on whether the value
  of \p x is negative, zero or positive, respectively.

  \relates Checked_Number
*/
template <typename T, typename Policy>
int
sgn(const Checked_Number<T, Policy>& x);

/*! \brief
  Returns a negative, zero or positive value depending on whether
  \p x is lower than, equal to or greater than \p y, respectively.

  \relates Checked_Number
*/
template <typename T1, typename Policy1,
	  typename T2, typename Policy2>
int
cmp(const Checked_Number<T1, Policy1>& x,
    const Checked_Number<T2, Policy2>& y);

//@} // Relational Operators and Comparison Functions

//! \name Input-Output Operators
//@{

/*! \relates Checked_Number */
template <typename T, typename Policy>
Result
output(std::ostream& os,
       const Checked_Number<T, Policy>& x,
       const Numeric_Format& fmt,
       Rounding_Dir dir);

//! Output operator.
/*! \relates Checked_Number */
template <typename T, typename Policy>
std::ostream&
operator<<(std::ostream& os, const Checked_Number<T, Policy>& x);

//! Input function.
/*!
  \relates Checked_Number

  \param is
  Input stream to read from;

  \param x
  Number (possibly extended) to assign to in case of successful reading;

  \param dir
  Rounding mode to be applied.

  \return
  Result of the input operation.  Success, success with imprecision,
  overflow, parsing error: all possibilities are taken into account,
  checked for, and properly reported.

  This function attempts reading a (possibly extended) number from the given
  stream \p is, possibly rounding as specified by \p dir, assigning the result
  to \p x upon success, and returning the appropriate Result.

  The input syntax allows the specification of:
  - plain base-10 integer numbers as <CODE>34976098</CODE>,
    <CODE>-77</CODE> and <CODE>+13</CODE>;
  - base-10 integer numbers in scientific notation as <CODE>15e2</CODE>
    and <CODE>15*^2</CODE> (both meaning \f$15 \cdot 10^2 = 1500\f$),
    <CODE>9200e-2</CODE> and <CODE>-18*^+11111111111111111</CODE>;
  - base-10 rational numbers in fraction notation as
    <CODE>15/3</CODE> and <CODE>15/-3</CODE>;
  - base-10 rational numbers in fraction/scientific notation as
    <CODE>15/30e-1</CODE> (meaning \f$5\f$) and <CODE>15*^-3/29e2</CODE>
    (meaning \f$3/580000\f$);
  - base-10 rational numbers in floating point notation as
    <CODE>71.3</CODE> (meaning \f$713/10\f$) and
    <CODE>-0.123456</CODE> (meaning \f$-1929/15625\f$);
  - base-10 rational numbers in floating point scientific notation as
    <CODE>2.2e-1</CODE> (meaning \f$11/50\f$) and <CODE>-2.20001*^+3</CODE>
    (meaning \f$-220001/100\f$);
  - integers and rationals (in fractional, floating point and scientific
    notations) specified by using Mathematica-style bases, in the range
    from 2 to 36, as
    <CODE>2^^11</CODE> (meaning \f$3\f$),
    <CODE>36^^z</CODE> (meaning \f$35\f$),
    <CODE>36^^xyz</CODE> (meaning \f$44027\f$),
    <CODE>2^^11.1</CODE> (meaning \f$7/2\f$),
    <CODE>10^^2e3</CODE> (meaning \f$2000\f$),
    <CODE>8^^2e3</CODE> (meaning \f$1024\f$),
    <CODE>8^^2.1e3</CODE> (meaning \f$1088\f$),
    <CODE>8^^20402543.120347e7</CODE> (meaning \f$9073863231288\f$),
    <CODE>8^^2.1</CODE> (meaning \f$17/8\f$);
    note that the base and the exponent are always written as plain
    base-10 integer numbers; also, when an ambiguity may arise, the
    character <CODE>e</CODE> is interpreted as a digit, so that
    <CODE>16^^1e2</CODE> (meaning \f$482\f$) is different from
    <CODE>16^^1*^2</CODE> (meaning \f$256\f$);
  - the C-style hexadecimal prefix <CODE>0x</CODE> is interpreted as
    the Mathematica-style prefix <CODE>16^^</CODE>;
  - special values like <CODE>inf</CODE> and <CODE>+inf</CODE>
    (meaning \f$+\infty\f$), <CODE>-inf</CODE> (meaning \f$-\infty\f$),
    and <CODE>nan</CODE> (meaning "not a number").

  The rationale behind the accepted syntax can be summarized as follows:
  - if the syntax is accepted by Mathematica, then this function
    accepts it with the same semantics;
  - if the syntax is acceptable as standard C++ integer or floating point
    literal (except for octal notation and type suffixes, which are not
    supported), then this function accepts it with the same semantics;
  - natural extensions of the above are accepted with the natural
    extensions of the semantics;
  - special values are accepted.

  Valid syntax is more formally and completely specified by the
  following grammar, with the additional provisos that everything is
  <EM>case insensitive</EM>, that the syntactic category
  <CODE>BDIGIT</CODE> is further restricted by the current base
  and that for all bases above 14, any <CODE>e</CODE> is always
  interpreted as a digit and never as a delimiter for the exponent part
  (if such a delimiter is desired, it has to be written as <CODE>*^</CODE>).

\code
number	: NAN					INF	: 'inf'
	| SIGN INF					;
	| INF
	| num					NAN	: 'nan'
	| num DIV num					;
	;
						SIGN	: '-'
num     : unum						| '+'
        | SIGN unum					;

unum	: unum1					EXP	: 'e'
	| HEX unum1					| '*^'
	| base BASE unum1				;
	;
						POINT	: '.'
unum1	: mantissa					;
	| mantissa EXP exponent
	;					DIV	: '/'
							;
mantissa: bdigits
        | POINT bdigits				MINUS	: '-'
	| bdigits POINT					;
	| bdigits POINT bdigits
	;					PLUS	: '+'
						;
exponent: SIGN digits
	| digits				HEX	: '0x'
	;					;

bdigits : BDIGIT				BASE	: '^^'
	| bdigits BDIGIT				;
	;
						DIGIT   : '0' .. '9'
digits  : DIGIT						;
	| digits DIGIT
	;					BDIGIT  : '0' .. '9'
							| 'a' .. 'z'
							;
\endcode
*/
template <typename T, typename Policy>
Result
input(std::istream& is, Checked_Number<T, Policy>& x, Rounding_Dir dir);

//! Input operator.
/*! \relates Checked_Number */
template <typename T, typename Policy>
std::istream&
operator>>(std::istream& is, Checked_Number<T, Policy>& x);

//@} // Input-Output Operators

void throw_result_exception(Result r);

template <typename T>
T
plus_infinity();

template <typename T>
T
minus_infinity();

template <typename T>
T
not_a_number();

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Checked_Number.inlines.hh line 1
/* Checked_Number class implementation: inline functions.
*/


#include <stdexcept>
#include <sstream>

namespace Parma_Polyhedra_Library {

inline Rounding_Dir
rounding_dir(Rounding_Dir dir) {
  if (dir == ROUND_NOT_NEEDED) {
#ifdef DEBUG_ROUND_NOT_NEEDED
    return ROUND_DIRECT;
#else
    return ROUND_IGNORE;
#endif
  }
  return dir;
}

inline Result
check_result(Result r, Rounding_Dir dir) {
  if (dir == ROUND_NOT_NEEDED && !is_special(r)) {
#ifdef DEBUG_ROUND_NOT_NEEDED
    // FIXME: this is wrong. If an overflow happens the Result may be
    // V_LT or V_GT. What's the better way to cope with that?
    assert(r == V_EQ);
#else
    return V_EQ;
#endif
  }
  return r;
}


inline void
Checked_Number_Transparent_Policy::handle_result(Result) {
}

inline void
Checked_Number_Default_Policy::handle_result(Result r) {
  if (is_special(r))
    throw_result_exception(r);
}

inline void
Extended_Number_Policy::handle_result(Result r) {
  if (is_special(r))
    throw_result_exception(r);
}

template <typename T, typename Policy>
inline
Checked_Number<T, Policy>::Checked_Number()
 : v(0) {
}

template <typename T, typename Policy>
inline
Checked_Number<T, Policy>::Checked_Number(const Checked_Number& y) {
  // TODO: avoid default construction of value member
  Checked::copy<Policy>(v, y.raw_value());
}

template <typename T, typename Policy>
template <typename From, typename From_Policy>
inline
Checked_Number<T, Policy>
::Checked_Number(const Checked_Number<From, From_Policy>& y, Rounding_Dir dir) {
  // TODO: avoid default construction of value member
  Policy::handle_result(check_result(Checked::assign_ext<Policy, From_Policy>
				     (v,
				      y.raw_value(),
				      rounding_dir(dir)),
				     dir));
}

template <typename T, typename Policy>
template <typename From, typename From_Policy>
inline
Checked_Number<T, Policy>
::Checked_Number(const Checked_Number<From, From_Policy>& y) {
  // TODO: avoid default construction of value member
  Rounding_Dir dir = Policy::ROUND_DEFAULT_CONSTRUCTOR;
  Policy::handle_result(check_result(Checked::assign_ext<Policy, From_Policy>
				     (v,
				      y.raw_value(),
				      rounding_dir(dir)),
				     dir));
}

// TODO: avoid default construction of value member
#define DEF_CTOR(type) \
template <typename T, typename Policy> \
inline \
Checked_Number<T, Policy>::Checked_Number(const type x, Rounding_Dir dir) { \
  Policy::handle_result(check_result(Checked::assign_ext<Policy, Default_From_Policy>(v, x, rounding_dir(dir)), dir)); \
} \
template <typename T, typename Policy> \
inline \
Checked_Number<T, Policy>::Checked_Number(const type x) { \
  Rounding_Dir dir = Policy::ROUND_DEFAULT_CONSTRUCTOR; \
  Policy::handle_result(check_result(Checked::assign_ext<Policy, Default_From_Policy>(v, x, rounding_dir(dir)), dir)); \
}

#define COND_0(...)
#define COND_1(...) __VA_ARGS__
#define COND_(if, ...) COND_##if(__VA_ARGS__)
#define COND(if, ...) COND_(if, __VA_ARGS__)

DEF_CTOR(signed char)
DEF_CTOR(signed short)
DEF_CTOR(signed int)
DEF_CTOR(signed long)
DEF_CTOR(signed long long)
DEF_CTOR(unsigned char)
DEF_CTOR(unsigned short)
DEF_CTOR(unsigned int)
DEF_CTOR(unsigned long)
DEF_CTOR(unsigned long long)
COND(PPL_SUPPORTED_FLOAT, DEF_CTOR(float))
COND(PPL_SUPPORTED_DOUBLE, DEF_CTOR(double))
COND(PPL_SUPPORTED_LONG_DOUBLE, DEF_CTOR(long double))
DEF_CTOR(mpq_class&)
DEF_CTOR(mpz_class&)

#undef DEF_CTOR

template <typename T, typename Policy>
inline
Checked_Number<T, Policy>::Checked_Number(const char* x, Rounding_Dir dir) {
  std::istringstream s(x);
  Policy::handle_result(check_result(Checked::input<Policy>(v,
							    s,
							    rounding_dir(dir)),
				     dir));
}

template <typename T, typename Policy>
inline
Checked_Number<T, Policy>::Checked_Number(const char* x) {
  std::istringstream s(x);
  Rounding_Dir dir = Policy::ROUND_DEFAULT_CONSTRUCTOR;
  Policy::handle_result(check_result(Checked::input<Policy>(v,
							    s,
							    rounding_dir(dir)),
				     dir));
}

template <typename T, typename Policy>
inline
Checked_Number<T, Policy>::Checked_Number(const Not_A_Number& x,
					  Rounding_Dir dir) {
  // TODO: avoid default construction of value member
  Policy::handle_result(check_result(Checked::assign<Policy>(v,
							     x,
							     rounding_dir(dir)),
				     dir));
}

template <typename T, typename Policy>
inline
Checked_Number<T, Policy>::Checked_Number(const Not_A_Number& x) {
  // TODO: avoid default construction of value member
  Rounding_Dir dir = ROUND_IGNORE;
  Policy::handle_result(check_result(Checked::assign<Policy>(v,
							     x,
							     rounding_dir(dir)),
				     dir));
}

template <typename T, typename Policy>
inline
Checked_Number<T, Policy>::Checked_Number(const Minus_Infinity& x,
					  Rounding_Dir dir) {
  // TODO: avoid default construction of value member
  Policy::handle_result(check_result(Checked::assign<Policy>(v,
							     x,
							     rounding_dir(dir)),
				     dir));
}

template <typename T, typename Policy>
inline
Checked_Number<T, Policy>::Checked_Number(const Minus_Infinity& x) {
  // TODO: avoid default construction of value member
  Rounding_Dir dir = Policy::ROUND_DEFAULT_CONSTRUCTOR_INF;
  Policy::handle_result(check_result(Checked::assign<Policy>(v,
							     x,
							     rounding_dir(dir)),
				     dir));
}

template <typename T, typename Policy>
inline
Checked_Number<T, Policy>::Checked_Number(const Plus_Infinity& x,
					  Rounding_Dir dir) {
  // TODO: avoid default construction of value member
  Policy::handle_result(check_result(Checked::assign<Policy>(v,
							     x,
							     rounding_dir(dir)),
				     dir));
}

template <typename T, typename Policy>
inline
Checked_Number<T, Policy>::Checked_Number(const Plus_Infinity& x) {
  // TODO: avoid default construction of value member
  Rounding_Dir dir = Policy::ROUND_DEFAULT_CONSTRUCTOR_INF;
  Policy::handle_result(check_result(Checked::assign<Policy>(v,
							     x,
							     rounding_dir(dir)),
				     dir));
}

template <typename T>
inline bool
is_minus_infinity(const T& x) {
  return Checked::is_minf<typename Native_Checked_From_Wrapper<T>::Policy>(Native_Checked_From_Wrapper<T>::raw_value(x));
}

template <typename T>
inline bool
is_plus_infinity(const T& x) {
  return Checked::is_pinf<typename Native_Checked_From_Wrapper<T>::Policy>(Native_Checked_From_Wrapper<T>::raw_value(x));
}

template <typename T>
inline bool
is_not_a_number(const T& x) {
  return Checked::is_nan<typename Native_Checked_From_Wrapper<T>::Policy>(Native_Checked_From_Wrapper<T>::raw_value(x));
}

template <typename T>
inline bool
is_integer(const T& x) {
  return Checked::is_int<typename Native_Checked_From_Wrapper<T>::Policy>(Native_Checked_From_Wrapper<T>::raw_value(x));
}

template <typename T, typename Policy>
inline
Checked_Number<T, Policy>::operator T() const {
  if (Policy::convertible)
    return v;
}

template <typename T, typename Policy>
inline T&
Checked_Number<T, Policy>::raw_value() {
  return v;
}

template <typename T, typename Policy>
inline const T&
Checked_Number<T, Policy>::raw_value() const {
  return v;
}

/*! \relates Checked_Number */
template <typename T, typename Policy>
inline const T&
raw_value(const Checked_Number<T, Policy>& x) {
  return x.raw_value();
}

/*! \relates Checked_Number */
template <typename T, typename Policy>
inline T&
raw_value(Checked_Number<T, Policy>& x) {
  return x.raw_value();
}

template <typename T, typename Policy>
inline bool
Checked_Number<T, Policy>::OK() const {
  return true;
}

template <typename T, typename Policy>
inline Result
Checked_Number<T, Policy>::classify(bool nan, bool inf, bool sign) const {
  return Checked::classify<Policy>(v, nan, inf, sign);
}

template <typename T, typename Policy>
inline bool
is_not_a_number(const Checked_Number<T, Policy>& x) {
  return Checked::is_nan<Policy>(x.raw_value());
}

template <typename T, typename Policy>
inline bool
is_minus_infinity(const Checked_Number<T, Policy>& x) {
  return Checked::is_minf<Policy>(x.raw_value());
}

template <typename T, typename Policy>
inline bool
is_plus_infinity(const Checked_Number<T, Policy>& x) {
  return Checked::is_pinf<Policy>(x.raw_value());
}

/*! \relates Checked_Number */
template <typename T, typename Policy>
inline memory_size_type
total_memory_in_bytes(const Checked_Number<T, Policy>& x) {
  return Checked::total_memory_in_bytes(x.raw_value());
}

/*! \relates Checked_Number */
template <typename T, typename Policy>
inline memory_size_type
external_memory_in_bytes(const Checked_Number<T, Policy>& x) {
  return Checked::external_memory_in_bytes(x.raw_value());
}

template <typename To>
inline Result
assign_r(To& to, const Minus_Infinity& x, Rounding_Dir dir) {
  return check_result(Checked::assign<typename Native_Checked_To_Wrapper<To>::Policy>(Native_Checked_To_Wrapper<To>::raw_value(to), x, rounding_dir(dir)), dir);
}
template <typename To>
inline Result
assign_r(To& to, const Plus_Infinity& x, Rounding_Dir dir) {
  return check_result(Checked::assign<typename Native_Checked_To_Wrapper<To>::Policy>(Native_Checked_To_Wrapper<To>::raw_value(to), x, rounding_dir(dir)), dir);
}
template <typename To>
inline Result
assign_r(To& to, const Not_A_Number& x, Rounding_Dir dir) {
  return check_result(Checked::assign<typename Native_Checked_To_Wrapper<To>::Policy>(Native_Checked_To_Wrapper<To>::raw_value(to), x, rounding_dir(dir)), dir);
}

template <typename To>
inline Result
assign_r(To& to, const char* x, Rounding_Dir dir) {
  std::istringstream s(x);
  return check_result(Checked::input<typename Native_Checked_To_Wrapper<To>::Policy>(Native_Checked_To_Wrapper<To>::raw_value(to), s, rounding_dir(dir)), dir);
}

#define FUNC1(name, func) \
template <typename To, typename From> \
inline Result \
name(To& to, const From& x, Rounding_Dir dir) { \
  return check_result(Checked::func<typename Native_Checked_To_Wrapper<To>::Policy, typename Native_Checked_From_Wrapper<From>::Policy>(Native_Checked_To_Wrapper<To>::raw_value(to), Native_Checked_From_Wrapper<From>::raw_value(x), rounding_dir(dir)), dir); \
}

FUNC1(construct, construct_ext)
FUNC1(assign_r, assign_ext)
FUNC1(neg_assign_r, neg_ext)
FUNC1(abs_assign_r, abs_ext)
FUNC1(sqrt_assign_r, sqrt_ext)

#undef FUNC1

#define FUNC1(name, func) \
template <typename To, typename From> \
inline Result \
name(To& to, const From& x, int exp, Rounding_Dir dir) { \
  return check_result(Checked::func<typename Native_Checked_To_Wrapper<To>::Policy, typename Native_Checked_From_Wrapper<From>::Policy>(Native_Checked_To_Wrapper<To>::raw_value(to), Native_Checked_From_Wrapper<From>::raw_value(x), exp, rounding_dir(dir)), dir); \
}

FUNC1(mul2exp_assign_r, mul2exp_ext)
FUNC1(div2exp_assign_r, div2exp_ext)

#undef FUNC1

#define FUNC2(name, func) \
template <typename To, \
          typename From1, \
	  typename From2> \
inline Result \
name(To& to, const From1& x, const From2& y, Rounding_Dir dir) { \
  return check_result(Checked::func<typename Native_Checked_To_Wrapper<To>::Policy, typename Native_Checked_From_Wrapper<From1>::Policy, typename Native_Checked_From_Wrapper<From2>::Policy>(Native_Checked_To_Wrapper<To>::raw_value(to), Native_Checked_From_Wrapper<From1>::raw_value(x), Native_Checked_From_Wrapper<From2>::raw_value(y), rounding_dir(dir)), dir); \
}

FUNC2(add_assign_r, add_ext)
FUNC2(sub_assign_r, sub_ext)
FUNC2(mul_assign_r, mul_ext)
FUNC2(div_assign_r, div_ext)
FUNC2(rem_assign_r, rem_ext)
FUNC2(gcd_assign_r, gcd_ext)
FUNC2(lcm_assign_r, lcm_ext)
FUNC2(add_mul_assign_r, add_mul_ext)
FUNC2(sub_mul_assign_r, sub_mul_ext)

#undef FUNC2

#define FUNC4(name, func)						\
template <typename To1,							\
          typename From1,						\
          typename From2,						\
          typename To2,							\
	  typename To3>							\
inline Result								\
name(To1& to, const From1& x, const From2& y, To2& s, To3& t,		\
     Rounding_Dir dir) {						\
  return								\
    check_result							\
    (Checked::func<typename Native_Checked_To_Wrapper<To1>::Policy,	\
                   typename Native_Checked_From_Wrapper<From1>::Policy,	\
                   typename Native_Checked_From_Wrapper<From2>::Policy,	\
                   typename Native_Checked_To_Wrapper<To2>::Policy,	\
                   typename Native_Checked_To_Wrapper<To3>::Policy>	\
     (Native_Checked_To_Wrapper<To1>::raw_value(to),			\
      Native_Checked_From_Wrapper<From1>::raw_value(x),			\
      Native_Checked_From_Wrapper<From2>::raw_value(y),			\
      Native_Checked_To_Wrapper<To2>::raw_value(s),			\
      Native_Checked_To_Wrapper<To3>::raw_value(t),			\
      rounding_dir(dir)),						\
     dir);								\
}

FUNC4(gcdext_assign_r, gcdext_ext)

#undef FUNC4

#define DEF_INCREMENT(f, fun) \
template <typename T, typename Policy> \
inline Checked_Number<T, Policy>& \
Checked_Number<T, Policy>::f() { \
  Policy::handle_result(fun(*this, *this, T(1), \
			    Policy::ROUND_DEFAULT_OPERATOR)); \
  return *this; \
} \
template <typename T, typename Policy> \
inline Checked_Number<T, Policy> \
Checked_Number<T, Policy>::f(int) {\
  T r = v;\
  Policy::handle_result(fun(*this, *this, T(1), \
			    Policy::ROUND_DEFAULT_OPERATOR)); \
  return r;\
}

DEF_INCREMENT(operator ++, add_assign_r)
DEF_INCREMENT(operator --, sub_assign_r)

#undef DEF_INCREMENT

/*! \relates Checked_Number */
template <typename T, typename Policy>
inline void
swap(Checked_Number<T, Policy>& x, Checked_Number<T, Policy>& y) {
  std::swap(x.raw_value(), y.raw_value());
}

template <typename T, typename Policy>
inline Checked_Number<T, Policy>&
Checked_Number<T, Policy>::operator=(const Checked_Number<T, Policy>& y) {
  Checked::copy<Policy>(v, y.raw_value());
  return *this;
}
template <typename T, typename Policy>
template <typename From, typename From_Policy>
inline Checked_Number<T, Policy>&
Checked_Number<T, Policy>
::operator=(const Checked_Number<From, From_Policy>& y) {
  Policy::handle_result(assign_r(*this, y, Policy::ROUND_DEFAULT_OPERATOR));
  return *this;
}
template <typename T, typename Policy>
template <typename From>
inline Checked_Number<T, Policy>&
Checked_Number<T, Policy>::operator=(const From& y) {
  Policy::handle_result(assign_r(*this, y, Policy::ROUND_DEFAULT_OPERATOR));
  return *this;
}
template <typename T, typename Policy>
inline Checked_Number<T, Policy>&
Checked_Number<T, Policy>::operator=(const Not_A_Number& y) {
  Policy::handle_result(assign_r(*this, y, ROUND_IGNORE));
  return *this;
}
template <typename T, typename Policy>
inline Checked_Number<T, Policy>&
Checked_Number<T, Policy>::operator=(const Minus_Infinity& y) {
  Policy::handle_result(assign_r(*this, y, Policy::ROUND_DEFAULT_ASSIGN_INF));
  return *this;
}
template <typename T, typename Policy>
inline Checked_Number<T, Policy>&
Checked_Number<T, Policy>::operator=(const Plus_Infinity& y) {
  Policy::handle_result(assign_r(*this, y, Policy::ROUND_DEFAULT_ASSIGN_INF));
  return *this;
}

#define DEF_BINARY_OP_ASSIGN(f, fun) \
template <typename T, typename Policy> \
template <typename From_Policy> \
inline Checked_Number<T, Policy>& \
Checked_Number<T, Policy>::f(const Checked_Number<T, From_Policy>& y) { \
  Policy::handle_result(fun(*this, *this, y, \
			    Policy::ROUND_DEFAULT_OPERATOR)); \
  return *this; \
} \
template <typename T, typename Policy> \
inline Checked_Number<T, Policy>& \
Checked_Number<T, Policy>::f(const T& y) { \
  Policy::handle_result(fun(*this, *this, y, \
			    Policy::ROUND_DEFAULT_OPERATOR)); \
  return *this; \
} \
template <typename T, typename Policy> \
template <typename From, typename From_Policy> \
inline Checked_Number<T, Policy>& \
Checked_Number<T, Policy>::f(const Checked_Number<From, From_Policy>& y) { \
  Checked_Number<T, Policy> cy(y); \
  Policy::handle_result(fun(*this, *this, cy, \
			    Policy::ROUND_DEFAULT_OPERATOR)); \
  return *this; \
} \
template <typename T, typename Policy> \
template <typename From> \
inline Checked_Number<T, Policy>& \
Checked_Number<T, Policy>::f(const From& y) { \
  Checked_Number<T, Policy> cy(y); \
  Policy::handle_result(fun(*this, *this, cy, \
			    Policy::ROUND_DEFAULT_OPERATOR)); \
  return *this; \
}

DEF_BINARY_OP_ASSIGN(operator +=, add_assign_r)
DEF_BINARY_OP_ASSIGN(operator -=, sub_assign_r)
DEF_BINARY_OP_ASSIGN(operator *=, mul_assign_r)
DEF_BINARY_OP_ASSIGN(operator /=, div_assign_r)
DEF_BINARY_OP_ASSIGN(operator %=, rem_assign_r)

#undef DEF_BINARY_OP_ASSIGN

#define DEF_BINARY_OP_TYPE(f, fun, Type) \
template <typename T, typename Policy> \
inline Checked_Number<T, Policy> \
f(const Type x, const Checked_Number<T, Policy>& y) { \
  Checked_Number<T, Policy> r(x); \
  Policy::handle_result(fun(r, r, y, Policy::ROUND_DEFAULT_OPERATOR)); \
  return r; \
} \
template <typename T, typename Policy> \
inline Checked_Number<T, Policy> \
f(const Checked_Number<T, Policy>& x, const Type y) { \
  Checked_Number<T, Policy> r(y); \
  Policy::handle_result(fun(r, x, r, Policy::ROUND_DEFAULT_OPERATOR)); \
  return r; \
}

#define DEF_BINARY_OP(f, fun) \
template <typename T, typename Policy> \
inline Checked_Number<T, Policy> \
f(const Checked_Number<T, Policy>& x, const Checked_Number<T, Policy>& y) { \
  Checked_Number<T, Policy> r; \
  Policy::handle_result(fun(r, x, y, Policy::ROUND_DEFAULT_OPERATOR)); \
  return r; \
} \
DEF_BINARY_OP_TYPE(f, fun, signed char) \
DEF_BINARY_OP_TYPE(f, fun, signed short) \
DEF_BINARY_OP_TYPE(f, fun, signed int) \
DEF_BINARY_OP_TYPE(f, fun, signed long) \
DEF_BINARY_OP_TYPE(f, fun, signed long long) \
DEF_BINARY_OP_TYPE(f, fun, unsigned char) \
DEF_BINARY_OP_TYPE(f, fun, unsigned short) \
DEF_BINARY_OP_TYPE(f, fun, unsigned int) \
DEF_BINARY_OP_TYPE(f, fun, unsigned long) \
DEF_BINARY_OP_TYPE(f, fun, unsigned long long) \
COND(PPL_SUPPORTED_FLOAT, DEF_BINARY_OP_TYPE(f, fun, float)) \
COND(PPL_SUPPORTED_DOUBLE, DEF_BINARY_OP_TYPE(f, fun, double)) \
COND(PPL_SUPPORTED_LONG_DOUBLE, DEF_BINARY_OP_TYPE(f, fun, long double)) \
DEF_BINARY_OP_TYPE(f, fun, mpz_class&) \
DEF_BINARY_OP_TYPE(f, fun, mpq_class&)

DEF_BINARY_OP(operator +, add_assign_r)
DEF_BINARY_OP(operator -, sub_assign_r)
DEF_BINARY_OP(operator *, mul_assign_r)
DEF_BINARY_OP(operator /, div_assign_r)
DEF_BINARY_OP(operator %, rem_assign_r)

#undef DEF_BINARY_OP_TYPE
#undef DEF_BINARY_OP

#define DEF_COMPARE_TYPE(f, fun, Type) \
template <typename From, typename From_Policy> \
inline bool \
f(const Type x, const Checked_Number<From, From_Policy>& y) { \
  return Checked::fun<Default_From_Policy, From_Policy>(x, y.raw_value()); \
} \
template <typename From, typename From_Policy> \
inline bool \
f(const Checked_Number<From, From_Policy>& x, const Type y) { \
  return Checked::fun<From_Policy, Default_From_Policy>(x.raw_value(), y); \
}

#define DEF_COMPARE(f, fun) \
template <typename T1, typename Policy1, \
          typename T2, typename Policy2> \
inline bool \
f(const Checked_Number<T1, Policy1>& x, \
  const Checked_Number<T2, Policy2>& y) { \
  return Checked::fun<Policy1, Policy2>(x.raw_value(), y.raw_value()); \
} \
DEF_COMPARE_TYPE(f, fun, signed char) \
DEF_COMPARE_TYPE(f, fun, signed short) \
DEF_COMPARE_TYPE(f, fun, signed int) \
DEF_COMPARE_TYPE(f, fun, signed long) \
DEF_COMPARE_TYPE(f, fun, signed long long) \
DEF_COMPARE_TYPE(f, fun, unsigned char) \
DEF_COMPARE_TYPE(f, fun, unsigned short) \
DEF_COMPARE_TYPE(f, fun, unsigned int) \
DEF_COMPARE_TYPE(f, fun, unsigned long) \
DEF_COMPARE_TYPE(f, fun, unsigned long long) \
COND(PPL_SUPPORTED_FLOAT, DEF_COMPARE_TYPE(f, fun, float)) \
COND(PPL_SUPPORTED_DOUBLE, DEF_COMPARE_TYPE(f, fun, double)) \
COND(PPL_SUPPORTED_LONG_DOUBLE, DEF_COMPARE_TYPE(f, fun, long double)) \
DEF_COMPARE_TYPE(f, fun, mpz_class&) \
DEF_COMPARE_TYPE(f, fun, mpq_class&)


DEF_COMPARE(operator ==, eq_ext)
DEF_COMPARE(operator !=, ne_ext)
DEF_COMPARE(operator >=, ge_ext)
DEF_COMPARE(operator >, gt_ext)
DEF_COMPARE(operator <=, le_ext)
DEF_COMPARE(operator <, lt_ext)

#undef DEF_COMPARE_TYPE
#undef DEF_COMPARE

/*! \relates Checked_Number */
template <typename T, typename Policy>
inline Checked_Number<T, Policy>
operator+(const Checked_Number<T, Policy>& x) {
  return x;
}

/*! \relates Checked_Number */
template <typename T, typename Policy>
inline Checked_Number<T, Policy>
operator-(const Checked_Number<T, Policy>& x) {
  Checked_Number<T, Policy> r;
  Policy::handle_result(neg_assign_r(r, x, Policy::ROUND_DEFAULT_OPERATOR));
  return r;
}

#define DEF_ASSIGN_FUN2_1(f, fun) \
template <typename T, typename Policy> \
inline void \
f(Checked_Number<T, Policy>& x) { \
  Policy::handle_result(fun(x, x, Policy::ROUND_DEFAULT_FUNCTION));	\
}

#define DEF_ASSIGN_FUN2_2(f, fun) \
template <typename T, typename Policy> \
inline void \
f(Checked_Number<T, Policy>& x, const Checked_Number<T, Policy>& y) { \
  Policy::handle_result(fun(x, y, Policy::ROUND_DEFAULT_FUNCTION)); \
}

#define DEF_ASSIGN_FUN3_3(f, fun) \
template <typename T, typename Policy> \
inline void \
f(Checked_Number<T, Policy>& x, const Checked_Number<T, Policy>& y, \
  const Checked_Number<T, Policy>& z) { \
  Policy::handle_result(fun(x, y, z, Policy::ROUND_DEFAULT_FUNCTION)); \
}

#define DEF_ASSIGN_FUN5_5(f, fun)					\
template <typename T, typename Policy>					\
inline void								\
f(Checked_Number<T, Policy>& x, const Checked_Number<T, Policy>& y,	\
  const Checked_Number<T, Policy>& z,					\
  Checked_Number<T, Policy>& s, Checked_Number<T, Policy>& t) {		\
  Policy::handle_result(fun(x, y, z, s, t, Policy::ROUND_DEFAULT_FUNCTION)); \
}

DEF_ASSIGN_FUN2_2(sqrt_assign, sqrt_assign_r)

DEF_ASSIGN_FUN2_1(neg_assign, neg_assign_r)
DEF_ASSIGN_FUN2_2(neg_assign, neg_assign_r)

DEF_ASSIGN_FUN3_3(add_mul_assign, add_mul_assign_r)

DEF_ASSIGN_FUN3_3(sub_mul_assign, sub_mul_assign_r)

DEF_ASSIGN_FUN3_3(gcd_assign, gcd_assign_r)

DEF_ASSIGN_FUN5_5(gcdext_assign, gcdext_assign_r)

DEF_ASSIGN_FUN3_3(lcm_assign, lcm_assign_r)

#undef DEF_ASSIGN_FUN2_1
#undef DEF_ASSIGN_FUN2_2
#undef DEF_ASSIGN_FUN3_2
#undef DEF_ASSIGN_FUN3_3

template <typename T, typename Policy>
inline void
exact_div_assign(Checked_Number<T, Policy>& x,
		 const Checked_Number<T, Policy>& y,
		 const Checked_Number<T, Policy>& z) {
  Policy::handle_result(div_assign_r(x, y, z, ROUND_NOT_NEEDED));
}

/*! \relates Checked_Number */
template <typename T, typename Policy>
inline int
sgn(const Checked_Number<T, Policy>& x) {
  Result r = Checked::sgn_ext<Policy>(x.raw_value());
  switch (r) {
  case V_LT:
    return -1;
  case V_EQ:
    return 0;
  case V_GT:
    return 1;
  default:
    throw(0);
  }
}

/*! \relates Checked_Number */
template <typename T1, typename Policy1,
	  typename T2, typename Policy2>
inline int
cmp(const Checked_Number<T1, Policy1>& x,
    const Checked_Number<T2, Policy2>& y) {
  Result r = Checked::cmp_ext<Policy1, Policy2>(x.raw_value(), y.raw_value());
  switch (r) {
  case V_LT:
    return -1;
  case V_EQ:
    return 0;
  case V_GT:
    return 1;
  default:
    throw(0);
  }
}

/*! \relates Checked_Number */
template <typename T, typename Policy>
inline Result
output(std::ostream& os, const Checked_Number<T, Policy>& x,
       const Numeric_Format& fmt, Rounding_Dir dir) {
  return check_result(Checked::output_ext<Policy>(os,
						  x.raw_value(),
						  fmt,
						  rounding_dir(dir)),
		      dir);
}

/*! \relates Checked_Number */
template <typename T, typename Policy>
inline std::ostream&
operator<<(std::ostream& os, const Checked_Number<T, Policy>& x) {
  Policy::handle_result(output(os, x, Numeric_Format(), ROUND_IGNORE));
  return os;
}

/*! \relates Checked_Number */
template <typename T, typename Policy>
inline Result
input(Checked_Number<T, Policy>& x, std::istream& is, Rounding_Dir dir) {
  return check_result(Checked::input_ext<Policy>(x.raw_value(),
						 is,
						 rounding_dir(dir)),
		      dir);
}

/*! \relates Checked_Number */
template <typename T, typename Policy>
inline std::istream& operator>>(std::istream& is,
				Checked_Number<T, Policy>& x) {
  Result r = input(x, is, Policy::ROUND_DEFAULT_INPUT);
  if (r == V_CVT_STR_UNK)
    is.setstate(std::ios::failbit);
  else
    Policy::handle_result(r);
  return is;
}

template <typename T>
inline T
plus_infinity() {
  return PLUS_INFINITY;
}

template <typename T>
inline T
minus_infinity() {
  return MINUS_INFINITY;
}

template <typename T>
inline T
not_a_number() {
  return NOT_A_NUMBER;
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/checked_numeric_limits.hh line 1
/* Specializations of std::numeric_limits for "checked" types.
*/


// Automatically generated from PPL source file ../src/mp_numeric_limits.hh line 1
/* Specializations of std::numeric_limits for multi-precision types.
   This will become obsolete when GMP and MPFR will provide the
   specializations by themselves.
*/


#include <gmpxx.h>
#include <limits>

namespace std {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Specialization of std::numeric_limits.
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <>
class numeric_limits<mpz_class> {
private:
  typedef mpz_class Type;

public:
  static const bool is_specialized = true;
  static const int digits = 0;
  static const int digits10 = 0;
  static const bool is_signed = true;
  static const bool is_integer = true;
  static const bool is_exact = true;
  static const int radix = 2;
  static const int min_exponent = 0;
  static const int min_exponent10 = 0;
  static const int max_exponent = 0;
  static const int max_exponent10 = 0;
  static const bool has_infinity = false;
  static const bool has_quiet_NaN =  false;
  static const bool has_signaling_NaN = false;
  static const float_denorm_style has_denorm = denorm_absent;
  static const bool has_denorm_loss = false;
  static const bool is_iec559 = false;
  static const bool is_bounded = false;
  static const bool is_modulo = false;
  static const bool traps = false;
  static const bool tinyness_before = false;
  static const float_round_style round_style = round_toward_zero;

  static Type min() {
    return static_cast<Type>(0);
  }

  static Type max() {
    return static_cast<Type>(0);
  }

  static Type epsilon() {
    return static_cast<Type>(0);
  }

  static Type round_error() {
    return static_cast<Type>(0);
  }

  static Type infinity() {
    return static_cast<Type>(0);
  }

  static Type quiet_NaN() {
    return static_cast<Type>(0);
  }

  static Type denorm_min() {
    return static_cast<Type>(1);
  }
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Specialization of std::numeric_limits.
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <>
class numeric_limits<mpq_class> {
private:
  typedef mpq_class Type;

public:
  static const bool is_specialized = true;
  static const int digits = 0;
  static const int digits10 = 0;
  static const bool is_signed = true;
  static const bool is_integer = false;
  static const bool is_exact = true;
  static const int radix = 2;
  static const int min_exponent = 0;
  static const int min_exponent10 = 0;
  static const int max_exponent = 0;
  static const int max_exponent10 = 0;
  static const bool has_infinity = false;
  static const bool has_quiet_NaN =  false;
  static const bool has_signaling_NaN = false;
  static const float_denorm_style has_denorm = denorm_absent;
  static const bool has_denorm_loss = false;
  static const bool is_iec559 = false;
  static const bool is_bounded = false;
  static const bool is_modulo = false;
  static const bool traps = false;
  static const bool tinyness_before = false;
  static const float_round_style round_style = round_toward_zero;

  static Type min() {
    return static_cast<Type>(0);
  }

  static Type max() {
    return static_cast<Type>(0);
  }

  static Type epsilon() {
    return static_cast<Type>(0);
  }

  static Type round_error() {
    return static_cast<Type>(0);
  }

  static Type infinity() {
    return static_cast<Type>(0);
  }

  static Type quiet_NaN() {
    return static_cast<Type>(0);
  }

  static Type denorm_min() {
    return static_cast<Type>(0);
  }
};

} // namespace std

// Automatically generated from PPL source file ../src/checked_numeric_limits.hh line 29
#include <limits>

namespace std {

#define PPL_SPECIALIZE_LIMITS_INT(T)					\
/*! \brief Partial specialization of std::numeric_limits. */		\
template <typename Policy>						\
class numeric_limits<Parma_Polyhedra_Library::Checked_Number<T, Policy> > \
  : public numeric_limits<T> {						\
 private:								\
  typedef Parma_Polyhedra_Library::Checked_Number<T, Policy> Type;	\
									\
 public:								\
  static const bool has_infinity = Policy::handle_infinity;		\
  static const bool has_quiet_NaN =  Policy::handle_nan;			\
									\
  static Type min() {							\
    return Parma_Polyhedra_Library::Checked::Extended_Int<Policy, T>::min; \
  }									\
									\
  static Type max() {							\
    return Parma_Polyhedra_Library::Checked::Extended_Int<Policy, T>::max; \
  }									\
									\
  static Type infinity() {						\
    return								\
      Policy::handle_infinity						\
      ? Parma_Polyhedra_Library::PLUS_INFINITY				\
      : static_cast<Type>(0);						\
  }									\
									\
  static Type quiet_NaN() {						\
    return								\
      Policy::handle_nan							\
      ? Parma_Polyhedra_Library::NOT_A_NUMBER				\
      : static_cast<Type>(0);						\
  }									\
};

PPL_SPECIALIZE_LIMITS_INT(signed char)
PPL_SPECIALIZE_LIMITS_INT(signed short)
PPL_SPECIALIZE_LIMITS_INT(signed int)
PPL_SPECIALIZE_LIMITS_INT(signed long)
PPL_SPECIALIZE_LIMITS_INT(signed long long)

PPL_SPECIALIZE_LIMITS_INT(unsigned char)
PPL_SPECIALIZE_LIMITS_INT(unsigned short)
PPL_SPECIALIZE_LIMITS_INT(unsigned int)
PPL_SPECIALIZE_LIMITS_INT(unsigned long)
PPL_SPECIALIZE_LIMITS_INT(unsigned long long)

#undef PPL_SPECIALIZE_LIMITS_INT

#define PPL_SPECIALIZE_LIMITS_FLOAT(T)					\
/*! \brief Partial specialization of std::numeric_limits. */		\
template <typename Policy>						\
struct numeric_limits<Parma_Polyhedra_Library::Checked_Number<T, Policy> > \
  : public numeric_limits<T> {						\
};

#if PPL_SUPPORTED_FLOAT
PPL_SPECIALIZE_LIMITS_FLOAT(float)
#endif
#if PPL_SUPPORTED_DOUBLE
PPL_SPECIALIZE_LIMITS_FLOAT(double)
#endif
#if PPL_SUPPORTED_LONG_DOUBLE
PPL_SPECIALIZE_LIMITS_FLOAT(long double)
#endif

#undef PPL_SPECIALIZE_LIMITS_FLOAT

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Partial specialization of std::numeric_limits.
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename Policy>
class
numeric_limits<Parma_Polyhedra_Library::Checked_Number<mpz_class, Policy> >
  : public numeric_limits<mpz_class> {
private:
  typedef Parma_Polyhedra_Library::Checked_Number<mpz_class, Policy> Type;

public:
  static const bool has_infinity = Policy::handle_infinity;
  static const bool has_quiet_NaN =  Policy::handle_nan;

  static Type infinity() {
    return
      Policy::handle_infinity
      ? Parma_Polyhedra_Library::PLUS_INFINITY
      : static_cast<Type>(0);
  }

  static Type quiet_NaN() {
    return
      Policy::handle_nan
      ? Parma_Polyhedra_Library::NOT_A_NUMBER
      : static_cast<Type>(0);
  }
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Partial specialization of std::numeric_limits.
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename Policy>
class
numeric_limits<Parma_Polyhedra_Library::Checked_Number<mpq_class, Policy> >
: public numeric_limits<mpq_class> {
private:
  typedef Parma_Polyhedra_Library::Checked_Number<mpq_class, Policy> Type;

public:
  static const bool has_infinity = Policy::handle_infinity;
  static const bool has_quiet_NaN =  Policy::handle_nan;

  static Type infinity() {
    return
      Policy::handle_infinity
      ? Parma_Polyhedra_Library::PLUS_INFINITY
      : static_cast<Type>(0);
  }

  static Type quiet_NaN() {
    return
      Policy::handle_nan
      ? Parma_Polyhedra_Library::NOT_A_NUMBER
      : static_cast<Type>(0);
  }
};

} // namespace std

// Automatically generated from PPL source file ../src/Checked_Number.defs.hh line 912

// Automatically generated from PPL source file ../src/Coefficient.types.hh line 16

#if defined(CHECKED_INTEGERS) || defined(NATIVE_INTEGERS)

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Coefficient traits specialization for 8 bits checked integers.
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename Policy>
struct Coefficient_traits_template<Checked_Number<int8_t, Policy> > {
  //! The type used for references to const 8 bit checked integers.
  typedef Checked_Number<int8_t, Policy> const_reference;
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Coefficient traits specialization for 16 bits checked integers.
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename Policy>
struct Coefficient_traits_template<Checked_Number<int16_t, Policy> > {
  //! The type used for references to const 16 bit checked integers.
  typedef Checked_Number<int16_t, Policy> const_reference;
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Coefficient traits specialization for 32 bits checked integers.
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename Policy>
struct Coefficient_traits_template<Checked_Number<int32_t, Policy> > {
  //! The type used for references to const 32 bit checked integers.
  typedef Checked_Number<int32_t, Policy> const_reference;
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Coefficient traits specialization for 64 bits checked integers.
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename Policy>
struct Coefficient_traits_template<Checked_Number<int64_t, Policy> > {
  //! The type used for references to const 64 bit checked integers.
  typedef const Checked_Number<int64_t, Policy>& const_reference;
};

} // namespace Parma_Polyhedra_Library

#endif // defined(CHECKED_INTEGERS) || defined(NATIVE_INTEGERS)

#ifdef GMP_INTEGERS
// Automatically generated from PPL source file ../src/Coefficient.types.hh line 67
#endif

namespace Parma_Polyhedra_Library {

//! An alias for easily naming the type of PPL coefficients.
/*! \ingroup PPL_CXX_interface
  Objects of type Coefficient are used to implement the integral valued
  coefficients occurring in linear expressions, constraints, generators,
  intervals, bounding boxes and so on. Depending on the chosen
  configuration options (see file <CODE>README.configure</CODE>),
  a Coefficient may actually be:
    - The GMP_Integer type, which in turn is an alias for the
      <CODE>mpz_class</CODE> type implemented by the C++ interface
      of the GMP library (this is the default configuration);
    - An instance of the Checked_Number class template: with its default
      policy (Checked_Number_Default_Policy), this implements overflow
      detection on top of a native integral type (available template
      instances include checked integers having 8, 16, 32 or 64 bits);
      with the Checked_Number_Transparent_Policy, this is a wrapper
      for native integral types with no overflow detection
      (available template instances are as above).
*/
typedef COEFFICIENT_TYPE Coefficient;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! An alias for easily naming the coefficient traits.
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
typedef Coefficient_traits_template<Coefficient> Coefficient_traits;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Interval.types.hh line 1


namespace Parma_Polyhedra_Library {

class Boundary;
class LBoundary;
class UBoundary;
class Interval;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Bounding_Box.types.hh line 1


namespace Parma_Polyhedra_Library {

class Bounding_Box;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Constraint.types.hh line 1


namespace Parma_Polyhedra_Library {

class Constraint;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Generator.types.hh line 1


namespace Parma_Polyhedra_Library {

class Generator;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Grid_Generator.types.hh line 1


namespace Parma_Polyhedra_Library {

class Grid_Generator;

}

// Automatically generated from PPL source file ../src/Congruence.types.hh line 1


namespace Parma_Polyhedra_Library {

class Congruence;

}

// Automatically generated from PPL source file ../src/Init.types.hh line 1


namespace Parma_Polyhedra_Library {

class Init;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Row.types.hh line 1


namespace Parma_Polyhedra_Library {

class Row_Impl_Handler;
class Row;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Linear_Row.types.hh line 1


namespace Parma_Polyhedra_Library {

class Linear_Row;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Matrix.types.hh line 1


namespace Parma_Polyhedra_Library {

class Matrix;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Variable.types.hh line 1


namespace Parma_Polyhedra_Library {

class Variable;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Linear_Expression.types.hh line 1


namespace Parma_Polyhedra_Library {

class Linear_Expression;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Linear_System.types.hh line 1


namespace Parma_Polyhedra_Library {

class Linear_System;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Saturation_Row.types.hh line 1


namespace Parma_Polyhedra_Library {

class Saturation_Row;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Saturation_Matrix.types.hh line 1


namespace Parma_Polyhedra_Library {

class Saturation_Matrix;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Constraint_System.types.hh line 1


namespace Parma_Polyhedra_Library {

class Constraint_System;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Generator_System.types.hh line 1


namespace Parma_Polyhedra_Library {

class Generator_System;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Grid_Generator_System.types.hh line 1


namespace Parma_Polyhedra_Library {

class Grid_Generator_System;

}

// Automatically generated from PPL source file ../src/Congruence_System.types.hh line 1


namespace Parma_Polyhedra_Library {

class Congruence_System;

}

// Automatically generated from PPL source file ../src/Scalar_Products.types.hh line 1


namespace Parma_Polyhedra_Library {

class Scalar_Products;
class Topology_Adjusted_Scalar_Product_Sign;
class Topology_Adjusted_Scalar_Product_Assign;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/LP_Problem.types.hh line 1


namespace Parma_Polyhedra_Library {

//! Possible outcomes of the LP_Problem solver.
/*! \ingroup PPL_CXX_interface */
enum LP_Problem_Status {
  //! The problem is unfeasible.
  UNFEASIBLE_LP_PROBLEM,
  //! The problem is unbounded.
  UNBOUNDED_LP_PROBLEM,
  //! The problem has an optimal solution.
  OPTIMIZED_LP_PROBLEM
};

class LP_Problem;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Poly_Con_Relation.types.hh line 1


namespace Parma_Polyhedra_Library {

class Poly_Con_Relation;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Poly_Gen_Relation.types.hh line 1


namespace Parma_Polyhedra_Library {

class Poly_Gen_Relation;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/BHRZ03_Certificate.types.hh line 1


namespace Parma_Polyhedra_Library {

class BHRZ03_Certificate;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/H79_Certificate.types.hh line 1


namespace Parma_Polyhedra_Library {

class H79_Certificate;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Grid_Certificate.types.hh line 1


namespace Parma_Polyhedra_Library {

class Grid_Certificate;

}

// Automatically generated from PPL source file ../src/Polyhedron.types.hh line 1


namespace Parma_Polyhedra_Library {

class Polyhedron;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/C_Polyhedron.types.hh line 1


namespace Parma_Polyhedra_Library {

class C_Polyhedron;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/NNC_Polyhedron.types.hh line 1


namespace Parma_Polyhedra_Library {

class NNC_Polyhedron;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Grid.types.hh line 1


namespace Parma_Polyhedra_Library {

class Grid;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Ptr_Iterator.types.hh line 1


namespace Parma_Polyhedra_Library {

namespace Implementation {

template <typename P>
class Ptr_Iterator;

} // namespace Implementation

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/DB_Row.types.hh line 1


namespace Parma_Polyhedra_Library {

template <typename BT>
class DB_Row_Impl_Handler;

template <typename BT>
class DB_Row;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/DB_Matrix.types.hh line 1


namespace Parma_Polyhedra_Library {

template <typename T>
class DB_Matrix;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/BD_Shape.types.hh line 1


namespace Parma_Polyhedra_Library {

template <typename T>
class BD_Shape;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/GMP_Integer.defs.hh line 1
/* GMP_Integer class declaration.
*/


// Automatically generated from PPL source file ../src/GMP_Integer.defs.hh line 28
#include <cstddef>

namespace Parma_Polyhedra_Library {

//! \name Accessor Functions
//@{

//! Returns a const reference to the underlying integer value.
/*! \relates GMP_Integer */
const mpz_class& raw_value(const GMP_Integer& x);

//! Returns a reference to the underlying integer value.
/*! \relates GMP_Integer */
mpz_class& raw_value(GMP_Integer& x);

//@} // Accessor Functions

//! \name Memory Size Inspection Functions
//@{

//! Returns the total size in bytes of the memory occupied by \p x.
/*! \relates GMP_Integer */
memory_size_type total_memory_in_bytes(const GMP_Integer& x);

//! Returns the size in bytes of the memory managed by \p x.
/*! \relates GMP_Integer */
memory_size_type external_memory_in_bytes(const GMP_Integer& x);

//@} // Memory Size Inspection Functions

//! \name Arithmetic Operators
//@{

//! Assigns to \p x its negation.
/*! \relates GMP_Integer */
void neg_assign(GMP_Integer& x);

//! Assigns to \p x the negation of \p y.
/*! \relates GMP_Integer */
void neg_assign(GMP_Integer& x, const GMP_Integer& y);

//! Assigns to \p x the greatest common divisor of \p y and \p z.
/*! \relates GMP_Integer */
void gcd_assign(GMP_Integer& x,
		const GMP_Integer& y, const GMP_Integer& z);

//! Extended GCD.
/*! \relates GMP_Integer
  Assigns to \p x the greatest common divisor of \p y and \p z, and to
  \p s and \p t the values such that \p y * \p s + \p z * \p t = \p x.
*/
void gcdext_assign(GMP_Integer& x,
		   const GMP_Integer& y, const GMP_Integer& z,
		   GMP_Integer& s, GMP_Integer& t);

//! Assigns to \p x the least common multiple of \p y and \p z.
/*! \relates GMP_Integer */
void lcm_assign(GMP_Integer& x,
		const GMP_Integer& y, const GMP_Integer& z);

//! Assigns to \p x the value <CODE>x + y * z</CODE>.
/*! \relates GMP_Integer */
void add_mul_assign(GMP_Integer& x,
		    const GMP_Integer& y, const GMP_Integer& z);

//! Assigns to \p x the value <CODE>x - y * z</CODE>.
/*! \relates GMP_Integer */
void sub_mul_assign(GMP_Integer& x,
		    const GMP_Integer& y, const GMP_Integer& z);

/*! \brief
  If \p z divides \p y, assigns to \p x the quotient of the integer
  division of \p y and \p z.

  \relates GMP_Integer
  The behavior is undefined if \p z does not divide \p y.
*/
void exact_div_assign(GMP_Integer& x,
		      const GMP_Integer& y, const GMP_Integer& z);

//! Assigns to \p x the integer square root of \p y.
/*! \relates GMP_Integer */
void sqrt_assign(GMP_Integer& x, const GMP_Integer& y);

/*! \brief
  Returns a negative, zero or positive value depending on whether
  \p x is lower than, equal to or greater than \p y, respectively.

  \relates GMP_Integer
*/
int cmp(const GMP_Integer& x, const GMP_Integer& y);

//@} // Arithmetic Operators

} // namespace Parma_Polyhedra_Library


namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::GMP_Integer */
void swap(Parma_Polyhedra_Library::GMP_Integer& x,
	  Parma_Polyhedra_Library::GMP_Integer& y);

} // namespace std

// Automatically generated from PPL source file ../src/GMP_Integer.inlines.hh line 1
/* GMP_Integer class implementation: inline functions.
*/


namespace Parma_Polyhedra_Library {

inline void
neg_assign(GMP_Integer& x) {
  mpz_neg(x.get_mpz_t(), x.get_mpz_t());
}

inline void
neg_assign(GMP_Integer& x, const GMP_Integer& y) {
  mpz_neg(x.get_mpz_t(), y.get_mpz_t());
}

inline void
gcd_assign(GMP_Integer& x, const GMP_Integer& y, const GMP_Integer& z) {
  mpz_gcd(x.get_mpz_t(), y.get_mpz_t(), z.get_mpz_t());
}

inline void
gcdext_assign(GMP_Integer& x,
	      const GMP_Integer& y, const GMP_Integer& z,
	      GMP_Integer& s, GMP_Integer& t) {
  mpz_gcdext(x.get_mpz_t(),
	     s.get_mpz_t(), t.get_mpz_t(),
	     y.get_mpz_t(), z.get_mpz_t());
}

inline void
lcm_assign(GMP_Integer& x, const GMP_Integer& y, const GMP_Integer& z) {
  mpz_lcm(x.get_mpz_t(), y.get_mpz_t(), z.get_mpz_t());
}

inline void
add_mul_assign(GMP_Integer& x, const GMP_Integer& y, const GMP_Integer& z) {
  mpz_addmul(x.get_mpz_t(), y.get_mpz_t(), z.get_mpz_t());
}

inline void
sub_mul_assign(GMP_Integer& x, const GMP_Integer& y, const GMP_Integer& z) {
  mpz_submul(x.get_mpz_t(), y.get_mpz_t(), z.get_mpz_t());
}

inline void
exact_div_assign(GMP_Integer& x, const GMP_Integer& y, const GMP_Integer& z) {
  assert(y % z == 0);
  mpz_divexact(x.get_mpz_t(), y.get_mpz_t(), z.get_mpz_t());
}

inline void
sqrt_assign(GMP_Integer& x, const GMP_Integer& y) {
  mpz_sqrt(x.get_mpz_t(), y.get_mpz_t());
}

inline int
cmp(const GMP_Integer& x, const GMP_Integer& y) {
  return mpz_cmp(x.get_mpz_t(), y.get_mpz_t());
}

inline const mpz_class&
raw_value(const GMP_Integer& x) {
  return x;
}

inline mpz_class&
raw_value(GMP_Integer& x) {
  return x;
}

inline memory_size_type
external_memory_in_bytes(const GMP_Integer& x) {
  return x.get_mpz_t()[0]._mp_alloc * SIZEOF_MP_LIMB_T;
}

inline memory_size_type
total_memory_in_bytes(const GMP_Integer& x) {
  return sizeof(x) + external_memory_in_bytes(x);
}

} // namespace Parma_Polyhedra_Library

/*! \relates Parma_Polyhedra_Library::GMP_Integer */
inline void
std::swap(Parma_Polyhedra_Library::GMP_Integer& x,
	  Parma_Polyhedra_Library::GMP_Integer& y) {
  mpz_swap(x.get_mpz_t(), y.get_mpz_t());
}

// Automatically generated from PPL source file ../src/GMP_Integer.defs.hh line 135

// Automatically generated from PPL source file ../src/Coefficient.defs.hh line 1
/* Coefficient class declaration.
*/


// Automatically generated from PPL source file ../src/Coefficient.defs.hh line 27
#include <iosfwd>

#if defined(CHECKED_INTEGERS) || defined(NATIVE_INTEGERS)
// Automatically generated from PPL source file ../src/Coefficient.defs.hh line 32
#endif

#ifdef GMP_INTEGERS
// Automatically generated from PPL source file ../src/Coefficient.defs.hh line 36
#endif

namespace Parma_Polyhedra_Library {

Coefficient_traits::const_reference Coefficient_zero();
Coefficient_traits::const_reference Coefficient_one();

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Coefficient.inlines.hh line 1
/* Coefficient class implementation: inline functions.
*/


namespace Parma_Polyhedra_Library {

inline Coefficient_traits::const_reference
Coefficient_zero() {
  static Coefficient z(0);
  return z;
}

inline Coefficient_traits::const_reference
Coefficient_one() {
  static Coefficient o(1);
  return o;
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Coefficient.defs.hh line 46

// Automatically generated from PPL source file ../src/globals.defs.hh line 1
/* Declarations of global objects.
*/


// Automatically generated from PPL source file ../src/globals.defs.hh line 28
#include <exception>

namespace Parma_Polyhedra_Library {

//! Returns a value that does not designate a valid dimension.
dimension_type
not_a_dimension();

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A node of the list of available coefficients.
/*! \ingroup PPL_CXX_interface */
// FIXME: rewrite the comment.
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
class Coefficient_free_list_element {
private:
  Coefficient i;
  Coefficient_free_list_element* p;

public:
  Coefficient_free_list_element()
    : i() {
  }

  Coefficient& integer() {
    return i;
  }

  Coefficient_free_list_element*& next() {
    return p;
  }
};

extern Coefficient_free_list_element* Coefficient_free_list_first;

inline Coefficient&
get_tmp_Coefficient() {
  Coefficient* p;
  if (Coefficient_free_list_first != 0) {
    p = &Coefficient_free_list_first->integer();
    Coefficient_free_list_first = Coefficient_free_list_first->next();
  }
  else
    p = reinterpret_cast<Coefficient*>(new Coefficient_free_list_element());
  return *p;
}

inline void
release_tmp_Coefficient(Coefficient& i) {
  Coefficient_free_list_element& e
    = reinterpret_cast<Coefficient_free_list_element&>(i);
  e.next() = Coefficient_free_list_first;
  Coefficient_free_list_first = &e;
}

class Temp_Coefficient_Holder {
private:
  Coefficient& hold;

public:
  Temp_Coefficient_Holder(Coefficient& i)
    : hold(i) {
  }
  ~Temp_Coefficient_Holder() {
    release_tmp_Coefficient(hold);
  }
};

#if 1
#define TEMP_INTEGER(id) \
Coefficient& id = get_tmp_Coefficient(); \
Temp_Coefficient_Holder temp_Coefficient_holder_ ## id = (id)
#else
#define TEMP_INTEGER(id) static Coefficient id
#endif

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Speculative allocation function.
/*!
  \return
  The actual capacity to be allocated.

  \param requested_size
  The number of elements we need.

  \param maximum_size
  The maximum number of elements to be allocated. It is assumed
  to be no less than \p requested_size.

  Computes a capacity given a requested size.
  Allows for speculative allocation aimed at reducing the number of
  reallocations enough to guarantee amortized constant insertion time
  for our vector-like data structures. In all cases, the speculative
  allocation will not exceed \p maximum_size.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
dimension_type
compute_capacity(dimension_type requested_size,
		 dimension_type maximum_size);

//! User objects the PPL can throw.
/*! \ingroup PPL_CXX_interface
  This abstract base class should be instantiated by those users
  willing to provide a polynomial upper bound to the time spent
  by any invocation of a library operator.
*/
class Throwable {
public:
  //! Throws the user defined exception object.
  virtual void throw_me() const = 0;

  //! Virtual destructor.
  virtual ~Throwable();
};

/*! \brief
  A pointer to an exception object.

  \ingroup PPL_CXX_interface
  This pointer, which is initialized to zero, is repeatedly checked
  along any super-linear (i.e., computationally expensive) computation
  path in the library.
  When it is found nonzero the exception it points to is thrown.
  In other words, making this pointer point to an exception (and
  leaving it in this state) ensures that the library will return
  control to the client application, possibly by throwing the given
  exception, within a time that is a linear function of the size
  of the representation of the biggest object (powerset of polyhedra,
  polyhedron, system of constraints or generators) on which the library
  is operating upon.

  \note
  The only sensible way to assign to this pointer is from within a
  signal handler or from a parallel thread.  For this reason, the
  library, apart from ensuring that the pointer is initially set to zero,
  never assigns to it.  In particular, it does not zero it again when
  the exception is thrown: it is the client's responsibility to do so.
*/
extern const Throwable* volatile abandon_expensive_computations;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  If the pointer abandon_expensive_computations is found
  to be nonzero, the exception it points to is thrown.

  \relates Throwable
*/
#endif
void
maybe_abandon();

//! A tag class.
/*! \ingroup PPL_CXX_interface
  Tag class to differentiate the C_Polyhedron and NNC_Polyhedron
  constructors that build a polyhedron out of a bounding box.
*/
struct From_Bounding_Box {
};

//! A tag class.
/*! \ingroup PPL_CXX_interface
  Tag class to make the Grid covering box constructor unique.
*/
struct From_Covering_Box {
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  If \f$g\f$ is the GCD of \p x and \p y, the values of \p x and \p y
  divided by \f$g\f$ are assigned to \p nx and \p ny, respectively.

  \note
  \p x and \p nx may be the same object and likewise for
  \p y and \p ny.  Any other aliasing results in undefined behavior.
*/
#endif
void
normalize2(Coefficient_traits::const_reference x,
	   Coefficient_traits::const_reference y,
	   Coefficient& nx, Coefficient& ny);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns a mask for the lowest \p n bits,
#endif
template <typename T>
T low_bits_mask(unsigned n);

// Turn s into a string: PPL_STR(x + y) => "x + y".
#define PPL_STR(s) #s
// Turn the expansion of s into a string: PPL_XSTR(x) => "x expanded".
#define PPL_XSTR(s) PPL_STR(s)

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
#define PPL_OUTPUT_DECLARATIONS						\
  /*! \brief Writes to \c std::cerr an ASCII representation of \p *this. */ \
  void ascii_dump() const;						\
  /*! \brief Writes to \p s an ASCII representation of \p *this. */	\
  void ascii_dump(std::ostream& s) const;				\
  /*! \brief Prints \p *this to \c std::cerr using \c operator<<. */	\
  void print() const;
#else
#define PPL_OUTPUT_DECLARATIONS					\
  void ascii_dump() const;					\
  void ascii_dump(std::ostream& s) const;			\
  void print() const;
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS

#define PPL_OUTPUT_DEFINITIONS(class_name)			\
  void								\
  Parma_Polyhedra_Library::class_name::ascii_dump() const {	\
    ascii_dump(std::cerr);					\
  }								\
								\
  void								\
  Parma_Polyhedra_Library::class_name::print() const {		\
    using namespace IO_Operators;				\
    std::cerr << *this;						\
  }

#define PPL_OUTPUT_DEFINITIONS_ASCII_ONLY(class_name)			\
  void									\
  Parma_Polyhedra_Library::class_name::ascii_dump() const {		\
    ascii_dump(std::cerr);						\
  }									\
									\
  void									\
  Parma_Polyhedra_Library::class_name::print() const {			\
    std::cerr << "No user level output operator defined "		\
	      << "for class " PPL_XSTR(class_name) << "." << std::endl; \
  }

#define PPL_OUTPUT_TEMPLATE_DEFINITIONS(type_symbol, class_prefix)	\
  template <typename type_symbol>					\
  void									\
  class_prefix::ascii_dump() const {					\
    ascii_dump(std::cerr);						\
  }									\
									\
  template <typename type_symbol>					\
  void									\
  class_prefix::print() const {						\
    using namespace IO_Operators;					\
    std::cerr << *this;							\
  }

#define PPL_OUTPUT_TEMPLATE_DEFINITIONS_ASCII_ONLY(type_symbol, class_prefix) \
  template <typename type_symbol>					\
  void									\
  class_prefix::ascii_dump() const {					\
    ascii_dump(std::cerr);						\
  }									\
									\
  template <typename type_symbol>					\
  void									\
  class_prefix::print() const {						\
    std::cerr << "No user level output operator defined "		\
	      << "for " PPL_XSTR(class_prefix) << "." << std::endl;	\
  }

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/globals.inlines.hh line 1
/* Implementation of global objects: inline functions.
*/


// Automatically generated from PPL source file ../src/globals.inlines.hh line 27
#include <limits>
#include <cassert>

namespace Parma_Polyhedra_Library {

inline dimension_type
not_a_dimension() {
  return std::numeric_limits<dimension_type>::max();
}

inline
Throwable::~Throwable() {
}

inline void
maybe_abandon() {
  if (const Throwable* p = abandon_expensive_computations)
    p->throw_me();
}

inline dimension_type
compute_capacity(const dimension_type requested_size,
		 const dimension_type maximum_size) {
  assert(requested_size <= maximum_size);
  // Speculation factor 2.
  return (requested_size < maximum_size / 2)
    ? 2*(requested_size + 1)
    : maximum_size;
  // Speculation factor 1.5.
  // return (maximum_size - requested_size > requested_size/2)
  //   ? requested_size + requested_size/2 + 1
  //   : maximum_size;
}

inline void
normalize2(Coefficient_traits::const_reference x,
	   Coefficient_traits::const_reference y,
	   Coefficient& nx, Coefficient& ny) {
  TEMP_INTEGER(gcd);
  gcd_assign(gcd, x, y);
  exact_div_assign(nx, x, gcd);
  exact_div_assign(ny, y, gcd);
}

template <typename T>
inline T
low_bits_mask(const unsigned n) {
  assert(n < unsigned(std::numeric_limits<T>::digits));
  return n == 0 ? 0 : ~(~(T(0u)) << n);
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/globals.defs.hh line 289

// Automatically generated from PPL source file ../src/Interval.defs.hh line 1
/* Declarations for the Interval class and its constituents.
*/


// Automatically generated from PPL source file ../src/Interval.defs.hh line 29
#include <gmpxx.h>
#include <iosfwd>

namespace Parma_Polyhedra_Library {

typedef Checked_Number<mpq_class, Extended_Number_Policy> ERational;

}

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns <CODE>true</CODE> if and only if \p x is less than \p y.
/*! \relates Boundary */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
bool operator<(const Boundary& x, const Boundary& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns <CODE>true</CODE> if and only if \p x is greater than \p y.
/*! \relates Boundary */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
bool operator>(const Boundary& x, const Boundary& y);

} // namespace Parma_Polyhedra_Library


#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! An extended rational bound of an interval.
/*! \ingroup PPL_CXX_interface
  An object of class Boundary represents either an upper or a lower
  bound of an interval over the set of extended rational numbers.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
class Parma_Polyhedra_Library::Boundary {
protected:
  //! Kinds of bounds.
  enum Flag {
    //! An open upper bound.
    NEG = -1,
    //! A closed (lower or upper) bound.
    ZERO = 0,
    //! An open lower bound.
    POS = 1
  };

  //! The extended rational value of the bound.
  ERational value;
  //! The kind of the bound.
  Flag flag;

  //! Builds a bound of kind \p f and having value \p v.
  Boundary(const ERational& v, Flag f);

  friend bool
  Parma_Polyhedra_Library::operator<(const Boundary& x, const Boundary& y);
  friend bool
  Parma_Polyhedra_Library::operator>(const Boundary& x, const Boundary& y);

public:
  //! Returns <CODE>true</CODE> if and only if \p *this is a closed bound.
  bool is_closed() const;

  //! Returns a const reference to the value of the bound.
  const ERational& bound() const;

  //! Returns a reference to the value of the bound.
  ERational& bound();
};


#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! The lower bound of an extended rational interval.
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
class Parma_Polyhedra_Library::LBoundary : public Boundary {
public:
  //! Kinds of lower bounds.
  enum Open_Closed {
    //! An open lower bound.
    OPEN = Boundary::POS,
    //! A closed lower bound.
    CLOSED = Boundary::ZERO
  };

  //! Builds a lower bound of kind \p f and having value \p v.
  LBoundary(const ERational& v, Open_Closed f);

  //! Checks if all the invariants are satisfied.
  bool OK() const;
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! The upper bound of an extended rational interval.
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
class Parma_Polyhedra_Library::UBoundary : public Boundary {
public:
  //! Kinds of upper bounds.
  enum Open_Closed {
    //! An open upper bound.
    OPEN = Boundary::NEG,
    //! A closed upper bound.
    CLOSED = Boundary::ZERO
  };

  //! Builds an upper bound of kind \p f and having value \p v.
  UBoundary(const ERational& v, Open_Closed f);

  //! Checks if all the invariants are satisfied.
  bool OK() const;
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A interval over the set of rational numbers.
/*! \ingroup PPL_CXX_interface
  An object of class Interval represents a closed/half-closed/open
  interval over the set of rational numbers \f$\Qset\f$.

  Note that, even though the implementation is capable to represent
  any interval on the set of <EM>extended</EM> rational numbers,
  the available public methods only allows for the construction
  and manipulation of intervals over \f$\Qset\f$.
  Namely, it is not possible to create a non-empty interval having
  a <EM>closed</EM> bound whose value is \f$-\infty\f$ or \f$+\infty\f$.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS

class Parma_Polyhedra_Library::Interval {
public:
  //! Constructs the universe interval \f$(-\infty, +\infty) = \Qset\f$.
  Interval();

  //! Returns <CODE>true</CODE> if and only if \p *this is empty.
  bool is_empty() const;

  //! Returns a const reference to the interval's lower bound.
  const LBoundary& lower_bound() const;

  //! Returns a reference to the interval's lower bound.
  LBoundary& lower_bound();

  //! Returns a const reference to the interval's upper bound.
  const UBoundary& upper_bound() const;

  //! Returns a reference to the interval's upper bound.
  UBoundary& upper_bound();

  /*! \brief
    Raises the interval's lower bound, if \p new_lower is higher
    than the current one.
  */
  void raise_lower_bound(LBoundary new_lower);

  /*! \brief
    Lowers the interval's upper bound, if \p new_upper is lower
    than the current one.
  */
  void lower_upper_bound(UBoundary new_upper);

  //! Turns \p *this into the empty interval.
  void set_empty();

  //! Checks if all the invariants are satisfied.
  bool OK() const;

private:
  //! The interval's lower bound.
  LBoundary lower;

  //! The interval's upper bound.
  UBoundary upper;
};

// Automatically generated from PPL source file ../src/Interval.inlines.hh line 1
/* Inline functions for the Interval class and its constituents.
*/


#include <cassert>
// Automatically generated from PPL source file ../src/Interval.inlines.hh line 29

namespace Parma_Polyhedra_Library {

inline
Boundary::Boundary(const ERational& v, Flag f)
  : value(v), flag(f) {
}

inline bool
Boundary::is_closed() const {
  return flag == ZERO;
}

inline const ERational&
Boundary::bound() const {
  return value;
}

inline ERational&
Boundary::bound() {
  return value;
}

inline
LBoundary::LBoundary(const ERational& v, Open_Closed f)
  : Boundary(v, f == CLOSED ? ZERO : POS) {
}

inline
UBoundary::UBoundary(const ERational& v, Open_Closed f)
  : Boundary(v, f == CLOSED ? ZERO : NEG) {
}

/*! \relates Boundary */
inline bool
operator<(const Boundary& x, const Boundary& y) {
  return x.value < y.value ||
    (x.value == y.value && x.flag < y.flag);
}

/*! \relates Boundary */
inline bool
operator>(const Boundary& x, const Boundary& y) {
  return y < x;
}

inline
Interval::Interval()
  : lower(ERational(MINUS_INFINITY), LBoundary::OPEN),
    upper(ERational(PLUS_INFINITY), UBoundary::OPEN) {
}

inline bool
Interval::is_empty() const {
  return lower > upper;
}

inline const LBoundary&
Interval::lower_bound() const {
  return lower;
}

inline LBoundary&
Interval::lower_bound() {
  return lower;
}

inline const UBoundary&
Interval::upper_bound() const {
  return upper;
}

inline UBoundary&
Interval::upper_bound() {
  return upper;
}

inline void
Interval::raise_lower_bound(LBoundary new_lower) {
  if (new_lower > lower)
    lower = new_lower;
}

inline void
Interval::lower_upper_bound(UBoundary new_upper) {
  if (new_upper < upper)
    upper = new_upper;
}

inline void
Interval::set_empty() {
  lower = LBoundary(ERational(PLUS_INFINITY), LBoundary::OPEN);
  upper = UBoundary(ERational(MINUS_INFINITY), UBoundary::OPEN);
  assert(is_empty());
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Interval.defs.hh line 203

// Automatically generated from PPL source file ../src/Bounding_Box.defs.hh line 1
/* Bounding_Box class declaration.
*/


// Automatically generated from PPL source file ../src/Constraint_System.defs.hh line 1
/* Constraint_System class declaration.
*/


// Automatically generated from PPL source file ../src/Linear_System.defs.hh line 1
/* Linear_System class declaration.
*/


// Automatically generated from PPL source file ../src/Matrix.defs.hh line 1
/* Matrix class declaration.
*/


// Automatically generated from PPL source file ../src/Row.defs.hh line 1
/* Row class declaration.
*/


// Automatically generated from PPL source file ../src/Row.defs.hh line 29
#include <vector>
#include <limits>

#ifndef EXTRA_ROW_DEBUG
#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*!
  \brief
  Enables extra debugging information for class Row.

  \ingroup PPL_CXX_interface
  When <CODE>EXTRA_ROW_DEBUG</CODE> evaluates to <CODE>true</CODE>,
  each instance of the class Row carries its own capacity; this enables
  extra consistency checks to be performed.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
#define EXTRA_ROW_DEBUG 0
#endif

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! The handler of the actual Row implementation.
/*! \ingroup PPL_CXX_interface
  Exception-safety is the only responsibility of this class: it has
  to ensure that its \p impl member is correctly deallocated.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
class Parma_Polyhedra_Library::Row_Impl_Handler {
public:
  //! Default constructor.
  Row_Impl_Handler();

  //! Destructor.
  ~Row_Impl_Handler();

  class Impl;

  //! A pointer to the actual implementation.
  Impl* impl;

#if EXTRA_ROW_DEBUG
  //! The capacity of \p impl (only available during debugging).
  dimension_type capacity_;
#endif // EXTRA_ROW_DEBUG

private:
  //! Private and unimplemented: copy construction is not allowed.
  Row_Impl_Handler(const Row_Impl_Handler&);

  //! Private and unimplemented: copy assignment is not allowed.
  Row_Impl_Handler& operator=(const Row_Impl_Handler&);
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A finite sequence of coefficients.
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
class Parma_Polyhedra_Library::Row : private Row_Impl_Handler {
public:
#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Wrapper class to represent a set of flags with bits in a native
    unsigned integral type.
    \ingroup PPL_CXX_interface
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  class Flags {
  public:
    //! Constructs an object with all the flags unset.
    Flags();

    //! Returns <CODE>true</CODE> if and only if \p *this and \p y are equal.
    bool operator==(const Flags& y) const;

    /*! \brief
      Returns <CODE>true</CODE> if and only if \p *this and \p y
      are different.
    */
    bool operator!=(const Flags& y) const;

    PPL_OUTPUT_DECLARATIONS;

    //! Uses the ASCII Flags representation from \p s to recreate *this.
    /*!
      Returns <CODE>true</CODE> if successful, <CODE>false</CODE>
      otherwise.  The ASCII representation is as output by
      \ref Parma_Polyhedra_Library::Row::Flags::ascii_dump.
    */
    bool ascii_load(std::istream& s);

  protected:
    //! A native integral type holding the bits that encode the flags.
    typedef unsigned int base_type;

    //! Index of the first bit derived classes can use.
    static const unsigned first_free_bit = 0;

    //! Total number of bits that can be stored.
    static const unsigned num_bits = std::numeric_limits<base_type>::digits;

    //! Constructs an object with flags set as in \p n.
    explicit Flags(base_type n);

    //! Returns the integer encoding \p *this.
    base_type get_bits() const;

    //! Sets the bits in \p mask.
    void set_bits(base_type mask);

    //! Resets the bits in \p mask.
    void reset_bits(base_type mask);

    /*! \brief
      Returns <CODE>true</CODE> if and only if all the bits
      in \p mask are set.
    */
    bool test_bits(base_type mask) const;

  private:
    //! The integer encoding \p *this.
    base_type bits;

    friend class Row;
  };

  //! Pre-constructs a row: construction must be completed by construct().
  Row();

  //! \name Post-constructors
  //@{
  //! Constructs properly a default-constructed element.
  /*!
    Builds a row with size and capacity \p sz and flags \p f.
  */
  void construct(dimension_type sz, Flags f);

  //! Constructs properly a default-constructed element.
  /*!
    \param sz
    The size of the row that will be constructed;

    \param capacity
    The capacity of the row that will be constructed;

    \param f
    Flags for the row that will be constructed.

    The row that is constructed has storage for \p capacity elements,
    \p sz of which are default-constructed now.
    The row flags are set to \p f.
  */
  void construct(dimension_type sz, dimension_type capacity, Flags f);
  //@} // Post-constructors

  //! Tight constructor: resizing may require reallocation.
  /*!
    Constructs a row with size and capacity \p sz, and flags \p f.
  */
  Row(dimension_type sz, Flags f);

  //! Sizing constructor with capacity.
  /*!
    \param sz
    The size of the row that will be constructed;

    \param capacity
    The capacity of the row that will be constructed;

    \param f
    Flags for the row that will be constructed.

    The row that is constructed has storage for \p capacity elements,
    \p sz of which are default-constructed now.
    The row flags are set to \p f.
  */
  Row(dimension_type sz, dimension_type capacity, Flags f);

  //! Ordinary copy constructor.
  Row(const Row& y);

  //! Copy constructor with specified capacity.
  /*!
    It is assumed that \p capacity is greater than or equal to
    the size of \p y.
  */
  Row(const Row& y, dimension_type capacity);

  //! Copy constructor with specified size and capacity.
  /*!
    It is assumed that \p sz is greater than or equal to the size of \p y
    and, of course, that \p sz is less than or equal to \p capacity.
  */
  Row(const Row& y, dimension_type sz, dimension_type capacity);

  //! Destructor.
  ~Row();

  //! Assignment operator.
  Row& operator=(const Row& y);

  //! Swaps \p *this with \p y.
  void swap(Row& y);

  //! Assigns the implementation of \p y to \p *this.
  /*!
    To be used with extra care, since it may easily cause memory leaks
    or undefined behavior.
  */
  void assign(Row& y);

  /*! \brief
    Allocates memory for a default constructed Row object, setting
    flags to \p f and allowing for \p capacity coefficients at most.

    It is assumed that no allocation has been performed before
    (otherwise, a memory leak will occur).
    After execution, the size of the Row object is zero.
  */
  void allocate(dimension_type capacity, Flags f);

  //! Expands the row to size \p new_size.
  /*!
    Adds new positions to the implementation of the row
    obtaining a new row with size \p new_size.
    It is assumed that \p new_size is between the current size
    and capacity of the row.
  */
  void expand_within_capacity(dimension_type new_size);

  //! Shrinks the row by erasing elements at the end.
  /*!
    Destroys elements of the row implementation
    from position \p new_size to the end.
    It is assumed that \p new_size is not greater than the current size.
  */
  void shrink(dimension_type new_size);

  //! Returns a const reference to the flags of \p *this.
  const Flags& flags() const;

  //! Returns a non-const reference to the flags of \p *this.
  Flags& flags();

  //! Returns the size() of the largest possible Row.
  static dimension_type max_size();

  //! Gives the number of coefficients currently in use.
  dimension_type size() const;

  //! \name Subscript operators
  //@{
  //! Returns a reference to the element of the row indexed by \p k.
  Coefficient& operator[](dimension_type k);

  //! Returns a constant reference to the element of the row indexed by \p k.
  Coefficient_traits::const_reference operator[](dimension_type k) const;
  //@} // Subscript operators

  //! Normalizes the modulo of coefficients so that they are mutually prime.
  /*!
    Computes the Greatest Common Divisor (GCD) among the elements of
    the row and normalizes them by the GCD itself.
  */
  void normalize();

  PPL_OUTPUT_DECLARATIONS;

  //! Uses the ASCII Row representation at \p s to recreate *this.
  /*!
    Returns <CODE>true</CODE> if successful, <CODE>false</CODE>
    otherwise.  The ASCII representation is as output by \ref ascii_dump.
  */
  bool ascii_load(std::istream& s);

  /*! \brief
    Returns a lower bound to the total size in bytes of the memory
    occupied by \p *this.
  */
  memory_size_type total_memory_in_bytes() const;

  /*! \brief
    Returns a lower bound to the size in bytes of the memory
    managed by \p *this.
  */
  memory_size_type external_memory_in_bytes() const;

  /*! \brief
    Returns the total size in bytes of the memory occupied by \p *this,
    provided the capacity of \p *this is given by \p capacity.
  */
  memory_size_type total_memory_in_bytes(dimension_type capacity) const;

  /*! \brief
    Returns the size in bytes of the memory managed by \p *this,
    provided the capacity of \p *this is given by \p capacity.
  */
  memory_size_type external_memory_in_bytes(dimension_type capacity) const;

  //! Checks if all the invariants are satisfied.
  bool OK(dimension_type row_size, dimension_type row_capacity) const;

private:
  //! Exception-safe copy construction mechanism for coefficients.
  void copy_construct_coefficients(const Row& y);

#if EXTRA_ROW_DEBUG
  //! Returns the capacity of the row (only available during debugging).
  dimension_type capacity() const;
#endif // EXTRA_ROW_DEBUG
};

namespace Parma_Polyhedra_Library {

//! Returns <CODE>true</CODE> if and only if \p x and \p y are equal.
/*! \relates Row */
bool operator==(const Row& x, const Row& y);

//! Returns <CODE>true</CODE> if and only if \p x and \p y are different.
/*! \relates Row */
bool operator!=(const Row& x, const Row& y);

} // namespace Parma_Polyhedra_Library


namespace std {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Row */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
void swap(Parma_Polyhedra_Library::Row& x,
	  Parma_Polyhedra_Library::Row& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Specializes <CODE>std::iter_swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Row */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
void iter_swap(std::vector<Parma_Polyhedra_Library::Row>::iterator x,
	       std::vector<Parma_Polyhedra_Library::Row>::iterator y);

} // namespace std


#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! The actual implementation of a Row object.
/*! \ingroup PPL_CXX_interface
  The class Row_Impl_Handler::Impl provides the implementation of Row
  objects and, in particular, of the corresponding memory allocation
  functions.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
class Parma_Polyhedra_Library::Row_Impl_Handler::Impl {
public:
  //! \name Custom allocator and deallocator
  //@{

  /*! \brief
    Allocates a chunk of memory able to contain \p capacity Coefficient objects
    beyond the specified \p fixed_size and returns a pointer to the new
    allocated memory.
  */
  static void* operator new(size_t fixed_size, dimension_type capacity);

  //! Uses the standard delete operator to free the memory \p p points to.
  static void operator delete(void* p);

  /*! \brief
    Placement version:
    uses the standard operator delete to free the memory \p p points to.
  */
  static void operator delete(void* p, dimension_type capacity);
  //@} // Custom allocator and deallocator

  //! Constructor.
  Impl(Row::Flags f);

  //! Destructor.
  /*!
    Uses <CODE>shrink()</CODE> method with argument \f$0\f$
    to delete all the row elements.
  */
  ~Impl();

  //! Expands the row to size \p new_size.
  /*!
    It is assumed that \p new_size is between the current size and capacity.
  */
  void expand_within_capacity(dimension_type new_size);

  //! Shrinks the row by erasing elements at the end.
  /*!
    It is assumed that \p new_size is not greater than the current size.
  */
  void shrink(dimension_type new_size);

  //! Exception-safe copy construction mechanism for coefficients.
  void copy_construct_coefficients(const Impl& y);

  //! Returns the size() of the largest possible Impl.
  static dimension_type max_size();

  //! \name Flags accessors
  //@{
  //! Returns a const reference to the flags of \p *this.
  const Row::Flags& flags() const;

  //! Returns a non-const reference to the flags of \p *this.
  Row::Flags& flags();
  //@} // Flags accessors

  //! \name Size accessors
  //@{
  //! Returns the actual size of \p this.
  dimension_type size() const;

  //! Sets to \p new_size the actual size of \p *this.
  void set_size(dimension_type new_size);

  //! Increment the size of \p *this by 1.
  void bump_size();
  //@} // Size accessors

  //! \name Subscript operators
  //@{
  //! Returns a reference to the element of \p *this indexed by \p k.
  Coefficient& operator[](dimension_type k);

  //! Returns a constant reference to the element of \p *this indexed by \p k.
  Coefficient_traits::const_reference operator[](dimension_type k) const;
  //@} // Subscript operators

  /*! \brief
    Returns a lower bound to the total size in bytes of the memory
    occupied by \p *this.
  */
  memory_size_type total_memory_in_bytes() const;

  //! Returns the total size in bytes of the memory occupied by \p *this.
  memory_size_type total_memory_in_bytes(dimension_type capacity) const;

  //! Returns the size in bytes of the memory managed by \p *this.
  memory_size_type external_memory_in_bytes() const;

private:
  //! The number of coefficients in the row.
  dimension_type size_;

  //! The flags of this row.
  Row::Flags flags_;

  //! The vector of coefficients.
  Coefficient vec_[
#if !CXX_SUPPORTS_FLEXIBLE_ARRAYS
	       1
#endif
  ];

  //! Private and unimplemented: default construction is not allowed.
  Impl();

  //! Private and unimplemented: copy construction is not allowed.
  Impl(const Impl& y);

  //! Private and unimplemented: assignment is not allowed.
  Impl& operator=(const Impl&);
};

// Automatically generated from PPL source file ../src/Row.inlines.hh line 1
/* Row class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/Row.inlines.hh line 27
#include <cassert>
#include <algorithm>

namespace Parma_Polyhedra_Library {

inline
Row::Flags::Flags()
  : bits(0) {
}

inline
Row::Flags::Flags(base_type n)
  : bits(n) {
}

inline Row::Flags::base_type
Row::Flags::get_bits() const {
  return bits;
}

inline void
Row::Flags::set_bits(const base_type mask) {
  bits |= mask;
}

inline void
Row::Flags::reset_bits(const base_type mask) {
  bits &= ~mask;
}

inline bool
Row::Flags::test_bits(const base_type mask) const {
  return (bits & mask) == mask;
}

inline bool
Row::Flags::operator==(const Flags& y) const {
  base_type mask = low_bits_mask<base_type>(first_free_bit);
  return (get_bits() & mask) == (y.get_bits() & mask);
}

inline bool
Row::Flags::operator!=(const Flags& y) const {
  return !operator==(y);
}

inline void*
Row_Impl_Handler::Impl::operator new(const size_t fixed_size,
				     const dimension_type capacity) {
#if CXX_SUPPORTS_FLEXIBLE_ARRAYS
  return ::operator new(fixed_size + capacity*sizeof(Coefficient));
#else
  assert(capacity >= 1);
  return ::operator new(fixed_size + (capacity-1)*sizeof(Coefficient));
#endif
}

inline void
Row_Impl_Handler::Impl::operator delete(void* p) {
  ::operator delete(p);
}

inline void
Row_Impl_Handler::Impl::operator delete(void* p, dimension_type) {
  ::operator delete(p);
}

inline dimension_type
Row_Impl_Handler::Impl::max_size() {
  return size_t(-1)/sizeof(Coefficient);
}

inline dimension_type
Row_Impl_Handler::Impl::size() const {
  return size_;
}

inline void
Row_Impl_Handler::Impl::set_size(const dimension_type new_size) {
  size_ = new_size;
}

inline void
Row_Impl_Handler::Impl::bump_size() {
  ++size_;
}

inline
Row_Impl_Handler::Impl::Impl(const Row::Flags f)
  : size_(0), flags_(f) {
}

inline
Row_Impl_Handler::Impl::~Impl() {
  shrink(0);
}

inline const Row::Flags&
Row_Impl_Handler::Impl::flags() const {
  return flags_;
}

inline Row::Flags&
Row_Impl_Handler::Impl::flags() {
  return flags_;
}

inline Coefficient&
Row_Impl_Handler::Impl::operator[](const dimension_type k) {
  assert(k < size());
  return vec_[k];
}

inline Coefficient_traits::const_reference
Row_Impl_Handler::Impl::operator[](const dimension_type k) const {
  assert(k < size());
  return vec_[k];
}

inline memory_size_type
Row_Impl_Handler::Impl::total_memory_in_bytes(dimension_type capacity) const {
  return
    sizeof(*this)
    + capacity*sizeof(Coefficient)
#if !CXX_SUPPORTS_FLEXIBLE_ARRAYS
    - 1*sizeof(Coefficient)
#endif
    + external_memory_in_bytes();
}

inline memory_size_type
Row_Impl_Handler::Impl::total_memory_in_bytes() const {
  // In general, this is a lower bound, as the capacity of *this
  // may be strictly greater than `size_'
  return total_memory_in_bytes(size_);
}

inline dimension_type
Row::max_size() {
  return Impl::max_size();
}

inline dimension_type
Row::size() const {
  return impl->size();
}

inline const Row::Flags&
Row::flags() const {
  return impl->flags();
}

inline Row::Flags&
Row::flags() {
  return impl->flags();
}

#if EXTRA_ROW_DEBUG
inline dimension_type
Row::capacity() const {
  return capacity_;
}
#endif

inline
Row_Impl_Handler::Row_Impl_Handler()
  : impl(0) {
#if EXTRA_ROW_DEBUG
  capacity_ = 0;
#endif
}

inline
Row_Impl_Handler::~Row_Impl_Handler() {
  delete impl;
}

inline
Row::Row()
  : Row_Impl_Handler() {
}

inline void
Row::allocate(
#if CXX_SUPPORTS_FLEXIBLE_ARRAYS
	       const
#endif
	       dimension_type capacity,
	       const Flags f) {
  assert(capacity <= max_size());
#if !CXX_SUPPORTS_FLEXIBLE_ARRAYS
  if (capacity == 0)
    ++capacity;
#endif
  assert(impl == 0);
  impl = new (capacity) Impl(f);
#if EXTRA_ROW_DEBUG
  assert(capacity_ == 0);
  capacity_ = capacity;
#endif
}

inline void
Row::expand_within_capacity(const dimension_type new_size) {
  assert(impl);
#if EXTRA_ROW_DEBUG
  assert(new_size <= capacity_);
#endif
  impl->expand_within_capacity(new_size);
}

inline void
Row::copy_construct_coefficients(const Row& y) {
  assert(impl && y.impl);
#if EXTRA_ROW_DEBUG
  assert(y.size() <= capacity_);
#endif
  impl->copy_construct_coefficients(*(y.impl));
}

inline void
Row::construct(const dimension_type sz,
	       const dimension_type capacity,
	       const Flags f) {
  assert(sz <= capacity && capacity <= max_size());
  allocate(capacity, f);
  expand_within_capacity(sz);
}

inline void
Row::construct(const dimension_type sz, const Flags f) {
  construct(sz, sz, f);
}

inline
Row::Row(const dimension_type sz,
	 const dimension_type capacity,
	 const Flags f)
  : Row_Impl_Handler() {
  construct(sz, capacity, f);
}

inline
Row::Row(const dimension_type sz, const Flags f)
  : Row_Impl_Handler() {
  construct(sz, f);
}

inline
Row::Row(const Row& y)
  : Row_Impl_Handler() {
  if (y.impl) {
    allocate(compute_capacity(y.size(), max_size()), y.flags());
    copy_construct_coefficients(y);
  }
}

inline
Row::Row(const Row& y,
	 const dimension_type capacity)
  : Row_Impl_Handler() {
  assert(y.impl);
  assert(y.size() <= capacity && capacity <= max_size());
  allocate(capacity, y.flags());
  copy_construct_coefficients(y);
}

inline
Row::Row(const Row& y,
	 const dimension_type sz,
	 const dimension_type capacity)
  : Row_Impl_Handler() {
  assert(y.impl);
  assert(y.size() <= sz && sz <= capacity && capacity <= max_size());
  allocate(capacity, y.flags());
  copy_construct_coefficients(y);
  expand_within_capacity(sz);
}

inline
Row::~Row() {
}

inline void
Row::shrink(const dimension_type new_size) {
  assert(impl);
  impl->shrink(new_size);
}

inline void
Row::swap(Row& y) {
  std::swap(impl, y.impl);
#if EXTRA_ROW_DEBUG
  std::swap(capacity_, y.capacity_);
#endif
}

inline void
Row::assign(Row& y) {
  impl = y.impl;
#if EXTRA_ROW_DEBUG
  capacity_ = y.capacity_;
#endif
}

inline Row&
Row::operator=(const Row& y) {
  // Copy-construct `tmp' from `y'.
  Row tmp(y);
  // Swap the implementation of `*this' with the one of `tmp'.
  swap(tmp);
  // Now `tmp' goes out of scope, so the old `*this' will be destroyed.
  return *this;
}

inline Coefficient&
Row::operator[](const dimension_type k) {
  assert(impl);
  return (*impl)[k];
}

inline Coefficient_traits::const_reference
Row::operator[](const dimension_type k) const {
  assert(impl);
  return (*impl)[k];
}

inline memory_size_type
Row::external_memory_in_bytes(dimension_type capacity) const {
  return impl->total_memory_in_bytes(capacity);
}

inline memory_size_type
Row::total_memory_in_bytes(dimension_type capacity) const {
  return sizeof(*this) + external_memory_in_bytes(capacity);
}

inline memory_size_type
Row::external_memory_in_bytes() const {
#if EXTRA_ROW_DEBUG
  return impl->total_memory_in_bytes(capacity_);
#else
  return impl->total_memory_in_bytes();
#endif
}

inline memory_size_type
Row::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

/*! \relates Row */
inline bool
operator!=(const Row& x, const Row& y) {
  return !(x == y);
}

} // namespace Parma_Polyhedra_Library


namespace std {

/*! \relates Parma_Polyhedra_Library::Row */
inline void
swap(Parma_Polyhedra_Library::Row& x, Parma_Polyhedra_Library::Row& y) {
  x.swap(y);
}

/*! \relates Parma_Polyhedra_Library::Row */
inline void
iter_swap(std::vector<Parma_Polyhedra_Library::Row>::iterator x,
	  std::vector<Parma_Polyhedra_Library::Row>::iterator y) {
  swap(*x, *y);
}

} // namespace std

// Automatically generated from PPL source file ../src/Row.defs.hh line 495

// Automatically generated from PPL source file ../src/Matrix.defs.hh line 31
#include <vector>
#include <cstddef>

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A 2-dimensional matrix of coefficients.
/*! \ingroup PPL_CXX_interface
  A Matrix object is a sequence of Row objects and is characterized
  by the matrix dimensions (the number of rows and columns).
  All the rows in a matrix, besides having the same size (corresponding
  to the number of columns of the matrix), are also bound to have the
  same capacity.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS

class Parma_Polyhedra_Library::Matrix {
public:
  //! Returns the maximum number of rows of a Matrix.
  static dimension_type max_num_rows();

  //! Returns the maximum number of columns of a Matrix.
  static dimension_type max_num_columns();

  //! Builds an empty matrix.
  /*!
    Rows' size and capacity are initialized to \f$0\f$.
  */
  Matrix();

  //! Builds a zero matrix with specified dimensions and flags.
  /*!
    \param n_rows
    The number of rows of the matrix that will be created;

    \param n_columns
    The number of columns of the matrix that will be created.

    \param row_flags
    The flags used to build the rows of the matrix;
    by default, the rows will have all flags unset.
  */
  Matrix(dimension_type n_rows, dimension_type n_columns,
	 Row::Flags row_flags = Row::Flags());

  //! Copy-constructor.
  Matrix(const Matrix& y);

  //! Destructor.
  ~Matrix();

  //! Assignment operator.
  Matrix& operator=(const Matrix& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  //! An iterator over a matrix.
  /*! \ingroup PPL_CXX_interface
    A const_iterator is used to provide read-only access
    to each row contained in a Matrix object.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  class const_iterator {
  private:
    typedef std::vector<Row>::const_iterator Iter;
    //! The const iterator on the rows' vector \p rows.
    Iter i;

  public:
    typedef std::forward_iterator_tag iterator_category;
    typedef std::iterator_traits<Iter>::value_type value_type;
    typedef std::iterator_traits<Iter>::difference_type difference_type;
    typedef std::iterator_traits<Iter>::pointer pointer;
    typedef std::iterator_traits<Iter>::reference reference;

    //! Default constructor.
    const_iterator();

    /*! \brief
      Builds a const iterator on the matrix starting from
      an iterator \p b on the elements of the vector \p rows.
    */
    explicit const_iterator(const Iter& b);

    //! Ordinary copy-constructor.
    const_iterator(const const_iterator& y);

    //! Assignment operator.
    const_iterator& operator=(const const_iterator& y);

    //! Dereference operator.
    reference operator*() const;

    //! Indirect member selector.
    pointer operator->() const;

    //! Prefix increment operator.
    const_iterator& operator++();

    //! Postfix increment operator.
    const_iterator operator++(int);

    /*! \brief
      Returns <CODE>true</CODE> if and only if
      \p *this and \p y are identical.
    */
    bool operator==(const const_iterator& y) const;

    /*! \brief
      Returns <CODE>true</CODE> if and only if
      \p *this and \p y are different.
    */
    bool operator!=(const const_iterator& y) const;
  };

  /*! \brief
    Returns the const_iterator pointing to the first row, if \p *this is
    not empty; otherwise, returns the past-the-end const_iterator.
  */
  const_iterator begin() const;

  //! Returns the past-the-end const_iterator.
  const_iterator end() const;

  // FIXME: the following section must become private.
protected:
  //! Contains the rows of the matrix.
  std::vector<Row> rows;

  //! Size of the initialized part of each row.
  dimension_type row_size;

  //! Capacity allocated for each row.
  dimension_type row_capacity;

public:
  //! Swaps \p *this with \p y.
  void swap(Matrix& y);

  //! Adds to the matrix \p n rows of zeroes with flags set to \p row_flags.
  /*!
    \param n
    The number of rows to be added: must be strictly positive.

    \param row_flags
    Flags for the newly added rows.

    Turns the \f$r \times c\f$ matrix \f$M\f$ into
    the \f$(r+n) \times c\f$ matrix \f$M \choose 0\f$.
    The matrix is expanded avoiding reallocation whenever possible.
  */
  void add_zero_rows(dimension_type n, Row::Flags row_flags);

  //! Adds \p n columns of zeroes to the matrix.
  /*!
    \param n
    The number of columns to be added: must be strictly positive.

    Turns the \f$r \times c\f$ matrix \f$M\f$ into
    the \f$r \times (c+n)\f$ matrix \f$(M \, 0)\f$.
    The matrix is expanded avoiding reallocation whenever possible.
  */
  void add_zero_columns(dimension_type n);

  //! Adds \p n rows and \p m columns of zeroes to the matrix.
  /*!
    \param n
    The number of rows to be added: must be strictly positive.

    \param m
    The number of columns to be added: must be strictly positive.

    \param row_flags
    Flags for the newly added rows.

    Turns the \f$r \times c\f$ matrix \f$M\f$ into
    the \f$(r+n) \times (c+m)\f$ matrix
    \f$\bigl({M \atop 0}{0 \atop 0}\bigr)\f$.
    The matrix is expanded avoiding reallocation whenever possible.
  */
  void add_zero_rows_and_columns(dimension_type n, dimension_type m,
				 Row::Flags row_flags);

  //! Adds a copy of the row \p y to the matrix.
  /*!
    \param y
    The row to be copied: it must have the same number of columns as
    the matrix.

    Turns the \f$r \times c\f$ matrix \f$M\f$ into
    the \f$(r+1) \times c\f$ matrix
    \f$\bigl({M \atop 0}\bigr)\f$.
    The matrix is expanded avoiding reallocation whenever possible.
  */
  void add_row(const Row& y);

  //! Adds the row \p y to the matrix.
  /*!
    \param y
    The row to be added: it must have the same size and capacity as \p
    *this.

    Turns the \f$r \times c\f$ matrix \f$M\f$ into
    the \f$(r+1) \times c\f$ matrix
    \f$\bigl({M \atop 0}\bigr)\f$.
    The matrix is expanded avoiding reallocation whenever possible.
  */
  void add_recycled_row(Row& y);

  //! Makes the matrix shrink by removing its \p n trailing columns.
  void remove_trailing_columns(dimension_type n);

  //! Resizes the matrix without worrying about the old contents.
  /*!
    \param new_n_rows
    The number of rows of the resized matrix;

    \param new_n_columns
    The number of columns of the resized matrix.

    \param row_flags
    The flags of the rows eventually added to the matrix.

    The matrix is expanded to the specified dimensions avoiding
    reallocation whenever possible.
    The contents of the original matrix is lost.
  */
  void resize_no_copy(dimension_type new_n_rows, dimension_type new_n_columns,
		      Row::Flags row_flags);

  //! Swaps the columns having indexes \p i and \p j.
  void swap_columns(dimension_type i,  dimension_type j);

  //! Permutes the columns of the matrix.
  /*
    \param cycles
    A vector representing the non-trivial cycles of the permutation
    according to which the columns must be rearranged.

    The \p cycles vector contains, one after the other, the
    non-trivial cycles (i.e., the cycles of length greater than one)
    of a permutation of non-zero column indexes.  Each cycle is
    terminated by zero.  For example, assuming the matrix has 6
    columns, the permutation \f$ \{ 1 \mapsto 3, 2 \mapsto 4,
    3 \mapsto 6, 4 \mapsto 2, 5 \mapsto 5, 6 \mapsto 1 \}\f$ can be
    represented by the non-trivial cycles \f$(1 3 6)(2 4)\f$ that, in
    turn can be represented by a vector of 6 elements containing 1, 3,
    6, 0, 2, 4, 0.
  */
  void permute_columns(const std::vector<dimension_type>& cycles);

  //! \name Accessors
  //@{

  //! Returns the number of columns of the matrix (i.e., the size of the rows).
  dimension_type num_columns() const;

  //! Returns the number of rows in the matrix.
  dimension_type num_rows() const;
  //@} // Accessors

  //! \name Subscript operators
  //@{
  //! Returns a reference to the \p k-th row of the matrix.
  Row& operator[](dimension_type k);

  //! Returns a constant reference to the \p k-th row of the matrix.
  const Row& operator[](dimension_type k) const;
  //@} // Subscript operators

  //! Clears the matrix deallocating all its rows.
  void clear();

  PPL_OUTPUT_DECLARATIONS;

  /*! \brief
    Loads from \p s an ASCII representation (as produced by \ref ascii_dump)
    and sets \p *this accordingly.  Returns <CODE>true</CODE> if successful,
    <CODE>false</CODE> otherwise.
  */
  bool ascii_load(std::istream& s);

  //! Returns the total size in bytes of the memory occupied by \p *this.
  memory_size_type total_memory_in_bytes() const;

  //! Returns the size in bytes of the memory managed by \p *this.
  memory_size_type external_memory_in_bytes() const;

  /*! \brief
    Erases from the matrix all the rows but those having
    an index less than \p first_to_erase.
  */
  void erase_to_end(dimension_type first_to_erase);

  //! Checks if all the invariants are satisfied.
  bool OK() const;
};

namespace std {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  //! Specializes <CODE>std::swap</CODE>.
  /*! \relates Parma_Polyhedra_Library::Matrix */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
void swap(Parma_Polyhedra_Library::Matrix& x,
	  Parma_Polyhedra_Library::Matrix& y);

} // namespace std


namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns <CODE>true</CODE> if and only if \p x and \p y are identical.
/*! \relates Matrix */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
bool operator==(const Matrix& x, const Matrix& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns <CODE>true</CODE> if and only if \p x and \p y are different.
/*! \relates Matrix */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
bool operator!=(const Matrix& x, const Matrix& y);

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Matrix.inlines.hh line 1
/* Matrix class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/Matrix.inlines.hh line 27
#include <algorithm>
#include <cassert>

namespace Parma_Polyhedra_Library {

inline dimension_type
Matrix::max_num_rows() {
  return std::vector<Row>().max_size();
}

inline dimension_type
Matrix::max_num_columns() {
  return Row::max_size();
}

inline memory_size_type
Matrix::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

inline
Matrix::const_iterator::const_iterator()
  : i(Iter()) {
}

inline
Matrix::const_iterator::const_iterator(const Iter& b)
  : i(b) {
}

inline
Matrix::const_iterator::const_iterator(const const_iterator& y)
  : i(y.i) {
}

inline Matrix::const_iterator&
Matrix::const_iterator::operator=(const const_iterator& y) {
  i = y.i;
  return *this;
}

inline Matrix::const_iterator::reference
Matrix::const_iterator::operator*() const {
  return *i;
}

inline Matrix::const_iterator::pointer
Matrix::const_iterator::operator->() const {
  return &*i;
}

inline Matrix::const_iterator&
Matrix::const_iterator::operator++() {
  ++i;
  return *this;
}

inline Matrix::const_iterator
Matrix::const_iterator::operator++(int) {
  return const_iterator(i++);
}

inline bool
Matrix::const_iterator::operator==(const const_iterator& y) const {
  return i == y.i;
}

inline bool
Matrix::const_iterator::operator!=(const const_iterator& y) const {
  return !operator==(y);
}

inline Matrix::const_iterator
Matrix::begin() const {
  return const_iterator(rows.begin());
}

inline Matrix::const_iterator
Matrix::end() const {
  return const_iterator(rows.end());
}

inline void
Matrix::swap(Matrix& y) {
  std::swap(rows, y.rows);
  std::swap(row_size, y.row_size);
  std::swap(row_capacity, y.row_capacity);
}

inline
Matrix::Matrix()
  : rows(),
    row_size(0),
    row_capacity(0) {
}

inline
Matrix::Matrix(const Matrix& y)
  : rows(y.rows),
    row_size(y.row_size),
    row_capacity(compute_capacity(y.row_size, max_num_columns())) {
}

inline
Matrix::~Matrix() {
}

inline Matrix&
Matrix::operator=(const Matrix& y) {
  // Without the following guard against auto-assignments we would
  // recompute the row capacity based on row size, possibly without
  // actually increasing the capacity of the rows.  This would lead to
  // an inconsistent state.
  if (this != &y) {
    // The following assignment may do nothing on auto-assignments...
    rows = y.rows;
    row_size = y.row_size;
    // ... hence the following assignment must not be done on
    // auto-assignments.
    row_capacity = compute_capacity(y.row_size, max_num_columns());
  }
  return *this;
}

inline void
Matrix::add_row(const Row& y) {
  Row new_row(y, row_capacity);
  add_recycled_row(new_row);
}

inline Row&
Matrix::operator[](const dimension_type k) {
  assert(k < rows.size());
  return rows[k];
}

inline const Row&
Matrix::operator[](const dimension_type k) const {
  assert(k < rows.size());
  return rows[k];
}

inline dimension_type
Matrix::num_rows() const {
  return rows.size();
}

inline dimension_type
Matrix::num_columns() const {
  return row_size;
}

/*! \relates Matrix */
inline bool
operator!=(const Matrix& x, const Matrix& y) {
  return !(x == y);
}

inline void
Matrix::erase_to_end(const dimension_type first_to_erase) {
  assert(first_to_erase <= rows.size());
  if (first_to_erase < rows.size())
    rows.erase(rows.begin() + first_to_erase, rows.end());
}

inline void
Matrix::clear() {
  // Clear `rows' and minimize its capacity.
  std::vector<Row>().swap(rows);
  row_size = 0;
  row_capacity = 0;
}

} // namespace Parma_Polyhedra_Library

namespace std {

/*! \relates Parma_Polyhedra_Library::Matrix */
inline void
swap(Parma_Polyhedra_Library::Matrix& x,
     Parma_Polyhedra_Library::Matrix& y) {
  x.swap(y);
}

} // namespace std

// Automatically generated from PPL source file ../src/Matrix.defs.hh line 355

// Automatically generated from PPL source file ../src/Topology.hh line 1


namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Kinds of polyhedra domains.
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
enum Topology {
  NECESSARILY_CLOSED = 0,
  NOT_NECESSARILY_CLOSED = 1
};

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Linear_Row.defs.hh line 1
/* Linear_Row class declaration.
*/


// Automatically generated from PPL source file ../src/Linear_Row.defs.hh line 33

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! The base class for linear expressions, constraints and generators.
/*! \ingroup PPL_CXX_interface
  The class Linear_Row allows us to build objects of the form
  \f$[b, a_0, \ldots, a_{d-1}]_{(t, k)}\f$,
  i.e., a finite sequence of coefficients subscripted by a pair of flags,
  which are both stored in a Linear_Row::Flags object.
  The flag \f$t \in \{ \mathrm{c}, \mathrm{nnc} \}\f$ represents
  the <EM>topology</EM> and
  the flag \f$k \in \{\mathord{=}, \mathord{\geq} \}\f$ represents
  the <EM>kind</EM> of the Linear_Row object.
  Note that, even though all the four possible combinations of topology
  and kind values will result in a legal Linear_Row::Flags object, some
  of these pose additional constraints on the values of the Linear_Row's
  coefficients.

  When \f$t = c\f$, we have the following cases
  (\f$d\f$ is the dimension of the vector space):
    - \f$[b, a_0, \ldots, a_{d-1}]_{(c,=)}\f$
      represents the equality constraint
      \f$\sum_{i=0}^{d-1} a_i x_i + b = 0\f$.
    - \f$[b, a_0, \ldots, a_{d-1}]_{(c,\geq)}\f$
      represents the non-strict inequality constraint
      \f$\sum_{i=0}^{d-1} a_i x_i + b \geq 0\f$.
    - \f$[0, a_0, \ldots, a_{d-1}]_{(c,=)}\f$
      represents the line of direction
      \f$\vect{l} = (a_0, \ldots, a_{d-1})^\transpose\f$.
    - \f$[0, a_0, \ldots, a_{d-1}]_{(c,\geq)}\f$
      represents the ray of direction
      \f$\vect{r} = (a_0, \ldots, a_{d-1})^\transpose\f$.
    - \f$[b, a_0, \ldots, a_{d-1}]_{(c,\geq)}\f$, with \f$b > 0\f$,
      represents the point
      \f$\vect{p} = (\frac{a_0}{b}, \ldots, \frac{a_{d-1}}{b})^\transpose\f$.

  When \f$t = \mathrm{nnc}\f$, the last coefficient of the Linear_Row is
  associated to the slack variable \f$\epsilon\f$, so that we have the
  following cases (\f$d\f$ is again the dimension of the vector space,
  but this time we have \f$d+2\f$ coefficients):
    - \f$[b, a_0, \ldots, a_{d-1}, 0]_{(\mathrm{nnc},=)}\f$
      represents the equality constraint
      \f$\sum_{i=0}^{d-1} a_i x_i + b = 0\f$.
    - \f$[b, a_0, \ldots, a_{d-1}, 0]_{(\mathrm{nnc},\geq)}\f$
      represents the non-strict inequality constraint
      \f$\sum_{i=0}^{d-1} a_i x_i + b \geq 0\f$.
    - \f$[b, a_0, \ldots, a_{d-1}, e]_{(\mathrm{nnc},\geq)}\f$,
      with \f$e < 0\f$, represents the strict inequality constraint
      \f$\sum_{i=0}^{d-1} a_i x_i + b > 0\f$.
    - \f$[0, a_0, \ldots, a_{d-1}, 0]_{(\mathrm{nnc},=)}\f$
      represents the line of direction
      \f$\vect{l} = (a_0, \ldots, a_{d-1})^\transpose\f$.
    - \f$[0, a_0, \ldots, a_{d-1}, 0]_{(\mathrm{nnc},\geq)}\f$
      represents the ray of direction
      \f$\vect{r} = (a_0, \ldots, a_{d-1})^\transpose\f$.
    - \f$[b, a_0, \ldots, a_{d-1}, e]_{(\mathrm{nnc},\geq)}\f$,
      with \f$b > 0\f$ and \f$e > 0\f$, represents the point
      \f$\vect{p} = (\frac{a_0}{b}, \ldots, \frac{a_{d-1}}{b})^\transpose\f$.
    - \f$[b, a_0, \ldots, a_{d-1}, 0]_{(\mathrm{nnc},\geq)}\f$,
      with \f$b > 0\f$, represents the closure point
      \f$\vect{c} = (\frac{a_0}{b}, \ldots, \frac{a_{d-1}}{b})^\transpose\f$.

  So, a Linear_Row can be both a constraint and a generator: it can be an
  equality, a strict or non-strict inequality, a line, a ray, a point
  or a closure point.

  The inhomogeneous term of a constraint can be zero or different from zero.

  Points and closure points must have a positive inhomogeneous term
  (which is used as a common divisor for all the other coefficients),
  lines and rays must have the inhomogeneous term equal to zero.
  If needed, the coefficients of points and closure points are negated
  at creation time so that they satisfy this invariant.
  The invariant is maintained because, when combining a point or closure
  point with another generator, we only consider positive combinations.

  The \f$\epsilon\f$ coefficient, when present, is negative for strict
  inequality constraints, positive for points and equal to zero in all
  the other cases.
  Note that the above description corresponds to the end-user, high-level
  view of a Linear_Row object. In the implementation, to allow for code reuse,
  it is sometimes useful to regard an \f$\mathrm{nnc}\f$-object on
  the vector space \f$\Rset^d\f$ as if it was a \f$\mathrm{c}\f$-object
  on the vector space \f$\Rset^{d+1}\f$, therefore interpreting the slack
  variable \f$\epsilon\f$ as an ordinary dimension of the vector space.

  A Linear_Row object implementing a Linear_Expression is always of the form
  \f$[0, a_0, \ldots, a_{d-1}]_{(c,=)}\f$, which represents the
  linear expression \f$\sum_{i=0}^{d-1} a_i x_i\f$.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS

class Parma_Polyhedra_Library::Linear_Row : public Row {
public:
  //! The possible kinds of Linear_Row objects.
  enum Kind {
    LINE_OR_EQUALITY = 0,
    RAY_OR_POINT_OR_INEQUALITY = 1
  };

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    The type of the object to which the coefficients refer to,
    encoding both topology and kind.

    \ingroup PPL_CXX_interface
    This combines the information about the topology (necessarily closed
    or not) and the kind (line/equality or ray/point/inequality)
    of a Linear_Row object.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  class Flags : public Row::Flags {
  public:
    //! Default constructor: builds an object where all flags are invalid.
    Flags();

    //! Builds an object corresponding to the topology \p t.
    explicit Flags(Topology t);

    //! Builds an object corresponding to the topology \p t and kind \p k.
    Flags(Topology t, Kind k);

    //! \name Testing and setting the type
    //@{
    Topology topology() const;
    bool is_necessarily_closed() const;
    bool is_not_necessarily_closed() const;
    bool is_line_or_equality() const;
    bool is_ray_or_point_or_inequality() const;

    void set_necessarily_closed();
    void set_not_necessarily_closed();
    void set_is_line_or_equality();
    void set_is_ray_or_point_or_inequality();
    //@} // Testing and setting the type

    //! Returns <CODE>true</CODE> if and only if \p *this and \p y are equal.
    bool operator==(const Flags& y) const;

    /*! \brief
      Returns <CODE>true</CODE> if and only if \p *this and \p y
      are different.
    */
    bool operator!=(const Flags& y) const;

    PPL_OUTPUT_DECLARATIONS;

    //! Uses the ASCII Flags representation from \p s to recreate *this.
    /*!
      Returns <CODE>true</CODE> if successful, <CODE>false</CODE>
      otherwise.  The ASCII representation is as output by \ref ascii_dump.
    */
    bool ascii_load(std::istream& s);

  private:
    //! Builds the type from a bit-mask.
    explicit Flags(base_type mask);

    //! \name The bits that are currently in use
    //@{
    // NB: ascii_load assumes that these are sequential.
    static const unsigned rpi_validity_bit
    = Row::Flags::first_free_bit + 0;
    static const unsigned rpi_bit
    = Row::Flags::first_free_bit + 1;
    static const unsigned nnc_validity_bit
    = Row::Flags::first_free_bit + 2;
    static const unsigned nnc_bit
    = Row::Flags::first_free_bit + 3;
    //@}

  protected:
    //! Index of the first bit derived classes can use.
    static const unsigned first_free_bit
    = Row::Flags::first_free_bit + 4;

    friend class Parma_Polyhedra_Library::Linear_Row;
  };

  //! Pre-constructs a row: construction must be completed by construct().
  Linear_Row();

  //! \name Post-constructors
  //@{
  //! Constructs properly a default-constructed element.
  /*!
    Builds a row with type \p t, size \p sz and minimum capacity.
  */
  void construct(dimension_type sz, Flags f);

  //! Constructs properly a default-constructed element.
  /*!
    \param sz
    The size of the row that will be constructed;

    \param capacity
    The minimum capacity of the row that will be constructed.

    \param f
    Flags for the row that will be constructed.

    The row that we are constructing has a minimum capacity, i.e., it
    can contain at least \p capacity elements, \p sz of which will be
    default-constructed now. The row flags are set to \p f.
  */
  void construct(dimension_type sz, dimension_type capacity, Flags f);
  //@} // Post-constructors

  //! Tight constructor: resizing will require reallocation.
  Linear_Row(dimension_type sz, Flags f);

  //! Sizing constructor with capacity.
  Linear_Row(dimension_type sz, dimension_type capacity, Flags f);

  //! Ordinary copy constructor.
  Linear_Row(const Linear_Row& y);

  //! Copy constructor with specified capacity.
  /*!
    It is assumed that \p capacity is greater than or equal to \p y size.
  */
  Linear_Row(const Linear_Row& y, dimension_type capacity);

  //! Copy constructor with specified size and capacity.
  /*!
    It is assumed that \p sz is greater than or equal to the size of \p y
    and, of course, that \p sz is less than or equal to \p capacity.
  */
  Linear_Row(const Linear_Row& y, dimension_type sz, dimension_type capacity);

  //! Destructor.
  ~Linear_Row();

  //! \name Flags inspection methods
  //@{
  //! Returns a const reference to the flags of \p *this.
  const Flags& flags() const;

  //! Returns a non-const reference to the flags of \p *this.
  Flags& flags();

  //! Returns the topological kind of \p *this.
  Topology topology() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if the topology
    of \p *this row is not necessarily closed.
  */
  bool is_not_necessarily_closed() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if the topology
    of \p *this row is necessarily closed.
  */
  bool is_necessarily_closed() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this row
    represents a line or an equality.
  */
  bool is_line_or_equality() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this row
    represents a ray, a point or an inequality.
  */
  bool is_ray_or_point_or_inequality() const;
  //@} // Flags inspection methods

  //! \name Flags coercion methods
  //@{
  //! Sets to \p NECESSARILY_CLOSED the topological kind of \p *this row.
  void set_necessarily_closed();

  //! Sets to \p NOT_NECESSARILY_CLOSED the topological kind of \p *this row.
  void set_not_necessarily_closed();

  //! Sets to \p LINE_OR_EQUALITY the kind of \p *this row.
  void set_is_line_or_equality();

  //! Sets to \p RAY_OR_POINT_OR_INEQUALITY the kind of \p *this row.
  void set_is_ray_or_point_or_inequality();
  //@} // Flags coercion methods

  //! Returns the maximum space dimension a Linear_Row can handle.
  static dimension_type max_space_dimension();

  //! Returns the dimension of the vector space enclosing \p *this.
  dimension_type space_dimension() const;

  //! Returns the inhomogeneous term.
  Coefficient_traits::const_reference inhomogeneous_term() const;

  //! Returns the coefficient \f$a_n\f$.
  Coefficient_traits::const_reference coefficient(dimension_type n) const;

  /*! \brief
    Normalizes the sign of the coefficients so that the first non-zero
    (homogeneous) coefficient of a line-or-equality is positive.
  */
  void sign_normalize();

  /*! \brief
    Strong normalization: ensures that different Linear_Row objects
    represent different hyperplanes or hyperspaces.

    Applies both Linear_Row::normalize() and Linear_Row::sign_normalize().
  */
  void strong_normalize();

  /*! \brief
    Returns <CODE>true</CODE> if and only if the coefficients are
    strongly normalized.
  */
  bool check_strong_normalized() const;

  //! Linearly combines \p *this with \p y so that <CODE>*this[k]</CODE> is 0.
  /*!
    \param y
    The Linear_Row that will be combined with \p *this object;

    \param k
    The position of \p *this that have to be \f$0\f$.

    Computes a linear combination of \p *this and \p y having
    the element of index \p k equal to \f$0\f$. Then it assigns
    the resulting Linear_Row to \p *this and normalizes it.
  */
  void linear_combine(const Linear_Row& y, dimension_type k);

  /*! \brief
    Returns <CODE>true</CODE> if and only if all the homogeneous
    terms of \p *this are \f$0\f$.
  */
  bool all_homogeneous_terms_are_zero() const;

  PPL_OUTPUT_DECLARATIONS;

  //! Uses the ASCII Linear_Row representation from \p s to recreate *this.
  /*!
    Returns <CODE>true</CODE> if successful, <CODE>false</CODE>
    otherwise.  The ASCII representation is as output by \ref ascii_dump.
  */
  bool ascii_load(std::istream& s);

  //! Checks if all the invariants are satisfied.
  bool OK(dimension_type row_size, dimension_type row_capacity) const;

private:
  friend class Parma_Polyhedra_Library::Linear_Expression;
  friend class Parma_Polyhedra_Library::Constraint;
  friend class Parma_Polyhedra_Library::Generator;
};

namespace Parma_Polyhedra_Library {

//! Returns <CODE>true</CODE> if and only if \p x and \p y are equal.
/*! \relates Linear_Row */
bool operator==(const Linear_Row& x, const Linear_Row& y);

//! Returns <CODE>true</CODE> if and only if \p x and \p y are different.
/*! \relates Linear_Row */
bool operator!=(const Linear_Row& x, const Linear_Row& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! The basic comparison function.
/*! \relates Linear_Row
  \return
  The returned absolute value can be \f$0\f$, \f$1\f$ or \f$2\f$.

  \param x
  A row of coefficients;

  \param y
  Another row.

  Compares \p x and \p y, where \p x and \p y may be of different size,
  in which case the "missing" coefficients are assumed to be zero.
  The comparison is such that:
  -# equalities are smaller than inequalities;
  -# lines are smaller than points and rays;
  -# the ordering is lexicographic;
  -# the positions compared are, in decreasing order of significance,
     1, 2, ..., \p size(), 0;
  -# the result is negative, zero, or positive if x is smaller than,
     equal to, or greater than y, respectively;
  -# when \p x and \p y are different, the absolute value of the
     result is 1 if the difference is due to the coefficient in
     position 0; it is 2 otherwise.

  When \p x and \p y represent the hyper-planes associated
  to two equality or inequality constraints, the coefficient
  at 0 is the known term.
  In this case, the return value can be characterized as follows:
  - -2, if \p x is smaller than \p y and they are \e not parallel;
  - -1, if \p x is smaller than \p y and they \e are parallel;
  -  0, if \p x and y are equal;
  - +1, if \p y is smaller than \p x and they \e are parallel;
  - +2, if \p y is smaller than \p x and they are \e not parallel.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
int compare(const Linear_Row& x, const Linear_Row& y);

} // namespace Parma_Polyhedra_Library


namespace std {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Linear_Row */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
void swap(Parma_Polyhedra_Library::Linear_Row& x,
	  Parma_Polyhedra_Library::Linear_Row& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Specializes <CODE>std::iter_swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Linear_Row */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
void iter_swap(std::vector<Parma_Polyhedra_Library::Linear_Row>::iterator x,
	       std::vector<Parma_Polyhedra_Library::Linear_Row>::iterator y);

} // namespace std

// Automatically generated from PPL source file ../src/Linear_Row.inlines.hh line 1
/* Linear_Row class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/Linear_Row.inlines.hh line 27
#include <cassert>
#include <algorithm>

namespace Parma_Polyhedra_Library {

inline
Linear_Row::Flags::Flags()
  : Row::Flags() {
  // Note that the constructed type has its validity bit unset.
}

inline
Linear_Row::Flags::Flags(const Topology t)
  : Row::Flags(t << nnc_bit) {
#ifndef NDEBUG
  set_bits(1 << nnc_validity_bit);
#endif
}

inline
Linear_Row::Flags::Flags(const Topology t, const Kind k)
  : Row::Flags((k << rpi_bit) | (t << nnc_bit)) {
#ifndef NDEBUG
  set_bits((1 << rpi_validity_bit)
	   | (1 << nnc_validity_bit));
#endif
}

inline bool
Linear_Row::Flags::is_ray_or_point_or_inequality() const {
  assert(test_bits(1 << rpi_validity_bit));
  return test_bits(RAY_OR_POINT_OR_INEQUALITY << rpi_bit);
}

inline void
Linear_Row::Flags::set_is_ray_or_point_or_inequality() {
#ifndef NDEBUG
  set_bits(1 << rpi_validity_bit);
#endif
  set_bits(RAY_OR_POINT_OR_INEQUALITY << rpi_bit);
}

inline bool
Linear_Row::Flags::is_line_or_equality() const {
  assert(test_bits(1 << rpi_validity_bit));
  return !is_ray_or_point_or_inequality();
}

inline void
Linear_Row::Flags::set_is_line_or_equality() {
#ifndef NDEBUG
  set_bits(1 << rpi_validity_bit);
#endif
  reset_bits(RAY_OR_POINT_OR_INEQUALITY << rpi_bit);
}

inline bool
Linear_Row::Flags::is_not_necessarily_closed() const {
  assert(test_bits(1 << nnc_validity_bit));
  return test_bits(NOT_NECESSARILY_CLOSED << nnc_bit);
}

inline bool
Linear_Row::Flags::is_necessarily_closed() const {
  assert(test_bits(1 << nnc_validity_bit));
  return !is_not_necessarily_closed();
}

inline void
Linear_Row::Flags::set_not_necessarily_closed() {
#ifndef NDEBUG
  set_bits(1 << nnc_validity_bit);
#endif
  set_bits(NOT_NECESSARILY_CLOSED << nnc_bit);
}

inline void
Linear_Row::Flags::set_necessarily_closed() {
#ifndef NDEBUG
  set_bits(1 << nnc_validity_bit);
#endif
  reset_bits(NOT_NECESSARILY_CLOSED << nnc_bit);
}

inline Topology
Linear_Row::Flags::topology() const {
  return is_necessarily_closed() ? NECESSARILY_CLOSED : NOT_NECESSARILY_CLOSED;
}

inline bool
Linear_Row::Flags::operator==(const Flags& y) const {
  base_type mask = low_bits_mask<base_type>(first_free_bit);
  return (get_bits() & mask) == (y.get_bits() & mask);
}

inline bool
Linear_Row::Flags::operator!=(const Flags& y) const {
  return !operator==(y);
}

inline const Linear_Row::Flags&
Linear_Row::flags() const {
  return static_cast<const Flags&>(Row::flags());
}

inline Linear_Row::Flags&
Linear_Row::flags() {
  return static_cast<Flags&>(Row::flags());
}

inline bool
Linear_Row::is_necessarily_closed() const {
  return flags().is_necessarily_closed();
}

inline dimension_type
Linear_Row::max_space_dimension() {
  // The first coefficient holds the inhomogeneous term or the divisor.
  // In NNC rows, the last coefficient is for the epsilon dimension.
  return max_size() - 2;
}

inline dimension_type
Linear_Row::space_dimension() const {
  const dimension_type sz = size();
  return (sz == 0)
    ? 0
    : sz - (is_necessarily_closed() ? 1 : 2);
}

inline
Linear_Row::Linear_Row()
  : Row() {
}

inline void
Linear_Row::construct(const dimension_type sz, const dimension_type capacity,
		      const Flags f) {
  Row::construct(sz, capacity, f);
}

inline
Linear_Row::Linear_Row(const dimension_type sz, const dimension_type capacity,
		       const Flags f) {
  construct(sz, capacity, f);
}

inline void
Linear_Row::construct(const dimension_type sz, const Flags f) {
  construct(sz, sz, f);
}

inline
Linear_Row::Linear_Row(const dimension_type sz, const Flags f) {
  construct(sz, f);
}

inline
Linear_Row::Linear_Row(const Linear_Row& y)
  : Row(y) {
}

inline
Linear_Row::Linear_Row(const Linear_Row& y,
		       const dimension_type capacity)
  : Row(y, capacity) {
}

inline
Linear_Row::Linear_Row(const Linear_Row& y,
		       const dimension_type sz, const dimension_type capacity)
  : Row(y, sz, capacity) {
}

inline
Linear_Row::~Linear_Row() {
}

inline bool
Linear_Row::is_line_or_equality() const {
  return flags().is_line_or_equality();
}

inline bool
Linear_Row::is_ray_or_point_or_inequality() const {
  return flags().is_ray_or_point_or_inequality();
}

inline Topology
Linear_Row::topology() const {
  return flags().topology();
}

inline void
Linear_Row::set_is_line_or_equality() {
  flags().set_is_line_or_equality();
}

inline void
Linear_Row::set_is_ray_or_point_or_inequality() {
  flags().set_is_ray_or_point_or_inequality();
}

inline void
Linear_Row::set_necessarily_closed() {
  flags().set_necessarily_closed();
}

inline void
Linear_Row::set_not_necessarily_closed() {
  flags().set_not_necessarily_closed();
}

inline Coefficient_traits::const_reference
Linear_Row::inhomogeneous_term() const {
  return (*this)[0];
}

inline Coefficient_traits::const_reference
Linear_Row::coefficient(const dimension_type k) const {
  return (*this)[k+1];
}

inline void
Linear_Row::strong_normalize() {
  normalize();
  sign_normalize();
}

/*! \relates Linear_Row */
inline bool
operator==(const Linear_Row& x, const Linear_Row& y) {
  return x.flags() == y.flags()
    && static_cast<const Row&>(x) == static_cast<const Row&>(y);
}

/*! \relates Linear_Row */
inline bool
operator!=(const Linear_Row& x, const Linear_Row& y) {
  return !(x == y);
}

} // namespace Parma_Polyhedra_Library


namespace std {

/*! \relates Parma_Polyhedra_Library::Linear_Row */
inline void
swap(Parma_Polyhedra_Library::Linear_Row& x,
     Parma_Polyhedra_Library::Linear_Row& y) {
  x.swap(y);
}

/*! \relates Parma_Polyhedra_Library::Linear_Row */
inline void
iter_swap(std::vector<Parma_Polyhedra_Library::Linear_Row>::iterator x,
	  std::vector<Parma_Polyhedra_Library::Linear_Row>::iterator y) {
  swap(*x, *y);
}

} // namespace std

// Automatically generated from PPL source file ../src/Linear_Row.defs.hh line 457

// Automatically generated from PPL source file ../src/Linear_System.defs.hh line 33

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! The base class for systems of constraints and generators.
/*! \ingroup PPL_CXX_interface
  An object of this class represents either a constraint system
  or a generator system. Each Linear_System object can be viewed
  as a finite sequence of strong-normalized Linear_Row objects,
  where each Linear_Row implements a constraint or a generator.
  Linear systems are characterized by the matrix of coefficients,
  also encoding the number, size and capacity of Linear_row objects,
  as well as a few additional information, including:
   - the topological kind of (all) the rows;
   - an indication of whether or not some of the rows in the Linear_System
     are <EM>pending</EM>, meaning that they still have to undergo
     an (unspecified) elaboration; if there are pending rows, then these
     form a proper suffix of the overall sequence of rows;
   - a Boolean flag that, when <CODE>true</CODE>, ensures that the
     non-pending prefix of the sequence of rows is sorted.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS

class Parma_Polyhedra_Library::Linear_System : public Matrix {
public:
  //! Builds an empty linear system with specified topology.
  /*!
    Rows size and capacity are initialized to \f$0\f$.
  */
  Linear_System(Topology topol);

  //! Builds a system with specified topology and dimensions.
  /*!
    \param topol
    The topology of the system that will be created;

    \param n_rows
    The number of rows of the system that will be created;

    \param n_columns
    The number of columns of the system that will be created.

    Creates a \p n_rows \f$\times\f$ \p n_columns system whose
    coefficients are all zero and whose rows are all initialized
    to be of the given topology.
  */
  Linear_System(Topology topol,
		dimension_type n_rows, dimension_type n_columns);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  //! A tag class.
  /*! \ingroup PPL_CXX_interface
    Tag class to differentiate the Linear_System copy-constructor that
    copies pending rows as pending from the one that transforms
    pending rows into non-pending ones.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  struct With_Pending {
  };

  //! Copy-constructor: pending rows are transformed into non-pending ones.
  Linear_System(const Linear_System& y);

  //! Full copy-constructor: pending rows are copied as pending.
  Linear_System(const Linear_System& y, With_Pending);

  //! Assignment operator: pending rows are transformed into non-pending ones.
  Linear_System& operator=(const Linear_System& y);

  //! Full assignment operator: pending rows are copied as pending.
  void assign_with_pending(const Linear_System& y);

  //! Swaps \p *this with \p y.
  void swap(Linear_System& y);

  //! Returns the maximum space dimension a Linear_System can handle.
  static dimension_type max_space_dimension();

  //! Returns the space dimension of the rows in the system.
  /*!
    The computation of the space dimension correctly ignores
    the column encoding the inhomogeneous terms of constraint
    (resp., the divisors of generators);
    if the system topology is <CODE>NOT_NECESSARILY_CLOSED</CODE>,
    also the column of the \f$\epsilon\f$-dimension coefficients
    will be ignored.
  */
  dimension_type space_dimension() const;

  //! Makes the system shrink by removing its \p n trailing columns.
  void remove_trailing_columns(dimension_type n);

  //! Permutes the columns of the system.
  /*
    \param cycles
    A vector representing the non-trivial cycles of the permutation
    according to which the columns must be rearranged.

    The \p cycles vector contains, one after the other, the
    non-trivial cycles (i.e., the cycles of length greater than one)
    of a permutation of non-zero column indexes.  Each cycle is
    terminated by zero.  For example, assuming the system has 6
    columns, the permutation \f$ \{ 1 \mapsto 3, 2 \mapsto 4,
    3 \mapsto 6, 4 \mapsto 2, 5 \mapsto 5, 6 \mapsto 1 \}\f$ can be
    represented by the non-trivial cycles \f$(1 3 6)(2 4)\f$ that, in
    turn can be represented by a vector of 6 elements containing 1, 3,
    6, 0, 2, 4, 0.
  */
  void permute_columns(const std::vector<dimension_type>& cycles);

  //! \name Subscript operators
  //@{
  //! Returns a reference to the \p k-th row of the system.
  Linear_Row& operator[](dimension_type k);

  //! Returns a constant reference to the \p k-th row of the system.
  const Linear_Row& operator[](dimension_type k) const;
  //@} // Subscript operators

  //! Strongly normalizes the system.
  void strong_normalize();

  //! Sign-normalizes the system.
  void sign_normalize();

  //! \name Accessors
  //@{
  //! Returns the system topology.
  Topology topology() const;

  //! Returns the value of the sortedness flag.
  bool is_sorted() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if
    the system topology is <CODE>NECESSARILY_CLOSED</CODE>.
  */
  bool is_necessarily_closed() const;

  /*! \brief
    Returns the number of rows in the system
    that represent either lines or equalities.
  */
  dimension_type num_lines_or_equalities() const;

  //! Returns the index of the first pending row.
  dimension_type first_pending_row() const;

  //! Returns the number of rows that are in the pending part of the system.
  dimension_type num_pending_rows() const;
  //@} // Accessors

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is sorted,
    without checking for duplicates.
  */
  bool check_sorted() const;

  //! Sets the system topology to <CODE>NECESSARILY_CLOSED</CODE>.
  void set_necessarily_closed();

  //! Sets the system topology to <CODE>NOT_NECESSARILY_CLOSED</CODE>.
  void set_not_necessarily_closed();

  //! Sets the topology of all rows equal to the system topology.
  void set_rows_topology();

  //! Sets the index to indicate that the system has no pending rows.
  void unset_pending_rows();

  //! Sets the index of the first pending row to \p i.
  void set_index_first_pending_row(dimension_type i);

  //! Sets the sortedness flag of the system to \p b.
  void set_sorted(bool b);

  //! Resizes the system without worrying about the old contents.
  /*!
    \param new_n_rows
    The number of rows of the resized system;

    \param new_n_columns
    The number of columns of the resized system.

    The system is expanded to the specified dimensions avoiding
    reallocation whenever possible.
    The contents of the original system is lost.
  */
  void resize_no_copy(dimension_type new_n_rows, dimension_type new_n_columns);

  //! Adds \p n rows and columns to the system.
  /*!
    \param n
    The number of rows and columns to be added: must be strictly positive.

    Turns the system \f$M \in \Rset^r \times \Rset^c\f$ into
    the system \f$N \in \Rset^{r+n} \times \Rset^{c+n}\f$
    such that
    \f$N = \bigl(\genfrac{}{}{0pt}{}{0}{M}\genfrac{}{}{0pt}{}{J}{o}\bigr)\f$,
    where \f$J\f$ is the specular image
    of the \f$n \times n\f$ identity matrix.
  */
  void add_rows_and_columns(dimension_type n);

  /*! \brief
    Adds a copy of \p r to the system,
    automatically resizing the system or the row's copy, if needed.
  */
  void insert(const Linear_Row& r);

  /*! \brief
    Adds a copy of the given row to the pending part of the system,
    automatically resizing the system or the row, if needed.
  */
  void insert_pending(const Linear_Row& r);

  //! Adds a copy of the given row to the system.
  void add_row(const Linear_Row& r);

  //! Adds a new empty row to the system, setting only its flags.
  void add_pending_row(Linear_Row::Flags flags);

  //! Adds a copy of the given row to the pending part of the system.
  void add_pending_row(const Linear_Row& r);

  //! Adds to \p *this a copy of the rows of `y'.
  /*!
    It is assumed that \p *this has no pending rows.
  */
  void add_rows(const Linear_System& y);

  //! Adds a copy of the rows of `y' to the pending part of `*this'.
  void add_pending_rows(const Linear_System& y);

  /*! \brief
    Sorts the non-pending rows (in growing order) and eliminates
    duplicated ones.
  */
  void sort_rows();

  /*! \brief
    Sorts the rows (in growing order) form \p first_row to
    \p last_row and eliminates duplicated ones.
  */
  void sort_rows(dimension_type first_row, dimension_type last_row);

  /*! \brief
    Assigns to \p *this the result of merging its rows with
    those of \p y, obtaining a sorted system.

    Duplicated rows will occur only once in the result.
    On entry, both systems are assumed to be sorted and have
    no pending rows.
  */
  void merge_rows_assign(const Linear_System& y);

  /*! \brief
    Sorts the pending rows and eliminates those that also occur
    in the non-pending part of the system.
  */
  void sort_pending_and_remove_duplicates();

  class With_Saturation_Matrix_iterator;

  /*! \brief
    Sorts the system, removing duplicates, keeping the saturation
    matrix consistent.

    \param sat
    Saturation matrix with rows corresponding to the rows of \p *this.
  */
  void sort_and_remove_with_sat(Saturation_Matrix& sat);

  //! Minimizes the subsystem of equations contained in \p *this.
  /*!
    This method works only on the equalities of the system:
    the system is required to be partially sorted, so that
    all the equalities are grouped at its top; it is assumed that
    the number of equalities is exactly \p n_lines_or_equalities.
    The method finds a minimal system for the equalities and
    returns its rank, i.e., the number of linearly independent equalities.
    The result is an upper triangular subsystem of equalities:
    for each equality, the pivot is chosen starting from
    the right-most columns.
  */
  dimension_type gauss(dimension_type n_lines_or_equalities);

  /*! \brief
    Back-substitutes the coefficients to reduce
    the complexity of the system.

    Takes an upper triangular system having \p n_lines_or_equalities rows.
    For each row, starting from the one having the minimum number of
    coefficients different from zero, computes the expression of an element
    as a function of the remaining ones and then substitutes this expression
    in all the other rows.
  */
  void back_substitute(dimension_type n_lines_or_equalities);

  /*! \brief
    Applies Gaussian's elimination and back-substitution so as to
    simplify the linear system.
  */
  void simplify();

  /*! \brief
    Normalizes the system by dividing each row for the GCD of the
    row's elements.
  */
  void normalize();

  //! Clears the system deallocating all its rows.
  void clear();

  PPL_OUTPUT_DECLARATIONS;

  /*! \brief
    Loads from \p s an ASCII representation (as produced by \ref
    ascii_dump) and sets \p *this accordingly.  Returns <CODE>true</CODE>
    if successful, <CODE>false</CODE> otherwise.

    Reads into a Linear_System object the information produced by the
    output of <CODE>ascii_dump()</CODE>.  The specialized methods
    provided by Constraint_System and Generator_System take care of
    properly reading the contents of the system.
  */
  bool ascii_load(std::istream& s);

  //! Returns the total size in bytes of the memory occupied by \p *this.
  memory_size_type total_memory_in_bytes() const;

  //! Returns the size in bytes of the memory managed by \p *this.
  memory_size_type external_memory_in_bytes() const;

  //! Checks if all the invariants are satisfied.
  /*!
    \param check_strong_normalized
    <CODE>true</CODE> if and only if the strong normalization of all
    the rows in the system has to be checked.

    By default, the strong normalization check is performed.
    This check may be turned off to avoid useless repeated checking;
    e.g., when re-checking a well-formed Linear_System after the permutation
    or deletion of some of its rows.
  */
  bool OK(bool check_strong_normalized = true) const;

private:
  //! The topological kind of the rows in the system.
  Topology row_topology;

  //! The index of the first pending row.
  dimension_type index_first_pending;

  /*! \brief
    <CODE>true</CODE> if rows are sorted in the ascending order as defined by
    <CODE>bool compare(const Linear_Row&, const Linear_Row&)</CODE>.
    If <CODE>false</CODE> may not be sorted.
  */
  bool sorted;

  //! Ordering predicate (used when implementing the sort algorithm).
  struct Row_Less_Than {
    bool operator()(const Row& x, const Row& y) const;
  };
};

namespace std {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Linear_System */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
void swap(Parma_Polyhedra_Library::Linear_System& x,
	  Parma_Polyhedra_Library::Linear_System& y);

} // namespace std

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns <CODE>true</CODE> if and only if \p x and \p y are identical.
/*! \relates Linear_System */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
bool operator==(const Linear_System& x, const Linear_System& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns <CODE>true</CODE> if and only if \p x and \p y are different.
/*! \relates Linear_System */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
bool operator!=(const Linear_System& x, const Linear_System& y);

} // namespace Parma_Polyhedra_Library

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! An iterator keeping a Linear_System consistent with a Saturation_Matrix.
/*! \ingroup PPL_CXX_interface
  An iterator on the vector of Row objects encoded in a Linear_System
  extended to maintain a corresponding iterator on a vector of
  Saturation_Row objects.  Access to values is always done on the Row
  objects, but iterator
  movements and swaps are done on both components.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
class Parma_Polyhedra_Library::Linear_System::With_Saturation_Matrix_iterator {
public:
  typedef std::vector<Row>::iterator Iter1;
  typedef std::vector<Saturation_Row>::iterator Iter2;

private:
  Iter1 i1;
  Iter2 i2;

public:
  // Same traits as Iter1.
  typedef std::iterator_traits<Iter1>::iterator_category iterator_category;
  typedef std::iterator_traits<Iter1>::value_type value_type;
  typedef std::iterator_traits<Iter1>::difference_type difference_type;
  typedef std::iterator_traits<Iter1>::pointer pointer;
  typedef std::iterator_traits<Iter1>::reference reference;

  //! Constructor.
  With_Saturation_Matrix_iterator(Iter1 iter1, Iter2 iter2);

  //! Copy-constructor.
  With_Saturation_Matrix_iterator(const With_Saturation_Matrix_iterator& y);

  //! Destructor.
  ~With_Saturation_Matrix_iterator();

  //! Assignment operator.
  With_Saturation_Matrix_iterator&
  operator=(const With_Saturation_Matrix_iterator& y);

  //! \name Operators Implementing Iterator Movement
  //@{
  With_Saturation_Matrix_iterator& operator++();
  With_Saturation_Matrix_iterator operator++(int);

  With_Saturation_Matrix_iterator& operator--();
  With_Saturation_Matrix_iterator operator--(int);

  With_Saturation_Matrix_iterator& operator+=(difference_type d);
  With_Saturation_Matrix_iterator operator+(difference_type d) const;

  With_Saturation_Matrix_iterator& operator-=(difference_type d);
  With_Saturation_Matrix_iterator operator-(difference_type d) const;
  //@}

  //! Distance operator.
  difference_type operator-(const With_Saturation_Matrix_iterator& y) const;

  //! \name Comparisons between Iterators
  //@{
  bool operator==(const With_Saturation_Matrix_iterator& y) const;
  bool operator!=(const With_Saturation_Matrix_iterator& y) const;
  bool operator<(const With_Saturation_Matrix_iterator& y) const;
  //@}

  //! Dereferencing operator.
  reference operator*() const;

  //! Access-through operator.
  pointer operator->() const;

  //! Swaps the pointed Row objects while keeping Saturation_Matrix consistent.
  void iter_swap(const With_Saturation_Matrix_iterator& y) const;

};

namespace std {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Specializes <CODE>std::iter_swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Linear_System::With_Saturation_Matrix_iterator */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
void
iter_swap(Parma_Polyhedra_Library
	  ::Linear_System::With_Saturation_Matrix_iterator x,
	  Parma_Polyhedra_Library
	  ::Linear_System::With_Saturation_Matrix_iterator y);

} // namespace std

// Automatically generated from PPL source file ../src/Linear_System.inlines.hh line 1
/* Linear_System class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/Saturation_Row.defs.hh line 1
/* Saturation_Row class declaration.
*/


// Automatically generated from PPL source file ../src/Saturation_Row.defs.hh line 28
#include <iosfwd>
#include <gmp.h>
#include <vector>

namespace Parma_Polyhedra_Library {

// Put them in the namespace here to declare them friends later.

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns <CODE>true</CODE> if and only if \p x and \p y are equal.
/*! \relates Saturation_Row */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
bool operator==(const Saturation_Row& x, const Saturation_Row& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns <CODE>true</CODE> if and only if \p x and \p y are not equal.
/*! \relates Saturation_Row */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
bool operator!=(const Saturation_Row& x, const Saturation_Row& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! The basic comparison function.
/*! \relates Saturation_Row
  Compares \p x with \p y starting from the least significant bits.
  The ordering is total and has the following property: if \p x and \p y
  are two rows seen as sets of naturals, if \p x is a strict subset
  of \p y, then \p x comes before \p y.

  Returns
  - -1 if \p x comes before \p y in the ordering;
  -  0 if \p x and \p y are equal;
  -  1 if \p x comes after \p y in the ordering.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
int compare(const Saturation_Row& x, const Saturation_Row& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Set-theoretic inclusion test.
/*! \relates Saturation_Row */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
bool subset_or_equal(const Saturation_Row& x, const Saturation_Row& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  Set-theoretic inclusion test: sets \p strict_subset to a boolean
  indicating whether the inclusion is strict or not.

  \relates Saturation_Row
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
bool subset_or_equal(const Saturation_Row& x, const Saturation_Row& y,
		     bool& strict_subset);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Set-theoretic strict inclusion test.
/*! \relates Saturation_Row */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
bool strict_subset(const Saturation_Row& x, const Saturation_Row& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Set-theoretic union.
/*! \relates Saturation_Row */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
void set_union(const Saturation_Row& x,
	       const Saturation_Row& y,
	       Saturation_Row& z);

} // namespace Parma_Polyhedra_Library

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A row of a saturation matrix.
/*! \ingroup PPL_CXX_interface
  An object of this class represents a single row of a saturation matrix.
  The saturation row corresponds to a constraint and a system of generators
  (resp., a generator and a system of constraints) and records whether or
  not the constraint is saturated by each one of the generators (resp.,
  the generator saturates each one of the constraints).

  The saturation relation is encoded by using a bitset, so that the
  constraint is saturated by the \f$i\f$-th generator in the system
  (resp., the generator saturates the \f$i\f$-th constraint in the system)
  if and only if the \f$i\f$-th bit is not set.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
class Parma_Polyhedra_Library::Saturation_Row {
public:
  //! Default constructor.
  Saturation_Row();

  //! Copy-constructor.
  Saturation_Row(const Saturation_Row& y);

  //! Destructor.
  ~Saturation_Row();

  //! Assignment operator.
  Saturation_Row& operator=(const Saturation_Row& y);

  //! Swaps \p *this with \p y.
  void swap(Saturation_Row& y);

  //! Returns the truth value corresponding to the bit in position \p k.
  bool operator[](unsigned long k) const;

  //! Sets the bit in position \p k.
  void set(unsigned long k);

  //! Clears the bit in position \p k.
  void clear(unsigned long k);

  //! Clears bits from position \p k (included) onward.
  void clear_from(unsigned long k);

  //! Clears all the bits of the row.
  void clear();

  friend int
  Parma_Polyhedra_Library::compare(const Saturation_Row& x,
				   const Saturation_Row& y);

  friend bool
  Parma_Polyhedra_Library::operator==(const Saturation_Row& x,
				      const Saturation_Row& y);

  friend bool
  Parma_Polyhedra_Library::operator!=(const Saturation_Row& x,
				      const Saturation_Row& y);

  friend bool
  Parma_Polyhedra_Library::subset_or_equal(const Saturation_Row& x,
					   const Saturation_Row& y);

  friend bool
  Parma_Polyhedra_Library::subset_or_equal(const Saturation_Row& x,
					   const Saturation_Row& y,
					   bool& strict_subset);

  friend bool
  Parma_Polyhedra_Library::strict_subset(const Saturation_Row& x,
					 const Saturation_Row& y);

  friend void
  Parma_Polyhedra_Library::set_union(const Saturation_Row& x,
				     const Saturation_Row& y,
				     Saturation_Row& z);

  //! Returns the index of the first set bit or ULONG_MAX if no bit is set.
  unsigned long first() const;

  /*! \brief
    Returns the index of the first set bit after \p position
    or ULONG_MAX if no bit after \p position is set.
  */
  unsigned long next(unsigned long position) const;

  //! Returns the index of the last set bit or ULONG_MAX if no bit is set.
  unsigned long last() const;

  /*! \brief
    Returns the index of the first set bit before \p position
    or ULONG_MAX if no bits before \p position is set.
  */
  unsigned long prev(unsigned long position) const;

  //! Returns the number of set bits in the row.
  unsigned long count_ones() const;

  //! Returns <CODE>true</CODE> if no bit is set in the row.
  bool empty() const;

  //! Returns the total size in bytes of the memory occupied by \p *this.
  memory_size_type total_memory_in_bytes() const;

  //! Returns the size in bytes of the memory managed by \p *this.
  memory_size_type external_memory_in_bytes() const;

  //! Checks if all the invariants are satisfied
  bool OK() const;

private:
  //! Bit-vector representing the row.
  mpz_t vec;

  //! Assuming \p w is nonzero, returns the index of the first set bit in \p w.
  static unsigned int first_one(mp_limb_t w);

  //! Assuming \p w is nonzero, returns the index of the last set bit in \p w.
  static unsigned int last_one(mp_limb_t w);
};

namespace std {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Saturation_Row */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
void swap(Parma_Polyhedra_Library::Saturation_Row& x,
	  Parma_Polyhedra_Library::Saturation_Row& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Specializes <CODE>std::iter_swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Saturation_Row */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
void
iter_swap(std::vector<Parma_Polyhedra_Library::Saturation_Row>::iterator x,
	  std::vector<Parma_Polyhedra_Library::Saturation_Row>::iterator y);

} // namespace std

// Automatically generated from PPL source file ../src/Saturation_Row.inlines.hh line 1
/* Saturation_Row class implementation: inline functions.
*/


#include <cassert>
// For the declaration of ffs(3).
#include <cstring>

namespace Parma_Polyhedra_Library {

inline
Saturation_Row::Saturation_Row() {
  mpz_init(vec);
}

inline
Saturation_Row::Saturation_Row(const Saturation_Row& y) {
  mpz_init_set(vec, y.vec);
}

inline
Saturation_Row::~Saturation_Row() {
  mpz_clear(vec);
}

inline Saturation_Row&
Saturation_Row::operator=(const Saturation_Row& y) {
  mpz_set(vec, y.vec);
  return *this;
}

inline void
Saturation_Row::set(const unsigned long k) {
  mpz_setbit(vec, k);
}

inline void
Saturation_Row::clear(const unsigned long k) {
  mpz_clrbit(vec, k);
}

inline void
Saturation_Row::clear_from(const unsigned long k) {
  mpz_tdiv_r_2exp(vec, vec, k);
}

inline unsigned long
Saturation_Row::count_ones() const {
  assert(vec->_mp_size >= 0);
  return mpn_popcount(vec->_mp_d, vec->_mp_size);
}

inline bool
Saturation_Row::empty() const {
  return mpz_sgn(vec) == 0;
}

inline void
Saturation_Row::swap(Saturation_Row& y) {
  mpz_swap(vec, y.vec);
}

inline void
Saturation_Row::clear() {
  mpz_set_ui(vec, 0UL);
}

inline memory_size_type
Saturation_Row::external_memory_in_bytes() const {
  return vec[0]._mp_alloc * SIZEOF_MP_LIMB_T;
}

inline memory_size_type
Saturation_Row::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

#if HAVE_DECL_FFS && SIZEOF_MP_LIMB_T == SIZEOF_INT

inline unsigned int
Saturation_Row::first_one(mp_limb_t w) {
  return ffs(w)-1;
}

#endif

/*! \relates Saturation_Row */
inline void
set_union(const Saturation_Row& x, const Saturation_Row& y,
	  Saturation_Row& z) {
  mpz_ior(z.vec, x.vec, y.vec);
}

} // namespace Parma_Polyhedra_Library


namespace std {

/*! \relates Parma_Polyhedra_Library::Saturation_Row */
inline void
swap(Parma_Polyhedra_Library::Saturation_Row& x,
     Parma_Polyhedra_Library::Saturation_Row& y) {
  x.swap(y);
}

/*! \relates Parma_Polyhedra_Library::Saturation_Row */
inline void
iter_swap(std::vector<Parma_Polyhedra_Library::Saturation_Row>::iterator x,
	  std::vector<Parma_Polyhedra_Library::Saturation_Row>::iterator y) {
  swap(*x, *y);
}

} // namespace std

// Automatically generated from PPL source file ../src/Saturation_Row.defs.hh line 238

// Automatically generated from PPL source file ../src/Linear_System.inlines.hh line 27

namespace Parma_Polyhedra_Library {

inline memory_size_type
Linear_System::external_memory_in_bytes() const {
  return Matrix::external_memory_in_bytes();
}

inline memory_size_type
Linear_System::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

inline bool
Linear_System::is_sorted() const {
  // The flag `sorted' does not really reflect the sortedness status
  // of a system (if `sorted' evaluates to `false' nothing is known).
  // This assertion is used to ensure that the system
  // is actually sorted when `sorted' value is 'true'.
  assert(!sorted || check_sorted());
  return sorted;
}

inline void
Linear_System::set_sorted(const bool b) {
  sorted = b;
}

inline
Linear_System::Linear_System(Topology topol)
  : Matrix(),
    row_topology(topol),
    index_first_pending(0),
    sorted(true) {
}

inline
Linear_System::Linear_System(Topology topol,
			     dimension_type n_rows, dimension_type n_columns)
  : Matrix(n_rows, n_columns, Linear_Row::Flags(topol)),
    row_topology(topol),
    index_first_pending(n_rows),
    sorted(true) {
}

inline dimension_type
Linear_System::first_pending_row() const {
  return index_first_pending;
}

inline dimension_type
Linear_System::num_pending_rows() const {
  assert(num_rows() >= first_pending_row());
  return num_rows() - first_pending_row();
}

inline void
Linear_System::unset_pending_rows() {
  index_first_pending = num_rows();
}

inline void
Linear_System::set_index_first_pending_row(const dimension_type i) {
  index_first_pending = i;
}

inline
Linear_System::Linear_System(const Linear_System& y)
  : Matrix(y),
    row_topology(y.row_topology) {
  unset_pending_rows();
  // Previously pending rows may violate sortedness.
  sorted = (y.num_pending_rows() > 0) ? false : y.sorted;
  assert(num_pending_rows() == 0);
}

inline
Linear_System::Linear_System(const Linear_System& y, With_Pending)
  : Matrix(y),
    row_topology(y.row_topology),
    index_first_pending(y.index_first_pending),
    sorted(y.sorted) {
}

inline Linear_System&
Linear_System::operator=(const Linear_System& y) {
  Matrix::operator=(y);
  row_topology = y.row_topology;
  unset_pending_rows();
  // Previously pending rows may violate sortedness.
  sorted = (y.num_pending_rows() > 0) ? false : y.sorted;
  assert(num_pending_rows() == 0);
  return *this;
}

inline void
Linear_System::assign_with_pending(const Linear_System& y) {
  Matrix::operator=(y);
  row_topology = y.row_topology;
  index_first_pending = y.index_first_pending;
  sorted = y.sorted;
}

inline void
Linear_System::swap(Linear_System& y) {
  Matrix::swap(y);
  std::swap(row_topology, y.row_topology);
  std::swap(index_first_pending, y.index_first_pending);
  std::swap(sorted, y.sorted);
}

inline void
Linear_System::clear() {
  // Note: do NOT modify the value of `row_topology'.
  Matrix::clear();
  index_first_pending = 0;
  sorted = true;
}

inline void
Linear_System::resize_no_copy(const dimension_type new_n_rows,
			      const dimension_type new_n_columns) {
  Matrix::resize_no_copy(new_n_rows, new_n_columns,
			 Linear_Row::Flags(row_topology));
  // Even though `*this' may happen to keep its sortedness, we believe
  // that checking such a property is not worth the effort.  In fact,
  // it is very likely that the system will be overwritten as soon as
  // we return.
  set_sorted(false);
}

inline void
Linear_System::set_necessarily_closed() {
  row_topology = NECESSARILY_CLOSED;
  if (num_rows() > 0)
    set_rows_topology();
}

inline void
Linear_System::set_not_necessarily_closed() {
  row_topology = NOT_NECESSARILY_CLOSED;
  if (num_rows() > 0)
    set_rows_topology();
}

inline bool
Linear_System::is_necessarily_closed() const {
  return row_topology == NECESSARILY_CLOSED;
}

inline Linear_Row&
Linear_System::operator[](const dimension_type k) {
  return static_cast<Linear_Row&>(Matrix::operator[](k));
}

inline const Linear_Row&
Linear_System::operator[](const dimension_type k) const {
  return static_cast<const Linear_Row&>(Matrix::operator[](k));
}

inline Topology
Linear_System::topology() const {
  return row_topology;
}

inline dimension_type
Linear_System::max_space_dimension() {
  // Column zero holds the inhomogeneous term or the divisor.
  // In NNC linear systems, the last column holds the coefficient
  // of the epsilon dimension.
  return max_num_columns() - 2;
}

inline dimension_type
Linear_System::space_dimension() const {
  const dimension_type n_columns = num_columns();
  return (n_columns == 0)
    ? 0
    : n_columns - (is_necessarily_closed() ? 1 : 2);
}

inline void
Linear_System::remove_trailing_columns(const dimension_type n) {
  Matrix::remove_trailing_columns(n);
  // Have to re-normalize the rows of the system,
  // since we removed some coefficients.
  strong_normalize();
}

inline void
Linear_System::permute_columns(const std::vector<dimension_type>& cycles) {
  Matrix::permute_columns(cycles);
  // The rows with permuted columns are still normalized but may
  // be not strongly normalized: sign normalization is necessary.
  sign_normalize();
}

/*! \relates Linear_System */
inline bool
operator!=(const Linear_System& x, const Linear_System& y) {
  return !(x == y);
}

inline bool
Linear_System::Row_Less_Than::operator()(const Row& x, const Row& y) const {
  return compare(static_cast<const Linear_Row&>(x),
		 static_cast<const Linear_Row&>(y)) < 0;
}

} // namespace Parma_Polyhedra_Library

namespace std {

/*! \relates Parma_Polyhedra_Library::Linear_System */
inline void
swap(Parma_Polyhedra_Library::Linear_System& x,
     Parma_Polyhedra_Library::Linear_System& y) {
  x.swap(y);
}

} // namespace std


namespace Parma_Polyhedra_Library {

inline
Linear_System::With_Saturation_Matrix_iterator::
With_Saturation_Matrix_iterator(Iter1 iter1, Iter2 iter2)
  : i1(iter1), i2(iter2) {
}

inline
Linear_System::With_Saturation_Matrix_iterator::
With_Saturation_Matrix_iterator(const With_Saturation_Matrix_iterator& y)
  : i1(y.i1), i2(y.i2) {
}

inline
Linear_System::With_Saturation_Matrix_iterator::
~With_Saturation_Matrix_iterator() {
}

inline Linear_System::With_Saturation_Matrix_iterator&
Linear_System::With_Saturation_Matrix_iterator::
operator=(const With_Saturation_Matrix_iterator& y) {
  i1 = y.i1;
  i2 = y.i2;
  return *this;
}

inline Linear_System::With_Saturation_Matrix_iterator&
Linear_System::With_Saturation_Matrix_iterator::operator++() {
  ++i1;
  ++i2;
  return *this;
}

inline Linear_System::With_Saturation_Matrix_iterator
Linear_System::With_Saturation_Matrix_iterator::operator++(int) {
  With_Saturation_Matrix_iterator tmp = *this;
  operator++();
  return tmp;
}

inline Linear_System::With_Saturation_Matrix_iterator&
Linear_System::With_Saturation_Matrix_iterator::operator--() {
  --i1;
  --i2;
  return *this;
}

inline Linear_System::With_Saturation_Matrix_iterator
Linear_System::With_Saturation_Matrix_iterator::operator--(int) {
  With_Saturation_Matrix_iterator tmp = *this;
  operator--();
  return tmp;
}

inline Linear_System::With_Saturation_Matrix_iterator&
Linear_System::With_Saturation_Matrix_iterator::operator+=(difference_type d) {
  i1 += d;
  i2 += d;
  return *this;
}

inline Linear_System::With_Saturation_Matrix_iterator
Linear_System::With_Saturation_Matrix_iterator::
operator+(difference_type d) const {
  With_Saturation_Matrix_iterator tmp = *this;
  tmp += d;
  return tmp;
}

inline Linear_System::With_Saturation_Matrix_iterator&
Linear_System::With_Saturation_Matrix_iterator::operator-=(difference_type d) {
  i1 -= d;
  i2 -= d;
  return *this;
}

inline Linear_System::With_Saturation_Matrix_iterator
Linear_System::With_Saturation_Matrix_iterator::
operator-(difference_type d) const {
  With_Saturation_Matrix_iterator tmp = *this;
  tmp -= d;
  return tmp;
}

inline Linear_System::With_Saturation_Matrix_iterator::difference_type
Linear_System::With_Saturation_Matrix_iterator::
operator-(const With_Saturation_Matrix_iterator& y) const {
  return i1 - y.i1;
}

inline bool
Linear_System::With_Saturation_Matrix_iterator::
operator==(const With_Saturation_Matrix_iterator& y) const {
  return i1 == y.i1;
}

inline bool
Linear_System::With_Saturation_Matrix_iterator::
operator!=(const With_Saturation_Matrix_iterator& y) const {
  return i1 != y.i1;
}

inline bool
Linear_System::With_Saturation_Matrix_iterator::
operator<(const With_Saturation_Matrix_iterator& y) const {
  return i1 < y.i1;
}

inline Linear_System::With_Saturation_Matrix_iterator::reference
Linear_System::With_Saturation_Matrix_iterator::operator*() const {
  return *i1;
}

inline Linear_System::With_Saturation_Matrix_iterator::pointer
Linear_System::With_Saturation_Matrix_iterator::operator->() const {
  return &*i1;
}

inline void
Linear_System::With_Saturation_Matrix_iterator::
iter_swap(const With_Saturation_Matrix_iterator& y) const {
  std::iter_swap(i1, y.i1);
  std::iter_swap(i2, y.i2);
}

} // namespace Parma_Polyhedra_Library

namespace std {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates Parma_Polyhedra_Library::Linear_System::With_Saturation_Matrix_iterator */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
inline void
iter_swap(Parma_Polyhedra_Library
	  ::Linear_System::With_Saturation_Matrix_iterator x,
	  Parma_Polyhedra_Library
	  ::Linear_System::With_Saturation_Matrix_iterator y) {
  x.iter_swap(y);
}

} // namespace std

// Automatically generated from PPL source file ../src/Linear_System.defs.hh line 516

// Automatically generated from PPL source file ../src/Constraint_System.defs.hh line 33
#include <iterator>
#include <iosfwd>

namespace Parma_Polyhedra_Library {

namespace IO_Operators {

//! Output operator.
/*!
  \relates Parma_Polyhedra_Library::Constraint_System
  Writes <CODE>true</CODE> if \p cs is empty.  Otherwise, writes on
  \p s the constraints of \p cs, all in one row and separated by ", ".
*/
std::ostream& operator<<(std::ostream& s, const Constraint_System& cs);

} // namespace IO_Operators

// Put it in the namespace here to declare it friend later.
/*! \relates Polyhedron */
bool operator==(const Polyhedron& x, const Polyhedron& y);

} // namespace Parma_Polyhedra_Library


namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Constraint_System */
void swap(Parma_Polyhedra_Library::Constraint_System& x,
	  Parma_Polyhedra_Library::Constraint_System& y);

} // namespace std

//! A system of constraints.
/*! \ingroup PPL_CXX_interface
    An object of the class Constraint_System is a system of constraints,
    i.e., a multiset of objects of the class Constraint.
    When inserting constraints in a system, space dimensions are
    automatically adjusted so that all the constraints in the system
    are defined on the same vector space.

    \par
    In all the examples it is assumed that variables
    <CODE>x</CODE> and <CODE>y</CODE> are defined as follows:
    \code
  Variable x(0);
  Variable y(1);
    \endcode

    \par Example 1
    The following code builds a system of constraints corresponding to
    a square in \f$\Rset^2\f$:
    \code
  Constraint_System cs;
  cs.insert(x >= 0);
  cs.insert(x <= 3);
  cs.insert(y >= 0);
  cs.insert(y <= 3);
    \endcode
    Note that:
    the constraint system is created with space dimension zero;
    the first and third constraint insertions increase the space
    dimension to \f$1\f$ and \f$2\f$, respectively.

    \par Example 2
    By adding four strict inequalities to the constraint system
    of the previous example, we can remove just the four
    vertices from the square defined above.
    \code
  cs.insert(x + y > 0);
  cs.insert(x + y < 6);
  cs.insert(x - y < 3);
  cs.insert(y - x < 3);
    \endcode

    \par Example 3
    The following code builds a system of constraints corresponding to
    a half-strip in \f$\Rset^2\f$:
    \code
  Constraint_System cs;
  cs.insert(x >= 0);
  cs.insert(x - y <= 0);
  cs.insert(x - y + 1 >= 0);
    \endcode

    \note
    After inserting a multiset of constraints in a constraint system,
    there are no guarantees that an <EM>exact</EM> copy of them
    can be retrieved:
    in general, only an <EM>equivalent</EM> constraint system
    will be available, where original constraints may have been
    reordered, removed (if they are trivial, duplicate or
    implied by other constraints), linearly combined, etc.
*/
class Parma_Polyhedra_Library::Constraint_System : private Linear_System {
public:
  //! Default constructor: builds an empty system of constraints.
  Constraint_System();

  //! Builds the singleton system containing only constraint \p c.
  explicit Constraint_System(const Constraint& c);

  //! Ordinary copy-constructor.
  Constraint_System(const Constraint_System& cs);

  //! Destructor.
  ~Constraint_System();

  //! Assignment operator.
  Constraint_System& operator=(const Constraint_System& y);

  //! Returns the maximum space dimension a Constraint_System can handle.
  static dimension_type max_space_dimension();

  //! Returns the dimension of the vector space enclosing \p *this.
  dimension_type space_dimension() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this
    contains one or more strict inequality constraints.
  */
  bool has_strict_inequalities() const;

  /*! \brief
    Removes all the constraints from the constraint system
    and sets its space dimension to 0.
  */
  void clear();

  /*! \brief
    Inserts in \p *this a copy of the constraint \p c,
    increasing the number of space dimensions if needed.
  */
  void insert(const Constraint& c);

  /*! \brief
    Returns the singleton system containing only
    Constraint::zero_dim_false().
  */
  static const Constraint_System& zero_dim_empty();

  //! An iterator over a system of constraints.
  /*! \ingroup PPL_CXX_interface
    A const_iterator is used to provide read-only access
    to each constraint contained in a Constraint_System object.

    \par Example
    The following code prints the system of constraints
    defining the polyhedron <CODE>ph</CODE>:
    \code
  const Constraint_System& cs = ph.constraints();
  for (Constraint_System::const_iterator i = cs.begin(),
         cs_end = cs.end(); i != cs_end; ++i)
    cout << *i << endl;
    \endcode
  */
  class const_iterator
    : public std::iterator<std::forward_iterator_tag,
			   Constraint,
			   ptrdiff_t,
			   const Constraint*,
			   const Constraint&> {
  public:
    //! Default constructor.
    const_iterator();

    //! Ordinary copy-constructor.
    const_iterator(const const_iterator& y);

    //! Destructor.
    ~const_iterator();

    //! Assignment operator.
    const_iterator& operator=(const const_iterator& y);

    //! Dereference operator.
    const Constraint& operator*() const;

    //! Indirect member selector.
    const Constraint* operator->() const;

    //! Prefix increment operator.
    const_iterator& operator++();

    //! Postfix increment operator.
    const_iterator operator++(int);

    /*! \brief
      Returns <CODE>true</CODE> if and only if
      \p *this and \p y are identical.
    */
    bool operator==(const const_iterator& y) const;

    /*! \brief
      Returns <CODE>true</CODE> if and only if
      \p *this and \p y are different.
    */
    bool operator!=(const const_iterator& y) const;

  private:
    friend class Constraint_System;

    //! The const iterator over the matrix of constraints.
    Linear_System::const_iterator i;

    //! A const pointer to the matrix of constraints.
    const Linear_System* csp;

    //! Constructor.
    const_iterator(const Linear_System::const_iterator& iter,
		   const Constraint_System& csys);

    //! \p *this skips to the next non-trivial constraint.
    void skip_forward();
  };

  /*! \brief
    Returns the const_iterator pointing to the first constraint,
    if \p *this is not empty;
    otherwise, returns the past-the-end const_iterator.
  */
  const_iterator begin() const;

  //! Returns the past-the-end const_iterator.
  const_iterator end() const;

  //! Checks if all the invariants are satisfied.
#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*!
    Returns <CODE>true</CODE> if and only if \p *this is a valid
    Linear_System and each row in the system is a valid Constraint.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  bool OK() const;

  PPL_OUTPUT_DECLARATIONS;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    \ref ascii_dump) and sets \p *this accordingly.
    Returns <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  bool ascii_load(std::istream& s);

  //! Returns the total size in bytes of the memory occupied by \p *this.
  memory_size_type total_memory_in_bytes() const;

  //! Returns the size in bytes of the memory managed by \p *this.
  memory_size_type external_memory_in_bytes() const;

  //! Swaps \p *this with \p y.
  void swap(Constraint_System& y);

private:
  friend class const_iterator;
  friend class Parma_Polyhedra_Library::Polyhedron;
  friend class Parma_Polyhedra_Library::LP_Problem;

  friend bool
  Parma_Polyhedra_Library::operator==(const Polyhedron& x,
				      const Polyhedron& y);

  //! Builds an empty system of constraints having the specified topology.
  explicit Constraint_System(Topology topol);

  /*! \brief
    Builds a system of \p n_rows constraints on a \p n_columns - 1
    dimensional space (including the \f$\epsilon\f$ dimension, if
    \p topol is <CODE>NOT_NECESSARILY_CLOSED</CODE>).
  */
  Constraint_System(Topology topol,
		    dimension_type n_rows, dimension_type n_columns);

  /*! \brief
    Adjusts \p *this so that it matches the topology and
    the number of space dimensions given as parameters
    (adding or removing columns if needed).
    Returns <CODE>false</CODE> if and only if \p topol is
    equal to <CODE>NECESSARILY_CLOSED</CODE> and \p *this
    contains strict inequalities.
  */
  bool adjust_topology_and_space_dimension(Topology topol,
					   dimension_type num_dimensions);

  //! Returns the \p k- th constraint of the system.
  Constraint& operator[](dimension_type k);

  //! Returns a constant reference to the \p k- th constraint of the system.
  const Constraint& operator[](dimension_type k) const;

  //! Returns <CODE>true</CODE> if \p g satisfies all the constraints.
  bool satisfies_all_constraints(const Generator& g) const;

  //! Substitutes a given column of coefficients by a given affine expression.
  /*!
    \param v
    Index of the column to which the affine transformation is substituted.

    \param expr
    The numerator of the affine transformation:
    \f$\sum_{i = 0}^{n - 1} a_i x_i + b\f$;

    \param denominator
    The denominator of the affine transformation.

    We want to allow affine transformations
    (see Section \ref Images_and_Preimages_of_Affine_Transfer_Relations)
    having any rational coefficients. Since the coefficients of the
    constraints are integers we must also provide an integer \p
    denominator that will be used as denominator of the affine
    transformation.
    The denominator is required to be a positive integer.

    The affine transformation substitutes the matrix of constraints
    by a new matrix whose elements \f${a'}_{ij}\f$ are built from
    the old one \f$a_{ij}\f$ as follows:
    \f[
      {a'}_{ij} =
        \begin{cases}
          a_{ij} * \mathrm{denominator} + a_{iv} * \mathrm{expr}[j]
            \quad \text{for } j \neq v; \\
          \mathrm{expr}[v] * a_{iv}
            \quad \text{for } j = v.
        \end{cases}
    \f]

    \p expr is a constant parameter and unaltered by this computation.
  */
  void affine_preimage(dimension_type v,
		       const Linear_Expression& expr,
		       Coefficient_traits::const_reference denominator);

  //! Returns the number of equality constraints.
  dimension_type num_equalities() const;

  //! Returns the number of inequality constraints.
  dimension_type num_inequalities() const;

  /*! \brief
    Applies Gaussian's elimination and back-substitution so as
    to provide a partial simplification of the system of constraints.

    It is assumed that the system has no pending constraints.
  */
  void simplify();

  /*! \brief
    Inserts in \p *this a copy of the constraint \p c,
    increasing the number of space dimensions if needed.
    It is a pending constraint.
  */
  void insert_pending(const Constraint& c);

  //! Adds low-level constraints to the constraint system.
  void add_low_level_constraints();
};

// Constraint_System.inlines.hh is not included here on purpose.

// Automatically generated from PPL source file ../src/Bounding_Box.defs.hh line 31
#include <vector>
#include <iosfwd>

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A not necessarily closed bounding-box.
/*! \ingroup PPL_CXX_interface
  A Bounding_Box object represents the Cartesian product of \f$n\f$
  not necessarily closed and possibly unbounded intervals,
  where \f$n\f$ is the space dimension of the box.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
class Bounding_Box {
public:
  //! Constructs a universe bounding box of dimension \p num_dimensions.
  Bounding_Box(dimension_type num_dimensions);

  //! Returns the dimension of the vector space enclosing \p *this.
  dimension_type space_dimension() const;

  /*! \brief
    Returns a reference the interval that bounds
    the box on the <CODE>k</CODE>-th space dimension.
  */
  const Interval& operator[](dimension_type k) const;

  //! Returns <CODE>true</CODE> if and only if \p *this is empty.
  bool is_empty() const;

  /*! \brief
    If the <CODE>k</CODE>-th space dimension is unbounded below, returns
    <CODE>false</CODE>. Otherwise returns <CODE>true</CODE> and set
    \p closed, \p n and \p d accordingly.

    Let \f$I\f$ the interval corresponding to the <CODE>k</CODE>-th
    space dimension.  If \f$I\f$ is not bounded from below, simply return
    <CODE>false</CODE>.  Otherwise, set <CODE>closed</CODE>,
    <CODE>n</CODE> and <CODE>d</CODE> as follows: <CODE>closed</CODE>
    is set to <CODE>true</CODE> if the the lower boundary of \f$I\f$
    is closed and is set to <CODE>false</CODE> otherwise;
    <CODE>n</CODE> and <CODE>d</CODE> are assigned the integers
    \f$n\f$ and \f$d\f$ such that the canonical fraction \f$n/d\f$
    corresponds to the greatest lower bound of \f$I\f$.  The fraction
    \f$n/d\f$ is in canonical form if and only if \f$n\f$ and \f$d\f$
    have no common factors and \f$d\f$ is positive, \f$0/1\f$ being
    the unique representation for zero.

    An undefined behavior is obtained if \p k is greater than
    or equal to the space dimension of \p *this.
  */
  bool get_lower_bound(dimension_type k, bool& closed,
		       Coefficient& n, Coefficient& d) const;

  /*! \brief
    If the <CODE>k</CODE>-th space dimension is unbounded above, returns
    <CODE>false</CODE>. Otherwise returns <CODE>true</CODE> and set
    \p closed, \p n and \p d accordingly.

    Let \f$I\f$ the interval corresponding to the <CODE>k</CODE>-th
    space dimension.  If \f$I\f$ is not bounded from above, simply return
    <CODE>false</CODE>.  Otherwise, set <CODE>closed</CODE>,
    <CODE>n</CODE> and <CODE>d</CODE> as follows: <CODE>closed</CODE>
    is set to <CODE>true</CODE> if the the upper boundary of \f$I\f$
    is closed and is set to <CODE>false</CODE> otherwise;
    <CODE>n</CODE> and <CODE>d</CODE> are assigned the integers
    \f$n\f$ and \f$d\f$ such that the canonical fraction \f$n/d\f$
    corresponds to the least upper bound of \f$I\f$.

    An undefined behavior is obtained if \p k is greater than
    or equal to the space dimension of \p *this.
  */
  bool get_upper_bound(dimension_type k, bool& closed,
		       Coefficient& n, Coefficient& d) const;

  //! Causes the box to become empty, i.e., to represent the empty set.
  void set_empty();

  /*! \brief
    Raises the lower bound of the interval corresponding
    to the <CODE>k</CODE>-th space dimension.

    Intersects the interval corresponding to the <CODE>k</CODE>-th
    space dimension
    with \f$[n/d, +\infty)\f$ if <CODE>closed</CODE> is <CODE>true</CODE>,
    with \f$(n/d, +\infty)\f$ if <CODE>closed</CODE> is <CODE>false</CODE>.
    An undefined behavior is obtained if \p k is greater than or equal to
    the space dimension of \p *this or if \p d is equal to zero.
  */
  void raise_lower_bound(dimension_type k, bool closed,
			 Coefficient_traits::const_reference n,
			 Coefficient_traits::const_reference d);

  /*! \brief
    Lowers the upper bound of the interval corresponding
    to the <CODE>k</CODE>-th space dimension.

    Intersects the interval corresponding to the <CODE>k</CODE>-th
    space dimension
    with \f$(-\infty, n/d]\f$ if <CODE>closed</CODE> is <CODE>true</CODE>,
    with \f$(-\infty, n/d)\f$ if <CODE>closed</CODE>
    is <CODE>false</CODE>.
    An undefined behavior is obtained if \p k is greater than or equal to
    the space dimension of \p *this or if \p d is equal to zero.
  */
  void lower_upper_bound(dimension_type k, bool closed,
			 Coefficient_traits::const_reference n,
			 Coefficient_traits::const_reference d);

  //! Returns a system of constraints corresponding to \p *this.
  Constraint_System constraints() const;

  /*! \brief
    Assigns to \p *this the result of computing the
    \ref CC76_extrapolation "CC76-widening" between \p *this and \p y.

    \param y
    A bounding box that <EM>must</EM> be contained in \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void CC76_widening_assign(const Bounding_Box& y);

  /*! \brief
    Assigns to \p *this the result of computing the
    \ref CC76_extrapolation "CC76-widening" between \p *this and \p y.

    \param y
    A bounding box that <EM>must</EM> be contained in \p *this.

    \param first
    An iterator that points to the first stop-point.

    \param last
    An iterator that points one past the last stop-point.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  template <typename Iterator>
  void CC76_widening_assign(const Bounding_Box& y,
			    Iterator first, Iterator last);

private:
  /*! \brief
    A vector of rational intervals, one for each dimension
    of the vector space.
  */
  std::vector<Interval> vec;
  /*! \brief
    A boolean flag indicating emptiness of the bounding box.
    Only meaningful when \p empty_up_to_date is <CODE>true</CODE>.
  */
  mutable bool empty;
  //! Tells whether or not the flag \p empty is meaningful.
  mutable bool empty_up_to_date;

  //! Records the stop points for CC76_widening_assign(const Bounding_Box&).
  static ERational default_stop_points[];
};

namespace IO_Operators {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Output operator.
/*! \relates Parma_Polyhedra_Library::Bounding_Box */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
std::ostream& operator<<(std::ostream& s, const Bounding_Box& bbox);

} // namespace IO_Operators

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Bounding_Box.inlines.hh line 1
/* Bounding_Box class implementation: inline functions.
*/


namespace Parma_Polyhedra_Library {

inline
Bounding_Box::Bounding_Box(dimension_type num_dimensions)
  : vec(num_dimensions), empty(false), empty_up_to_date(true) {
}

inline dimension_type
Bounding_Box::space_dimension() const {
  return vec.size();
}

inline const Interval&
Bounding_Box::operator[](const dimension_type k) const {
  assert(k < vec.size());
  return vec[k];
}

inline bool
Bounding_Box::is_empty() const {
  if (empty_up_to_date)
    return empty;
  else {
    empty_up_to_date = true;
    for (dimension_type k = vec.size(); k-- > 0; )
      if (vec[k].is_empty()) {
	empty = true;
	return true;
      }
    empty = false;
    return false;
  }
}

inline bool
Bounding_Box::get_lower_bound(const dimension_type k, bool& closed,
			      Coefficient& n, Coefficient& d) const {
  assert(k < vec.size());
  const LBoundary& lb = vec[k].lower_bound();
  const ERational& lr = lb.bound();

  if (is_plus_infinity(lr) || is_minus_infinity(lr))
    return false;

  closed = lb.is_closed();
  n = raw_value(lr).get_num();
  d = raw_value(lr).get_den();

  return true;
}

inline bool
Bounding_Box::get_upper_bound(const dimension_type k, bool& closed,
			     Coefficient& n, Coefficient& d) const {
  assert(k < vec.size());
  const UBoundary& ub = vec[k].upper_bound();
  const ERational& ur = ub.bound();

  if (is_plus_infinity(ur) || is_minus_infinity(ur))
    return false;

  closed = ub.is_closed();
  n = raw_value(ur).get_num();
  d = raw_value(ur).get_den();

  return true;
}

inline void
Bounding_Box::set_empty() {
  for (dimension_type k = vec.size(); k-- > 0; )
    vec[k].set_empty();
  empty = empty_up_to_date = true;
}

inline void
Bounding_Box::raise_lower_bound(const dimension_type k, const bool closed,
				Coefficient_traits::const_reference n,
				Coefficient_traits::const_reference d) {
  assert(k < vec.size());
  assert(d != 0);
  mpq_class q;
  assign_r(q.get_num(), n, ROUND_NOT_NEEDED);
  assign_r(q.get_den(), d, ROUND_NOT_NEEDED);
  q.canonicalize();
  vec[k].raise_lower_bound(LBoundary(ERational(q, ROUND_NOT_NEEDED),
				     (closed
				      ? LBoundary::CLOSED
				      : LBoundary::OPEN)));
  empty_up_to_date = false;
}

inline void
Bounding_Box::lower_upper_bound(const dimension_type k, const bool closed,
				Coefficient_traits::const_reference n,
				Coefficient_traits::const_reference d) {
  assert(k < vec.size());
  assert(d != 0);
  mpq_class q;
  assign_r(q.get_num(), n, ROUND_NOT_NEEDED);
  assign_r(q.get_den(), d, ROUND_NOT_NEEDED);
  q.canonicalize();
  vec[k].lower_upper_bound(UBoundary(ERational(q, ROUND_NOT_NEEDED),
				     (closed
				      ? UBoundary::CLOSED
				      : UBoundary::OPEN)));
  empty_up_to_date = false;
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Bounding_Box.defs.hh line 206

// Automatically generated from PPL source file ../src/Variable.defs.hh line 1
/* Variable class declaration.
*/


// Automatically generated from PPL source file ../src/Variable.defs.hh line 29
#include <iosfwd>
#include <set>

namespace Parma_Polyhedra_Library {

namespace IO_Operators {

//! Output operator.
/*! \relates Parma_Polyhedra_Library::Variable */
std::ostream&
operator<<(std::ostream& s, const Variable& v);

} // namespace IO_Operators

//! Defines a total ordering on variables.
/*! \relates Variable */
bool less(Variable v, Variable w);

} // namespace Parma_Polyhedra_Library

//! A dimension of the vector space.
/*! \ingroup PPL_CXX_interface
  An object of the class Variable represents a dimension of the space,
  that is one of the Cartesian axes.
  Variables are used as basic blocks in order to build
  more complex linear expressions.
  Each variable is identified by a non-negative integer,
  representing the index of the corresponding Cartesian axis
  (the first axis has index 0).
  The space dimension of a variable is the dimension of the vector space
  made by all the Cartesian axes having an index less than or equal to
  that of the considered variable; thus, if a variable has index \f$i\f$,
  its space dimension is \f$i+1\f$.

  Note that the ``meaning'' of an object of the class Variable
  is completely specified by the integer index provided to its
  constructor:
  be careful not to be mislead by C++ language variable names.
  For instance, in the following example the linear expressions
  <CODE>e1</CODE> and <CODE>e2</CODE> are equivalent,
  since the two variables <CODE>x</CODE> and <CODE>z</CODE> denote
  the same Cartesian axis.
  \code
  Variable x(0);
  Variable y(1);
  Variable z(0);
  Linear_Expression e1 = x + y;
  Linear_Expression e2 = y + z;
  \endcode

*/
class Parma_Polyhedra_Library::Variable {

public:
  //! Builds the variable corresponding to the Cartesian axis of index \p i.
  /*!
    \exception std::length_error
    Thrown if the <CODE>i+1</CODE> exceeds
    <CODE>Variable::max_space_dimension()</CODE>.
  */
  explicit Variable(dimension_type i);

  //! Returns the index of the Cartesian axis associated to the variable.
  dimension_type id() const;

  //! Returns the maximum space dimension a Variable can handle.
  static dimension_type max_space_dimension();

  //! Returns the dimension of the vector space enclosing \p *this.
  /*!
    The returned value is <CODE>id()+1</CODE>.
  */
  dimension_type space_dimension() const;

  //! Returns the total size in bytes of the memory occupied by \p *this.
  memory_size_type total_memory_in_bytes() const;

  //! Returns the size in bytes of the memory managed by \p *this.
  memory_size_type external_memory_in_bytes() const;

  //! Checks if all the invariants are satisfied.
  bool OK() const;

  //! Type of output functions.
  typedef void output_function_type(std::ostream& s, const Variable& v);

  //! Sets the output function to be used for printing Variable objects.
  static void set_output_function(output_function_type* p);

  //! Returns the pointer to the current output function.
  static output_function_type* get_output_function();

  //! Binary predicate defining the total ordering on variables.
  /*! \ingroup PPL_CXX_interface */
  struct Compare {
    //! Returns <CODE>true</CODE> if and only if \p x comes before \p y.
    bool operator()(Variable x, Variable y) const;
  };

private:
  //! The index of the Cartesian axis.
  dimension_type varid;

  // The initialization class needs to set the default output function.
  friend class Init;

  friend std::ostream&
  Parma_Polyhedra_Library::IO_Operators::operator<<(std::ostream& s,
						    const Variable& v);

  //! Pointer to the current output function.
  static output_function_type* current_output_function;

  //! The default output function.
  static void default_output_function(std::ostream& s, const Variable& v);
};

// Automatically generated from PPL source file ../src/Variable.inlines.hh line 1
/* Variable class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/Variable.inlines.hh line 27
#include <stdexcept>

namespace Parma_Polyhedra_Library {

inline dimension_type
Variable::max_space_dimension() {
  return not_a_dimension() - 1;
}

inline
Variable::Variable(dimension_type i)
  : varid(i < max_space_dimension()
	  ? i
	  : (throw std::length_error("PPL::Variable::Variable(i):\n"
				     "i exceeds the maximum allowed "
				     "variable identifier."), i)) {
}

inline dimension_type
Variable::id() const {
  return varid;
}

inline dimension_type
Variable::space_dimension() const {
  return varid + 1;
}

inline memory_size_type
Variable::external_memory_in_bytes() const {
  return 0;
}

inline memory_size_type
Variable::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

inline void
Variable::set_output_function(output_function_type* p) {
  current_output_function = p;
}

inline Variable::output_function_type*
Variable::get_output_function() {
  return current_output_function;
}

/*! \relates Variable */
inline bool
less(const Variable v, const Variable w) {
  return v.id() < w.id();
}

inline bool
Variable::Compare::operator()(const Variable x, const Variable y) const {
  return less(x, y);
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Variable.defs.hh line 147

namespace Parma_Polyhedra_Library {

//! An std::set containing variables in increasing order of dimension index.
/*! \ingroup PPL_CXX_interface */
typedef std::set<Variable, Variable::Compare> Variables_Set;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Init.defs.hh line 1
/* Init class declaration.
*/


// Automatically generated from PPL source file ../src/Init.defs.hh line 28

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Class for initialization and finalization.
/*! \ingroup PPL_CXX_interface
  <EM>Nifty Counter</EM> initialization class,
  ensuring that the library is initialized only once
  and before its first use.
  A count of the number of translation units using the library
  is maintained. A static object of Init type will be declared
  by each translation unit using the library.  As a result,
  only one of them will initialize and properly finalize
  the library.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS

class Parma_Polyhedra_Library::Init {
private:
  //! Count the number of objects created.
  static unsigned int count;
  static fpu_rounding_direction_type old_rounding_direction;

public:
  //! Initializes the PPL.
  Init();

  //! Finalizes the PPL.
  ~Init();
};

// Automatically generated from PPL source file ../src/initializer.hh line 1
/* Nifty counter object for the initialization of the library.
*/


// Automatically generated from PPL source file ../src/initializer.hh line 27

namespace {

Parma_Polyhedra_Library::Init Parma_Polyhedra_Library_initializer;

} // namespace

// Automatically generated from PPL source file ../src/Saturation_Matrix.defs.hh line 1
/* Saturation_Matrix class declaration.
*/


// Automatically generated from PPL source file ../src/Saturation_Matrix.defs.hh line 29
#include <vector>
#include <iosfwd>

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A saturation matrix.
/*! \ingroup PPL_CXX_interface
  A saturation matrix is used to encode the relation between the
  generators and the constraints of a polyhedron: if a generator
  saturates a constraint the corresponding element of the saturation
  matrix is \f$0\f$, otherwise (i.e., if the generator satisfies but
  does not saturate the constraint) the corresponding element is \f$1\f$.
  \note
  since the constraints and generators are taken from the same polyhedron
  description, it cannot be the case that a generator <EM>violates</EM>
  a constraint.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS

class Parma_Polyhedra_Library::Saturation_Matrix {
public:
  //! Default constructor.
  Saturation_Matrix();

  /*! \brief
    Construct a saturation matrix with \p n_rows rows
    and \p n_columns columns.
  */
  Saturation_Matrix(dimension_type n_rows, dimension_type n_columns);

  //! Copy-constructor.
  Saturation_Matrix(const Saturation_Matrix& y);

  //! Destructor.
  ~Saturation_Matrix();

  //! Assignment operator.
  Saturation_Matrix& operator=(const Saturation_Matrix& y);

  //! Swaps \p *this with \p y.
  void swap(Saturation_Matrix& y);

  //! Subscript operator.
  Saturation_Row& operator[](dimension_type k);

  //! Constant subscript operator.
  const Saturation_Row& operator[](dimension_type k) const;

  //! Clears the matrix deallocating all its rows.
  void clear();

  //! Transposes the matrix.
  void transpose();

  //! Makes \p *this a transposed copy of \p y.
  void transpose_assign(const Saturation_Matrix& y);

  //! Returns the maximum number of rows of a Saturation_Matrix.
  static dimension_type max_num_rows();

  //! Returns the number of columns of \p *this.
  dimension_type num_columns() const;

  //! Returns the number of rows of \p *this.
  dimension_type num_rows() const;

  //! Sorts the rows and removes duplicates.
  void sort_rows();

  //! Looks for \p row in \p *this, which is assumed to be sorted.
  /*!
    \return
    <CODE>true</CODE> if \p row belongs to \p *this, false otherwise.

    \param row
    The row that will be searched for in the matrix.

    Given a sorted saturation matrix (this ensures better efficiency),
    tells whether it contains the given row.
  */
  bool sorted_contains(const Saturation_Row& row) const;

  //! Adds \p row to \p *this.
  void add_row(const Saturation_Row& row);

  //! Erases the rows from the \p first_to_erase -th to the last one.
  void rows_erase_to_end(dimension_type first_to_erase);

  //! Erases the columns from the \p first_to_erase -th to the last one.
  void columns_erase_to_end(dimension_type first_to_erase);

  //! Resizes the matrix copying the old contents.
  void resize(dimension_type new_n_rows, dimension_type new_n_columns);

  //! Checks if all the invariants are satisfied.
  bool OK() const;

  PPL_OUTPUT_DECLARATIONS;

  /*! \brief
    Loads from \p s an ASCII representation (as produced by \ref ascii_dump)
    and sets \p *this accordingly.  Returns <CODE>true</CODE> if successful,
    <CODE>false</CODE> otherwise.
  */
  bool ascii_load(std::istream& s);

  //! Returns the total size in bytes of the memory occupied by \p *this.
  memory_size_type total_memory_in_bytes() const;

  //! Returns the size in bytes of the memory managed by \p *this.
  memory_size_type external_memory_in_bytes() const;

#ifndef NDEBUG
  //! Checks whether \p *this is sorted. It does NOT check for duplicates.
  bool check_sorted() const;
#endif

private:
  //! Contains the rows of the matrix.
  std::vector<Saturation_Row> rows;

  //! Size of the initialized part of each row.
  dimension_type row_size;

  //! Ordering predicate (used when implementing the sort algorithm).
  /*! \ingroup PPL_CXX_interface */
  struct Saturation_Row_Less_Than {
    bool operator()(const Saturation_Row& x, const Saturation_Row& y) const;
  };

  friend
  void Parma_Polyhedra_Library::
  Linear_System::sort_and_remove_with_sat(Saturation_Matrix& sat);

};

namespace std {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Saturation_Matrix */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
void swap(Parma_Polyhedra_Library::Saturation_Matrix& x,
	  Parma_Polyhedra_Library::Saturation_Matrix& y);

} // namespace std

// Automatically generated from PPL source file ../src/Saturation_Matrix.inlines.hh line 1
/* Saturation_Matrix class implementation: inline functions.
*/


#include <algorithm>
#include <cassert>

namespace Parma_Polyhedra_Library {

inline
Saturation_Matrix::Saturation_Matrix()
  : rows(),
    row_size(0) {
}

inline dimension_type
Saturation_Matrix::max_num_rows() {
  return std::vector<Saturation_Row>().max_size();
}

inline
Saturation_Matrix::Saturation_Matrix(const dimension_type n_rows,
		     const dimension_type n_columns)
  : rows(n_rows),
    row_size(n_columns) {
}

inline
Saturation_Matrix::Saturation_Matrix(const Saturation_Matrix& y)
  : rows(y.rows),
    row_size(y.row_size) {
}

inline
Saturation_Matrix::~Saturation_Matrix() {
}

inline void
Saturation_Matrix::rows_erase_to_end(const dimension_type first_to_erase) {
  // The first row to be erased cannot be greater
  // than the actual number of the rows of the matrix.
  assert(first_to_erase <= rows.size());
  if (first_to_erase < rows.size())
    rows.erase(rows.begin() + first_to_erase, rows.end());
  assert(OK());
}

inline void
Saturation_Matrix::columns_erase_to_end(const dimension_type first_to_erase) {
  // The first column to be erased cannot be greater
  // than the actual number of the columns of the matrix.
  assert(first_to_erase <= row_size);
  row_size = first_to_erase;
  assert(OK());
}

inline void
Saturation_Matrix::swap(Saturation_Matrix& y) {
  std::swap(row_size, y.row_size);
  std::swap(rows, y.rows);
}

inline Saturation_Row&
Saturation_Matrix::operator[](const dimension_type k) {
  assert(k < rows.size());
  return rows[k];
}

inline const Saturation_Row&
Saturation_Matrix::operator[](const dimension_type k) const {
  assert(k < rows.size());
  return rows[k];
}

inline dimension_type
Saturation_Matrix::num_columns() const {
  return row_size;
}

inline dimension_type
Saturation_Matrix::num_rows() const {
  return rows.size();
}

inline void
Saturation_Matrix::clear() {
  // Clear `rows' and minimize its capacity.
  std::vector<Saturation_Row>().swap(rows);
  row_size = 0;
}

inline memory_size_type
Saturation_Matrix::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

inline bool
Saturation_Matrix::Saturation_Row_Less_Than::
operator()(const Saturation_Row& x, const Saturation_Row& y) const {
  return compare(x, y) < 0;
}

inline bool
Saturation_Matrix::sorted_contains(const Saturation_Row& row) const {
  assert(check_sorted());
  return std::binary_search(rows.begin(), rows.end(), row,
			    Saturation_Row_Less_Than());
}

} // namespace Parma_Polyhedra_Library


namespace std {

/*! \relates Parma_Polyhedra_Library::Saturation_Matrix */
inline void
swap(Parma_Polyhedra_Library::Saturation_Matrix& x,
     Parma_Polyhedra_Library::Saturation_Matrix& y) {
  x.swap(y);
}

} // namespace std

// Automatically generated from PPL source file ../src/Saturation_Matrix.defs.hh line 176

// Automatically generated from PPL source file ../src/Generator_System.defs.hh line 1
/* Generator_System class declaration.
*/


// Automatically generated from PPL source file ../src/Poly_Con_Relation.defs.hh line 1
/* Poly_Con_Relation class declaration.
*/


// Automatically generated from PPL source file ../src/Poly_Con_Relation.defs.hh line 28
#include <iosfwd>

namespace Parma_Polyhedra_Library {

// Put them in the namespace here to declare them friend later.

//! True if and only if \p x and \p y are logically equivalent.
/*! \relates Poly_Con_Relation */
bool operator==(const Poly_Con_Relation& x, const Poly_Con_Relation& y);

//! True if and only if \p x and \p y are not logically equivalent.
/*! \relates Poly_Con_Relation */
bool operator!=(const Poly_Con_Relation& x, const Poly_Con_Relation& y);

//! Yields the logical conjunction of \p x and \p y.
/*! \relates Poly_Con_Relation */
Poly_Con_Relation operator&&(const Poly_Con_Relation& x,
			     const Poly_Con_Relation& y);

/*! \brief
  Yields the assertion with all the conjuncts of \p x
  that are not in \p y.

  \relates Poly_Con_Relation
*/
Poly_Con_Relation operator-(const Poly_Con_Relation& x,
			    const Poly_Con_Relation& y);

namespace IO_Operators {

//! Output operator.
/*! \relates Parma_Polyhedra_Library::Poly_Con_Relation */
std::ostream& operator<<(std::ostream& s, const Poly_Con_Relation& r);

} // namespace IO_Operators

} // namespace Parma_Polyhedra_Library


//! The relation between a polyhedron and a constraint.
/*! \ingroup PPL_CXX_interface
  This class implements conjunctions of assertions on the relation
  between a polyhedron and a constraint.
*/
class Parma_Polyhedra_Library::Poly_Con_Relation {
private:
  //! Poly_Con_Relation is implemented by means of a finite bitset.
  typedef unsigned int flags_t;

  //! \name Bit-masks for the individual assertions
  //@{
  static const flags_t NOTHING             = 0U;
  static const flags_t IS_DISJOINT         = 1U << 0;
  static const flags_t STRICTLY_INTERSECTS = 1U << 1;
  static const flags_t IS_INCLUDED         = 1U << 2;
  static const flags_t SATURATES           = 1U << 3;
  //@} // Bit-masks for the individual assertions

  //! All assertions together.
  static const flags_t EVERYTHING
  = IS_DISJOINT
  | STRICTLY_INTERSECTS
  | IS_INCLUDED
  | SATURATES;

  //! This holds the current bitset.
  flags_t flags;

  //! True if and only if the conjunction \p x implies the conjunction \p y.
  static bool implies(flags_t x, flags_t y);

  //! Construct from a bit-mask.
  Poly_Con_Relation(flags_t mask);

  friend bool
  Parma_Polyhedra_Library::operator==(const Poly_Con_Relation& x,
				      const Poly_Con_Relation& y);

  friend bool
  Parma_Polyhedra_Library::operator!=(const Poly_Con_Relation& x,
				      const Poly_Con_Relation& y);

  friend Poly_Con_Relation
  Parma_Polyhedra_Library::operator&&(const Poly_Con_Relation& x,
				      const Poly_Con_Relation& y);

  friend Poly_Con_Relation
  Parma_Polyhedra_Library::operator-(const Poly_Con_Relation& x,
				     const Poly_Con_Relation& y);

  friend std::ostream&
  Parma_Polyhedra_Library::
  IO_Operators::operator<<(std::ostream& s, const Poly_Con_Relation& r);

public:
#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Access the internal flags: this is needed for some foreign
    language interfaces.
  */
#endif
  flags_t get_flags() const;

public:
  //! The assertion that says nothing.
  static Poly_Con_Relation nothing();

  /*! \brief
    The polyhedron and the set of points satisfying
    the constraint are disjoint.
  */
  static Poly_Con_Relation is_disjoint();

  /*! \brief
    The polyhedron intersects the set of points satisfying
    the constraint, but it is not included in it.
  */
  static Poly_Con_Relation strictly_intersects();

  /*! \brief
    The polyhedron is included in the set of points satisfying
    the constraint.
  */
  static Poly_Con_Relation is_included();

  /*! \brief
    The polyhedron is included in the set of points saturating
    the constraint.
  */
  static Poly_Con_Relation saturates();

  PPL_OUTPUT_DECLARATIONS;

  //! True if and only if \p *this implies \p y.
  bool implies(const Poly_Con_Relation& y) const;

  //! Checks if all the invariants are satisfied.
  bool OK() const;
};

// Automatically generated from PPL source file ../src/Poly_Con_Relation.inlines.hh line 1
/* Poly_Con_Relation class implementation: inline functions.
*/


namespace Parma_Polyhedra_Library {

inline
Poly_Con_Relation::Poly_Con_Relation(flags_t mask)
  : flags(mask) {
}

inline Poly_Con_Relation::flags_t
Poly_Con_Relation::get_flags() const {
  return flags;
}

inline Poly_Con_Relation
Poly_Con_Relation::nothing() {
  return Poly_Con_Relation(NOTHING);
}

inline Poly_Con_Relation
Poly_Con_Relation::is_disjoint() {
  return Poly_Con_Relation(IS_DISJOINT);
}

inline Poly_Con_Relation
Poly_Con_Relation::strictly_intersects() {
  return Poly_Con_Relation(STRICTLY_INTERSECTS);
}

inline Poly_Con_Relation
Poly_Con_Relation::is_included() {
  return Poly_Con_Relation(IS_INCLUDED);
}

inline Poly_Con_Relation
Poly_Con_Relation::saturates() {
  return Poly_Con_Relation(SATURATES);
}

inline bool
Poly_Con_Relation::implies(flags_t x, flags_t y) {
  return (x & y) == y;
}

inline bool
Poly_Con_Relation::implies(const Poly_Con_Relation& y) const {
  return implies(flags, y.flags);
}

/*! \relates Poly_Con_Relation */
inline bool
operator==(const Poly_Con_Relation& x, const Poly_Con_Relation& y) {
  return x.flags == y.flags;
}

/*! \relates Poly_Con_Relation */
inline bool
operator!=(const Poly_Con_Relation& x, const Poly_Con_Relation& y) {
  return x.flags != y.flags;
}

/*! \relates Poly_Con_Relation */
inline Poly_Con_Relation
operator&&(const Poly_Con_Relation& x, const Poly_Con_Relation& y) {
  return Poly_Con_Relation(x.flags | y.flags);
}

/*! \relates Poly_Con_Relation */
inline Poly_Con_Relation
operator-(const Poly_Con_Relation& x, const Poly_Con_Relation& y) {
  return Poly_Con_Relation(x.flags & ~y.flags);
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Poly_Con_Relation.defs.hh line 169

// Automatically generated from PPL source file ../src/Generator_System.defs.hh line 35
#include <iosfwd>

namespace Parma_Polyhedra_Library {

namespace IO_Operators {

//! Output operator.
/*!
  \relates Parma_Polyhedra_Library::Generator_System
  Writes <CODE>false</CODE> if \p gs is empty.  Otherwise, writes on
  \p s the generators of \p gs, all in one row and separated by ", ".
*/
std::ostream& operator<<(std::ostream& s, const Generator_System& gs);

} // namespace IO_Operators

// Put it in the namespace here to declare it friend later.
/*! \relates Polyhedron */
bool operator==(const Polyhedron& x, const Polyhedron& y);

} // namespace Parma_Polyhedra_Library


namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Generator_System */
void swap(Parma_Polyhedra_Library::Generator_System& x,
	  Parma_Polyhedra_Library::Generator_System& y);

} // namespace std

//! A system of generators.
/*! \ingroup PPL_CXX_interface
    An object of the class Generator_System is a system of generators,
    i.e., a multiset of objects of the class Generator
    (lines, rays, points and closure points).
    When inserting generators in a system, space dimensions are automatically
    adjusted so that all the generators in the system are defined
    on the same vector space.
    A system of generators which is meant to define a non-empty
    polyhedron must include at least one point: the reason is that
    lines, rays and closure points need a supporting point
    (lines and rays only specify directions while closure points only
    specify points in the topological closure of the NNC polyhedron).

    \par
     In all the examples it is assumed that variables
    <CODE>x</CODE> and <CODE>y</CODE> are defined as follows:
    \code
  Variable x(0);
  Variable y(1);
    \endcode

    \par Example 1
    The following code defines the line having the same direction
    as the \f$x\f$ axis (i.e., the first Cartesian axis)
    in \f$\Rset^2\f$:
    \code
  Generator_System gs;
  gs.insert(line(x + 0*y));
    \endcode
    As said above, this system of generators corresponds to
    an empty polyhedron, because the line has no supporting point.
    To define a system of generators that does correspond to
    the \f$x\f$ axis, we can add the following code which
    inserts the origin of the space as a point:
    \code
  gs.insert(point(0*x + 0*y));
    \endcode
    Since space dimensions are automatically adjusted, the following
    code obtains the same effect:
    \code
  gs.insert(point(0*x));
    \endcode
    In contrast, if we had added the following code, we would have
    defined a line parallel to the \f$x\f$ axis through
    the point \f$(0, 1)^\transpose \in \Rset^2\f$.
    \code
  gs.insert(point(0*x + 1*y));
    \endcode

    \par Example 2
    The following code builds a ray having the same direction as
    the positive part of the \f$x\f$ axis in \f$\Rset^2\f$:
    \code
  Generator_System gs;
  gs.insert(ray(x + 0*y));
    \endcode
    To define a system of generators indeed corresponding to the set
    \f[
      \bigl\{\,
        (x, 0)^\transpose \in \Rset^2
      \bigm|
        x \geq 0
      \,\bigr\},
    \f]
    one just has to add the origin:
    \code
  gs.insert(point(0*x + 0*y));
    \endcode

    \par Example 3
    The following code builds a system of generators having four points
    and corresponding to a square in \f$\Rset^2\f$
    (the same as Example 1 for the system of constraints):
    \code
  Generator_System gs;
  gs.insert(point(0*x + 0*y));
  gs.insert(point(0*x + 3*y));
  gs.insert(point(3*x + 0*y));
  gs.insert(point(3*x + 3*y));
    \endcode

    \par Example 4
    By using closure points, we can define the \e kernel
    (i.e., the largest open set included in a given set)
    of the square defined in the previous example.
    Note that a supporting point is needed and, for that purpose,
    any inner point could be considered.
    \code
  Generator_System gs;
  gs.insert(point(x + y));
  gs.insert(closure_point(0*x + 0*y));
  gs.insert(closure_point(0*x + 3*y));
  gs.insert(closure_point(3*x + 0*y));
  gs.insert(closure_point(3*x + 3*y));
    \endcode

    \par Example 5
    The following code builds a system of generators having two points
    and a ray, corresponding to a half-strip in \f$\Rset^2\f$
    (the same as Example 2 for the system of constraints):
    \code
  Generator_System gs;
  gs.insert(point(0*x + 0*y));
  gs.insert(point(0*x + 1*y));
  gs.insert(ray(x - y));
    \endcode

    \note
    After inserting a multiset of generators in a generator system,
    there are no guarantees that an <EM>exact</EM> copy of them
    can be retrieved:
    in general, only an <EM>equivalent</EM> generator system
    will be available, where original generators may have been
    reordered, removed (if they are duplicate or redundant), etc.
*/
class Parma_Polyhedra_Library::Generator_System : private Linear_System {
public:
  //! Default constructor: builds an empty system of generators.
  Generator_System();

  //! Builds the singleton system containing only generator \p g.
  explicit Generator_System(const Generator& g);

  //! Ordinary copy-constructor.
  Generator_System(const Generator_System& gs);

  //! Destructor.
  ~Generator_System();

  //! Assignment operator.
  Generator_System& operator=(const Generator_System& y);

  //! Returns the maximum space dimension a Generator_System can handle.
  static dimension_type max_space_dimension();

  //! Returns the dimension of the vector space enclosing \p *this.
  dimension_type space_dimension() const;

  /*! \brief
    Removes all the generators from the generator system
    and sets its space dimension to 0.
  */
  void clear();

  /*! \brief
    Inserts in \p *this a copy of the generator \p g,
    increasing the number of space dimensions if needed.
  */
  void insert(const Generator& g);

  /*! \brief
    Returns the singleton system containing only
    Generator::zero_dim_point().
  */
  static const Generator_System& zero_dim_univ();

  //! An iterator over a system of generators
  /*! \ingroup PPL_CXX_interface
      A const_iterator is used to provide read-only access
      to each generator contained in an object of Generator_System.

      \par Example
      The following code prints the system of generators
      of the polyhedron <CODE>ph</CODE>:
      \code
  const Generator_System& gs = ph.generators();
  for (Generator_System::const_iterator i = gs.begin(),
         gs_end = gs.end(); i != gs_end; ++i)
    cout << *i << endl;
      \endcode
      The same effect can be obtained more concisely by using
      more features of the STL:
      \code
  const Generator_System& gs = ph.generators();
  copy(gs.begin(), gs.end(), ostream_iterator<Generator>(cout, "\n"));
      \endcode
  */
  class const_iterator
    : public std::iterator<std::forward_iterator_tag,
			   Generator,
			   ptrdiff_t,
			   const Generator*,
			   const Generator&> {
  public:
    //! Default constructor.
    const_iterator();

    //! Ordinary copy-constructor.
    const_iterator(const const_iterator& y);

    //! Destructor.
    ~const_iterator();

    //! Assignment operator.
    const_iterator& operator=(const const_iterator& y);

    //! Dereference operator.
    const Generator& operator*() const;

    //! Indirect member selector.
    const Generator* operator->() const;

    //! Prefix increment operator.
    const_iterator& operator++();

    //! Postfix increment operator.
    const_iterator operator++(int);

    /*! \brief
      Returns <CODE>true</CODE> if and only if
      \p *this and \p y are identical.
    */
    bool operator==(const const_iterator& y) const;

    /*! \brief
      Returns <CODE>true</CODE> if and only if
      \p *this and \p y are different.
    */
    bool operator!=(const const_iterator& y) const;

  private:
    friend class Generator_System;

    //! The const iterator over the Linear_System.
    Linear_System::const_iterator i;

    //! A const pointer to the Linear_System.
    const Linear_System* gsp;

    //! Constructor.
    const_iterator(const Linear_System::const_iterator& iter,
		   const Generator_System& gsys);

    /*! \brief
      \p *this skips to the next generator, skipping those
      closure points that are immediately followed by a matching point.
    */
    void skip_forward();
  };

  /*! \brief
    Returns the const_iterator pointing to the first generator,
    if \p *this is not empty;
    otherwise, returns the past-the-end const_iterator.
  */
  const_iterator begin() const;

  //! Returns the past-the-end const_iterator.
  const_iterator end() const;

  //! Checks if all the invariants are satisfied.
  /*!
    Returns <CODE>true</CODE> if and only if \p *this is a valid
    Linear_System and each row in the system is a valid Generator.
  */
  bool OK() const;

  PPL_OUTPUT_DECLARATIONS;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    \ref ascii_dump) and sets \p *this accordingly.
    Returns <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise.

    Resizes the matrix of generators using the numbers of rows and columns
    read from \p s, then initializes the coordinates of each generator
    and its type reading the contents from \p s.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  bool ascii_load(std::istream& s);

  //! Returns the total size in bytes of the memory occupied by \p *this.
  memory_size_type total_memory_in_bytes() const;

  //! Returns the size in bytes of the memory managed by \p *this.
  memory_size_type external_memory_in_bytes() const;

  //! Swaps \p *this with \p y.
  void swap(Generator_System& y);

private:
  friend class const_iterator;
  friend class Parma_Polyhedra_Library::Polyhedron;
  friend class Parma_Polyhedra_Library::Grid_Generator_System;

  friend bool
  Parma_Polyhedra_Library::operator==(const Polyhedron& x,
				      const Polyhedron& y);

  //! Builds an empty system of generators having the specified topology.
  explicit Generator_System(Topology topol);

  /*! \brief
    Builds a system of \p n_rows rays/points on a \p n_columns - 1
    dimensional space (including the \f$\epsilon\f$ dimension, if
    \p topol is <CODE>NOT_NECESSARILY_CLOSED</CODE>).
  */
  Generator_System(Topology topol,
		   dimension_type n_rows, dimension_type n_columns);

  /*! \brief
    Adjusts \p *this so that it matches the topology and
    the number of space dimensions given as parameters
    (adding or removing columns if needed).
    Returns <CODE>false</CODE> if and only if \p topol is
    equal to <CODE>NECESSARILY_CLOSED</CODE> and \p *this
    contains closure points.
  */
  bool adjust_topology_and_space_dimension(Topology topol,
					   dimension_type num_dimensions);

  /*! \brief
    For each unmatched closure point in \p *this, adds the
    corresponding point.

    It is assumed that the topology of \p *this
    is <CODE>NOT_NECESSARILY_CLOSED</CODE>.
  */
  void add_corresponding_points();

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this
    contains one or more points.
  */
  bool has_points() const;

  /*! \brief
    For each unmatched point in \p *this, adds the corresponding
    closure point.

    It is assumed that the topology of \p *this
    is <CODE>NOT_NECESSARILY_CLOSED</CODE>.
  */
  void add_corresponding_closure_points();

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this
    contains one or more closure points.

    Note: the check for the presence of closure points is
    done under the point of view of the user. Namely, we scan
    the generator system using high-level iterators, so that
    closure points that are matching the corresponding points
    will be disregarded.
  */
  bool has_closure_points() const;

  //! Returns the \p k- th generator of the system.
  Generator& operator[](dimension_type k);

  //! Returns a constant reference to the \p k- th generator of the system.
  const Generator& operator[](dimension_type k) const;

  /*! \brief
    Returns the relations holding between the generator system
    and the constraint \p c.
  */
  Parma_Polyhedra_Library::Poly_Con_Relation
  relation_with(const Constraint& c) const;

  //! Returns <CODE>true</CODE> if all the generators satisfy \p c.
  bool satisfied_by_all_generators(const Constraint& c) const;

  //! Returns <CODE>true</CODE> if all the generators satisfy \p c.
  /*!
    It is assumed that <CODE>c.is_necessarily_closed()</CODE> holds.
  */
  bool satisfied_by_all_generators_C(const Constraint& c) const;

  //! Returns <CODE>true</CODE> if all the generators satisfy \p c.
  /*!
    It is assumed that <CODE>c.is_necessarily_closed()</CODE> does not hold.
  */
  bool satisfied_by_all_generators_NNC(const Constraint& c) const;

  //! Assigns to a given variable an affine expression.
  /*!
    \param v
    Index of the column to which the affine transformation is assigned;

    \param expr
    The numerator of the affine transformation:
    \f$\sum_{i = 0}^{n - 1} a_i x_i + b\f$;

    \param denominator
    The denominator of the affine transformation.

    We want to allow affine transformations (see the Introduction) having
    any rational coefficients. Since the coefficients of the
    constraints are integers we must also provide an integer \p denominator
    that will be used as denominator of the affine transformation.
    The denominator is required to be a positive integer.

    The affine transformation assigns to each element of \p v -th
    column the follow expression:
    \f[
      \frac{\sum_{i = 0}^{n - 1} a_i x_i + b}
           {\mathrm{denominator}}.
    \f]

    \p expr is a constant parameter and unaltered by this computation.
  */
  void affine_image(dimension_type v,
		    const Linear_Expression& expr,
		    Coefficient_traits::const_reference denominator);

  //! Returns the number of lines of the system.
  dimension_type num_lines() const;

  //! Returns the number of rays of the system.
  dimension_type num_rays() const;

  //! Removes all the invalid lines and rays.
  /*!
    The invalid lines and rays are those with all
    the homogeneous terms set to zero.
  */
  void remove_invalid_lines_and_rays();

  /*! \brief
    Applies Gaussian's elimination and back-substitution so as
    to provide a partial simplification of the system of generators.

    It is assumed that the system has no pending generators.
  */
  void simplify();

  /*! \brief
    Inserts in \p *this a copy of the generator \p g,
    increasing the number of space dimensions if needed.
    It is a pending generator.
  */
  void insert_pending(const Generator& g);
};

// Generator_System.inlines.hh is not included here on purpose.

// Automatically generated from PPL source file ../src/Grid_Generator_System.defs.hh line 1
/* Grid_Generator_System class declaration.
*/


// Automatically generated from PPL source file ../src/Grid_Generator_System.defs.hh line 30
#include <iosfwd>

namespace Parma_Polyhedra_Library {

namespace IO_Operators {

//! Output operator.
/*!
  \relates Parma_Polyhedra_Library::Grid_Generator_System
  Writes <CODE>false</CODE> if \p gs is empty.  Otherwise, writes on
  \p s the generators of \p gs, all in one row and separated by ", ".
*/
std::ostream& operator<<(std::ostream& s, const Grid_Generator_System& gs);

} // namespace IO_Operators

//! Returns <CODE>true</CODE> if and only if \p x and \p y are identical.
/*! \relates Grid_Generator_System */
bool operator==(const Grid_Generator_System& x,
		const Grid_Generator_System& y);

} // namespace Parma_Polyhedra_Library

namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Grid_Generator_System */
void swap(Parma_Polyhedra_Library::Grid_Generator_System& x,
	  Parma_Polyhedra_Library::Grid_Generator_System& y);

} // namespace std


//! A system of grid generators.
/*! \ingroup PPL_CXX_interface
    An object of the class Grid_Generator_System is a system of
    grid generators, i.e., a multiset of objects of the class
    Grid_Generator (lines, parameters and points).
    When inserting generators in a system, space dimensions are
    automatically adjusted so that all the generators in the system
    are defined on the same vector space.
    A system of grid generators which is meant to define a non-empty
    grid must include at least one point: the reason is that
    lines and parameters need a supporting point
    (lines only specify directions while parameters only
    specify direction and distance.

    \par
     In all the examples it is assumed that variables
    <CODE>x</CODE> and <CODE>y</CODE> are defined as follows:
    \code
  Variable x(0);
  Variable y(1);
    \endcode

    \par Example 1
    The following code defines the line having the same direction
    as the \f$x\f$ axis (i.e., the first Cartesian axis)
    in \f$\Rset^2\f$:
    \code
  Grid_Generator_System gs;
  gs.insert(grid_line(x + 0*y));
    \endcode
    As said above, this system of generators corresponds to
    an empty grid, because the line has no supporting point.
    To define a system of generators that does correspond to
    the \f$x\f$ axis, we can add the following code which
    inserts the origin of the space as a point:
    \code
  gs.insert(grid_point(0*x + 0*y));
    \endcode
    Since space dimensions are automatically adjusted, the following
    code obtains the same effect:
    \code
  gs.insert(grid_point(0*x));
    \endcode
    In contrast, if we had added the following code, we would have
    defined a line parallel to the \f$x\f$ axis through
    the point \f$(0, 1)^\transpose \in \Rset^2\f$.
    \code
  gs.insert(grid_point(0*x + 1*y));
    \endcode

    \par Example 2
    The following code builds a system of generators corresponding
    to the grid consisting of all the integral points on the \f$x\f$ axes;
    that is, all points satisfying the congruence relation
    \f[
      \bigl\{\,
        (x, 0)^\transpose \in \Rset^2
      \bigm|
        x \pmod{1}\ 0
      \,\bigr\},
    \f]
    \code
  Grid_Generator_System gs;
  gs.insert(parameter(x + 0*y));
  gs.insert(grid_point(0*x + 0*y));
    \endcode

    \par Example 3
    The following code builds a system of generators having three points
    corresponding to a non-relational grid consisting of all points
    whose coordinates are integer multiple of 3.
    \code
  Grid_Generator_System gs;
  gs.insert(grid_point(0*x + 0*y));
  gs.insert(grid_point(0*x + 3*y));
  gs.insert(grid_point(3*x + 0*y));
    \endcode

    \par Example 4
    By using parameters instead of two of the points we
    can define the same grid as that defined in the previous example.
    Note that there has to be at least one point and, for this purpose,
    any point in the grid could be considered.
    Thus the following code builds two identical grids from the
    grid generator systems \p gs and \p gs1.
    \code
  Grid_Generator_System gs;
  gs.insert(grid_point(0*x + 0*y));
  gs.insert(parameter(0*x + 3*y));
  gs.insert(parameter(3*x + 0*y));
  Grid_Generator_System gs1;
  gs1.insert(grid_point(3*x + 3*y));
  gs1.insert(parameter(0*x + 3*y));
  gs1.insert(parameter(3*x + 0*y));
    \endcode

    \par Example 5
    The following code builds a system of generators having one point and
    a parameter corresponding to all the integral points that
    lie on \f$x + y = 2\f$ in \f$\Rset^2\f$
    \code
  Grid_Generator_System gs;
  gs.insert(grid_point(1*x + 1*y));
  gs.insert(parameter(1*x - 1*y));
    \endcode

    \note
    After inserting a multiset of generators in a grid generator system,
    there are no guarantees that an <EM>exact</EM> copy of them
    can be retrieved:
    in general, only an <EM>equivalent</EM> grid generator system
    will be available, where original generators may have been
    reordered, removed (if they are duplicate or redundant), etc.
*/
class Parma_Polyhedra_Library::Grid_Generator_System
  : private Generator_System {
public:
  // FIXME: Add wrappers of any other public Generator_System methods.

  //! Default constructor: builds an empty system of generators.
  Grid_Generator_System();

  //! Ordinary copy-constructor.
  Grid_Generator_System(const Grid_Generator_System& gs);

  //! Builds an empty system of generators of dimension \p dim.
  explicit Grid_Generator_System(dimension_type dim);

  //! Builds the singleton system containing only generator \p g.
  explicit Grid_Generator_System(const Grid_Generator& g);

  //! Returns the maximum space dimension a Grid_Generator_System can handle.
  static dimension_type max_space_dimension();

  //! Returns the dimension of the vector space enclosing \p *this.
  dimension_type space_dimension() const;

  /*! \brief
    Removes all the generators from the generator system and sets its
    space dimension to 0.
  */
  void clear();

  /*! \brief
    Inserts into \p *this a copy of the generator \p g, increasing the
    number of space dimensions if needed.

    If \p g is an all-zero parameter then the only action is to ensure
    that the space dimension of \p *this is at least the space
    dimension of \p g.
  */
  void insert(const Grid_Generator& g);

  /*! \brief
    Inserts into \p *this the generator \p g, increasing the number of
    space dimensions if needed.
  */
  void recycling_insert(Grid_Generator& g);

  /*! \brief
    Inserts into \p *this the generators in \p gs, increasing the
    number of space dimensions if needed.
  */
  void recycling_insert(Grid_Generator_System& gs);

  //! An iterator over a system of grid generators
  /*! \ingroup PPL_CXX_interface
    A const_iterator is used to provide read-only access
    to each generator contained in an object of Grid_Generator_System.

    \par Example
    The following code prints the system of generators
    of the grid <CODE>gr</CODE>:
    \code
  const Grid_Generator_System& gs = gr.generators();
  for (Grid_Generator_System::const_iterator i = gs.begin(),
        gs_end = gs.end(); i != gs_end; ++i)
    cout << *i << endl;
    \endcode
    The same effect can be obtained more concisely by using
    more features of the STL:
    \code
  const Generator_System& gs = gr.generators();
  copy(gs.begin(), gs.end(), ostream_iterator<Grid_Generator>(cout, "\n"));
    \endcode
  */
  class const_iterator
    : public std::iterator<std::forward_iterator_tag,
			   Grid_Generator,
			   ptrdiff_t,
			   const Grid_Generator*,
			   const Grid_Generator&>,
      private Generator_System::const_iterator {
  public:
    //! Default constructor.
    const_iterator();

    //! Ordinary copy-constructor.
    const_iterator(const const_iterator& y);

    //! Destructor.
    ~const_iterator();

    //! Assignment operator.
    const_iterator& operator=(const const_iterator& y);

    //! Dereference operator.
    const Grid_Generator& operator*() const;

    //! Indirect member selector.
    const Grid_Generator* operator->() const;

    //! Prefix increment operator.
    const_iterator& operator++();

    //! Postfix increment operator.
    const_iterator operator++(int);

    /*! \brief
      Returns <CODE>true</CODE> if and only if \p *this and \p y are
      identical.
    */
    bool operator==(const const_iterator& y) const;

    /*! \brief
      Returns <CODE>true</CODE> if and only if \p *this and \p y are
      different.
    */
    bool operator!=(const const_iterator& y) const;

  private:
    friend class Grid_Generator_System;

    //! Copy-constructor from Generator_System::const_iterator.
    const_iterator(const Generator_System::const_iterator& y);
  };

  /*! \brief
    Returns the const_iterator pointing to the first generator, if \p
    *this is not empty; otherwise, returns the past-the-end
    const_iterator.
  */
  const_iterator begin() const;

  //! Returns the past-the-end const_iterator.
  const_iterator end() const;

  //! Swaps \p *this with \p y.
  void swap(Grid_Generator_System& y);

  //! Returns the size in bytes of the memory managed by \p *this.
  memory_size_type external_memory_in_bytes() const;

  //! Returns the total size in bytes of the memory occupied by \p *this.
  memory_size_type total_memory_in_bytes() const;

  //! Assigns to a given variable an affine expression.
  /*!
    \param v
    Index of the column to which the affine transformation is assigned;

    \param expr
    The numerator of the affine transformation:
    \f$\sum_{i = 0}^{n - 1} a_i x_i + b\f$;

    \param denominator
    The denominator of the affine transformation;

    We allow affine transformations (see the Section \ref
    rational_grid_operations)to have rational
    coefficients. Since the coefficients of linear expressions are
    integers we also provide an integer \p denominator that will
    be used as denominator of the affine transformation.  The
    denominator is required to be a positive integer and its
    default value is 1.

    The affine transformation assigns to each element of \p v -th
    column the follow expression:
    \f[
      \frac{\sum_{i = 0}^{n - 1} a_i x_i + b}
           {\mathrm{denominator}}.
    \f]

    \p expr is a constant parameter and unaltered by this computation.
  */
  void affine_image(dimension_type v,
		    const Linear_Expression& expr,
		    Coefficient_traits::const_reference denominator);

  //! Returns the number of generators in the system.
  dimension_type num_generators() const;

  //! Returns the number of parameters in the system.
  dimension_type num_parameters() const;

  //! Returns the number of lines in the system.
  dimension_type num_lines() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this contains one or
    more points.
  */
  bool has_points() const;

  //! Returns <CODE>true</CODE> if \p *this is identical to \p y.
  bool is_equal_to(const Grid_Generator_System y) const;

  //! Returns the \p k- th generator of the system.
  Grid_Generator& operator[](dimension_type k);

  //! Returns a constant reference to the \p k- th generator of the system.
  const Grid_Generator& operator[](dimension_type k) const;

  PPL_OUTPUT_DECLARATIONS;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Loads from \p s an ASCII representation (as produced by \ref
    ascii_dump) and sets \p *this accordingly.  Returns
    <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise.

    Resizes the matrix of generators using the numbers of rows and columns
    read from \p s, then initializes the coordinates of each generator
    and its type reading the contents from \p s.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  bool ascii_load(std::istream& s);

  //! Checks if all the invariants are satisfied.
  /*!
    Returns <CODE>true</CODE> if and only if \p *this is a valid
    Linear_System and each row in the system is a valid Grid_Generator.
  */
  bool OK() const;

  /*! \brief
    Adds \p dims rows and \p dims columns of zeroes to the matrix,
    initializing the added rows as in the universe system.

    \param dims
    The number of rows and columns to be added: must be strictly
    positive.

    Turns the \f$r \times c\f$ matrix \f$A\f$ into the \f$(r+dims)
    \times (c+dims)\f$ matrix \f$\bigl({A \atop 0}{0 \atop B}\bigr)\f$
    where \f$B\f$ is the \f$dims \times dims\f$ unit matrix of the
    form \f$\bigl({1 \atop 0}{0 \atop 1}\bigr)\f$.  The matrix is
    expanded avoiding reallocation whenever possible.
  */
  void add_universe_rows_and_columns(dimension_type dims);

  //! Removes all the specified dimensions from the generator system.
  /*!
    \exception std::invalid_argument
    Thrown if the highest space dimension of the variables in \p
    to_be_removed is higher than the space dimension of \p *this.
  */
  void remove_space_dimensions(const Variables_Set& to_be_removed);

  /*! \brief
    Removes the higher dimensions of the system so that the resulting
    system will have dimension \p new_dimension.

    \exception std::invalid_argument
    Thrown if the \p new_dimension is higher than the space dimension
    of \p *this.
  */
  void remove_higher_space_dimensions(dimension_type new_dimension);

private:
  friend bool operator==(const Grid_Generator_System& x,
			 const Grid_Generator_System& y);
  // FIXME: The following friend declaration grants Grid::conversion
  //        access to Matrix (for the Grid::reduce_reduced call) and
  //        Matrix::resize_no_copy, and the following methods.
  friend class Grid;

  //! Sets the sortedness flag of the system to \p b.
  void set_sorted(bool b);

  //! Sets the index to indicate that the system has no pending rows.
  void unset_pending_rows();

  //! Sets the index of the first pending row to \p i.
  void set_index_first_pending_row(dimension_type i);

  //! Resizes the system without worrying about the old contents.
  /*!
    \param new_n_rows
    The number of rows of the resized system;

    \param new_n_columns
    The number of columns of the resized system.

    The system is expanded to the specified dimensions avoiding
    reallocation whenever possible.
    The contents of the original system is lost.
  */
  void resize_no_copy(dimension_type new_n_rows,
		      dimension_type new_n_columns);

  /*! \brief
    Returns the number of columns of the matrix (i.e., the size of the
    rows).
  */
  dimension_type num_columns() const;

  /*! \brief
    Erases from the matrix all the rows but those having an index less
    than \p first_to_erase.
  */
  void erase_to_end(dimension_type first_to_erase);

  //! Permutes the columns of the matrix.
  /*
    \param cycles
    A vector representing the non-trivial cycles of the permutation
    according to which the columns must be rearranged.

    The \p cycles vector contains, one after the other, the
    non-trivial cycles (i.e., the cycles of length greater than one)
    of a permutation of non-zero column indexes.  Each cycle is
    terminated by zero.  For example, assuming the matrix has 6
    columns, the permutation \f$ \{ 1 \mapsto 3, 2 \mapsto 4,
    3 \mapsto 6, 4 \mapsto 2, 5 \mapsto 5, 6 \mapsto 1 \}\f$ can be
    represented by the non-trivial cycles \f$(1 3 6)(2 4)\f$ that, in
    turn can be represented by a vector of 6 elements containing 1, 3,
    6, 0, 2, 4, 0.
  */
  void permute_columns(const std::vector<dimension_type>& cycles);
};

// Grid_Generator_System.inlines.hh is not included here on purpose.

// Automatically generated from PPL source file ../src/Congruence_System.defs.hh line 1
/* Congruence_System class declaration.
*/


// Automatically generated from PPL source file ../src/Congruence_System.defs.hh line 33
#include <iosfwd>

namespace Parma_Polyhedra_Library {

namespace IO_Operators {

//! Output operator.
/*!
  \relates Parma_Polyhedra_Library::Congruence_System
  Writes <CODE>true</CODE> if \p cgs is empty.  Otherwise, writes on
  \p s the congruences of \p cgs, all in one row and separated by ", ".
*/
std::ostream&
operator<<(std::ostream& s, const Congruence_System& cgs);

} // namespace IO_Operators

// Put this in the namespace here to declare it a friend later.

//! Returns <CODE>true</CODE> if and only if \p x and \p y are equivalent.
/*! \relates Congruence_System */
bool
operator==(const Congruence_System& x, const Congruence_System& y);

} // namespace Parma_Polyhedra_Library


namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Congruence_System */
void
swap(Parma_Polyhedra_Library::Congruence_System& x,
     Parma_Polyhedra_Library::Congruence_System& y);

} // namespace std

//! A system of congruences.
/*! \ingroup PPL_CXX_interface
    An object of the class Congruence_System is a system of congruences,
    i.e., a multiset of objects of the class Congruence.
    When inserting congruences in a system, space dimensions are
    automatically adjusted so that all the congruences in the system
    are defined on the same vector space.

    \par
    In all the examples it is assumed that variables
    <CODE>x</CODE> and <CODE>y</CODE> are defined as follows:
    \code
  Variable x(0);
  Variable y(1);
    \endcode

    \par Example 1
    The following code builds a system of congruences corresponding to
    an integer grid in \f$\Rset^2\f$:
    \code
  Congruence_System cgs;
  cgs.insert(x %= 0);
  cgs.insert(y %= 0);
    \endcode
    Note that:
    the congruence system is created with space dimension zero;
    the first and second congruence insertions increase the space
    dimension to \f$1\f$ and \f$2\f$, respectively.

    \par Example 2
    By adding to the congruence system of the previous example,
    the congruence \f$x + y = 1 \pmod{2}\f$:
    \code
  cgs.insert((x + y %= 1) / 2);
    \endcode
    we obtain the grid containing just those integral
    points where the sum of the \p x and \p y values is odd.

    \par Example 3
    The following code builds a system of congruences corresponding to
    the grid in \f$\Zset^2\f$ containing just the integral points on
    the \p x axis:
    \code
  Congruence_System cgs;
  cgs.insert(x %= 0);
  cgs.insert((y %= 0) / 0);
    \endcode

    \note
    After inserting a multiset of congruences in a congruence system,
    there are no guarantees that an <EM>exact</EM> copy of them
    can be retrieved:
    in general, only an <EM>equivalent</EM> congruence system
    will be available, where original congruences may have been
    reordered, removed (if they are trivial, duplicate or
    implied by other congruences), linearly combined, etc.
*/
class Parma_Polyhedra_Library::Congruence_System : private Matrix {
public:
  //! Default constructor: builds an empty system of congruences.
  Congruence_System();

  //! Builds the singleton system containing only congruence \p cg.
  explicit Congruence_System(const Congruence& cg);

  /*! \brief
    If \p c represents the constraint \f$ e_1 = e_2 \f$, builds the
    singleton system containing only constraint \f$ e_1 = e_2
    \pmod{0}\f$.

    \exception std::invalid_argument
    Thrown if \p c is not an equality constraint.
  */
  explicit Congruence_System(const Constraint& c);

  //! Builds a system containing copies of any equalities in \p cs.
  explicit Congruence_System(const Constraint_System& cs);

  //! Ordinary copy-constructor.
  Congruence_System(const Congruence_System& cgs);

  //! Destructor.
  ~Congruence_System();

  //! Assignment operator.
  Congruence_System& operator=(const Congruence_System& cgs);

  //! Returns the maximum space dimension a Congruence_System can handle.
  static dimension_type max_space_dimension();

  //! Returns the dimension of the vector space enclosing \p *this.
  dimension_type space_dimension() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is exactly equal
    to \p cgs.
  */
  bool is_equal_to(const Congruence_System& cgs) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this contains one or
    more linear equalities.
  */
  bool has_linear_equalities() const;

  //! Removes all the congruences and sets the space dimension to 0.
  void clear();

  /*! \brief
    Inserts in \p *this a copy of the congruence \p cg, increasing the
    number of space dimensions if needed.

    The copy of \p cg will be strongly normalized after being
    inserted.
  */
  void insert(const Congruence& cg);

  /*! \brief
    Inserts in \p *this a copy of the equality constraint \p c, seen
    as a modulo 0 congruence, increasing the number of space
    dimensions if needed.

    The modulo 0 congruence will be strongly normalized after being
    inserted.

    \exception std::invalid_argument
    Thrown if \p c is a relation.
  */
  void insert(const Constraint& c);

  // TODO: Consider adding a recycling_insert(cg).

  /*! \brief
    Inserts in \p *this a copy of the congruences in \p cgs,
    increasing the number of space dimensions if needed.

    The inserted copies will be strongly normalized.
  */
  void insert(const Congruence_System& cgs);

  /*! \brief
    Inserts into \p *this the congruences in \p cgs, increasing the
    number of space dimensions if needed.
  */
  void recycling_insert(Congruence_System& cgs);

  //! Returns the system containing only Congruence::zero_dim_false().
  static const Congruence_System& zero_dim_empty();

  //! An iterator over a system of congruences.
  /*! \ingroup PPL_CXX_interface
    A const_iterator is used to provide read-only access
    to each congruence contained in an object of Congruence_System.

    \par Example
    The following code prints the system of congruences
    defining the grid <CODE>gr</CODE>:
    \code
  const Congruence_System& cgs = gr.congruences();
  for (Congruence_System::const_iterator i = cgs.begin(),
         cgs_end = cgs.end(); i != cgs_end; ++i)
    cout << *i << endl;
    \endcode
  */
  class const_iterator
    : public std::iterator<std::forward_iterator_tag,
			   Congruence,
			   ptrdiff_t,
			   const Congruence*,
			   const Congruence&> {
  public:
    //! Default constructor.
    const_iterator();

    //! Ordinary copy-constructor.
    const_iterator(const const_iterator& y);

    //! Destructor.
    ~const_iterator();

    //! Assignment operator.
    const_iterator& operator=(const const_iterator& y);

    //! Dereference operator.
    const Congruence& operator*() const;

    //! Indirect member selector.
    const Congruence* operator->() const;

    //! Prefix increment operator.
    const_iterator& operator++();

    //! Postfix increment operator.
    const_iterator operator++(int);

    /*! \brief
      Returns <CODE>true</CODE> if and only if \p *this and \p y are
      identical.
    */
    bool operator==(const const_iterator& y) const;

    /*! \brief
      Returns <CODE>true</CODE> if and only if \p *this and \p y are
      different.
    */
    bool operator!=(const const_iterator& y) const;

  private:
    friend class Congruence_System;

    //! The const iterator over the matrix of congruences.
    Matrix::const_iterator i;

    //! A const pointer to the matrix of congruences.
    const Matrix* csp;

    //! Constructor.
    const_iterator(const Matrix::const_iterator& iter,
		   const Congruence_System& cgs);

    //! \p *this skips to the next non-trivial congruence.
    void skip_forward();
  };

  /*! \brief
    Returns the const_iterator pointing to the first congruence, if \p
    *this is not empty; otherwise, returns the past-the-end
    const_iterator.
  */
  const_iterator begin() const;

  //! Returns the past-the-end const_iterator.
  const_iterator end() const;

  //! Checks if all the invariants are satisfied.
#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*!
    Returns <CODE>true</CODE> if and only if \p *this is a valid
    Matrix, each row in the system is a valid Congruence and the
    number of columns is consistent with the number of congruences.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  bool OK() const;

  PPL_OUTPUT_DECLARATIONS;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Loads from \p s an ASCII representation (as produced by \ref
    ascii_dump) and sets \p *this accordingly.  Returns
    <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  bool ascii_load(std::istream& s);

  //! Returns the total size in bytes of the memory occupied by \p *this.
  memory_size_type total_memory_in_bytes() const;

  //! Returns the size in bytes of the memory managed by \p *this.
  memory_size_type external_memory_in_bytes() const;

  //! Returns the number of equalities.
  dimension_type num_equalities() const;

  //! Returns the number of proper congruences.
  dimension_type num_proper_congruences() const;

  //! Swaps \p *this with \p y.
  void swap(Congruence_System& cgs);

  /*! \brief
    Adds \p dims rows and \p dims columns of zeroes to the matrix,
    initializing the added rows as in the unit congruence system.

    \param dims
    The number of rows and columns to be added: must be strictly
    positive.

    Turns the \f$r \times c\f$ matrix \f$A\f$ into the \f$(r+dims) \times
    (c+dims)\f$ matrix \f$\bigl({0 \atop A}{B \atop A}\bigr)\f$ where
    \f$B\f$ is the \f$dims \times dims\f$ unit matrix of the form
    \f$\bigl({0 \atop 1}{1 \atop 0}\bigr)\f$.  The matrix is expanded
    avoiding reallocation whenever possible.
  */
  void add_unit_rows_and_columns(dimension_type dims);

  /*! \brief
    Concatenates copies of the congruences from \p cgs onto \p *this.

    The matrix for the new system of congruences is obtained by
    leaving the old system in the upper left-hand side and placing the
    congruences of \p cgs in the lower right-hand side, and padding
    with zeroes.
  */
  void concatenate(const Congruence_System& cgs);

protected:

  //! Returns <CODE>true</CODE> if \p g satisfies all the congruences.
  bool satisfies_all_congruences(const Grid_Generator& g) const;

private:

  //! Adjusts all expressions to have the same moduli.
  void normalize_moduli();

  //! Increase the number of space dimensions to \p new_space_dim.
  /*!
    \p new_space_dim must at least equal to the current space
    dimension.
  */
  bool increase_space_dimension(const dimension_type new_space_dim);

  /*! \brief
    Inserts in \p *this an exact copy of the congruence \p cg,
    increasing the number of space dimensions if needed.

    This method inserts a copy of \p cg in the given form, instead of
    first strong normalizing \p cg as \ref insert would do.
  */
  void insert_verbatim(const Congruence& cg);

  friend class const_iterator;
  // FIXME: Reduce the dependence on this declaration.
  friend class Grid;
  friend class Grid_Certificate;

  friend void std::swap(Parma_Polyhedra_Library::Congruence_System& x,
			Parma_Polyhedra_Library::Congruence_System& y);

  friend bool
  Parma_Polyhedra_Library::operator==(const Congruence_System& x,
				      const Congruence_System& y);

  //! Returns the \p k- th congruence of the system.
  Congruence& operator[](dimension_type k);

  //! Returns a constant reference to the \p k- th congruence of the system.
  const Congruence& operator[](dimension_type k) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if any of the dimensions in
    \p *this is free of constraint.

    Any equality or proper congruence affecting a dimension constrains
    that dimension.

    This method assumes the system is in minimal form.
  */
  bool has_a_free_dimension() const;

  /*! \brief
    Substitutes a given column of coefficients by a given affine
    expression.

    \param v
    Index of the column to which the affine transformation is
    substituted;

    \param expr
    The numerator of the affine transformation:
    \f$\sum_{i = 0}^{n - 1} a_i x_i + b\f$;

    \param denominator
    The denominator of the affine transformation.

    We allow affine transformations (see the Section \ref
    rational_grid_operations) to have rational
    coefficients. Since the coefficients of linear expressions are
    integers we also provide an integer \p denominator that will
    be used as denominator of the affine transformation.  The
    denominator is required to be a positive integer and its default value
    is 1.

    The affine transformation substitutes the matrix of congruences
    by a new matrix whose elements \f${a'}_{ij}\f$ are built from
    the old one \f$a_{ij}\f$ as follows:
    \f[
      {a'}_{ij} =
        \begin{cases}
          a_{ij} * \mathrm{denominator} + a_{iv} * \mathrm{expr}[j]
            \quad \text{for } j \neq v; \\
          \mathrm{expr}[v] * a_{iv}
            \quad \text{for } j = v.
        \end{cases}
    \f]

    \p expr is a constant parameter and unaltered by this computation.
  */
  void affine_preimage(dimension_type v,
		       const Linear_Expression& expr,
		       Coefficient_traits::const_reference denominator);

  //! Resizes the system without worrying about the old contents.
  /*!
    \param new_n_rows
    The number of rows of the resized system;

    \param new_n_columns
    The number of columns of the resized system.

    The system is expanded to the specified dimensions avoiding
    reallocation whenever possible.
    The contents of the original system is lost.
  */
  void resize_no_copy(dimension_type new_n_rows, dimension_type new_n_columns);
};

// Congruence_System.inlines.hh is not included here on purpose.

// Automatically generated from PPL source file ../src/Linear_Expression.defs.hh line 1
/* Linear_Expression class declaration.
*/


// Automatically generated from PPL source file ../src/Linear_Expression.defs.hh line 42
#include <cstddef>

namespace Parma_Polyhedra_Library {
// Put them in the namespace here to declare them friend later.

//! Returns the congruence \p e1 = \p e2 \p \pmod{1}.
/*! \relates Congruence */
Congruence
operator%=(const Linear_Expression& e1, const Linear_Expression& e2);

//! Returns the congruence \p e = \p n \p \pmod{1}.
/*! \relates Congruence */
Congruence
operator%=(const Linear_Expression& e, Coefficient_traits::const_reference n);

//! Returns the linear expression \p e1 + \p e2.
/*! \relates Linear_Expression */
Linear_Expression
operator+(const Linear_Expression& e1, const Linear_Expression& e2);

//! Returns the linear expression \p v + \p w.
/*! \relates Linear_Expression */
Linear_Expression
operator+(Variable v, Variable w);

//! Returns the linear expression \p v + \p e.
/*! \relates Linear_Expression */
Linear_Expression
operator+(Variable v, const Linear_Expression& e);

//! Returns the linear expression \p e + \p v.
/*! \relates Linear_Expression */
Linear_Expression
operator+(const Linear_Expression& e, Variable v);

//! Returns the linear expression \p n + \p e.
/*! \relates Linear_Expression */
Linear_Expression
operator+(Coefficient_traits::const_reference n, const Linear_Expression& e);

//! Returns the linear expression \p e + \p n.
/*! \relates Linear_Expression */
Linear_Expression
operator+(const Linear_Expression& e, Coefficient_traits::const_reference n);

//! Returns the linear expression \p e.
/*! \relates Linear_Expression */
Linear_Expression
operator+(const Linear_Expression& e);

//! Returns the linear expression - \p e.
/*! \relates Linear_Expression */
Linear_Expression
operator-(const Linear_Expression& e);

//! Returns the linear expression \p e1 - \p e2.
/*! \relates Linear_Expression */
Linear_Expression
operator-(const Linear_Expression& e1, const Linear_Expression& e2);

//! Returns the linear expression \p v - \p w.
/*! \relates Linear_Expression */
Linear_Expression
operator-(Variable v, Variable w);

//! Returns the linear expression \p v - \p e.
/*! \relates Linear_Expression */
Linear_Expression
operator-(Variable v, const Linear_Expression& e);

//! Returns the linear expression \p e - \p v.
/*! \relates Linear_Expression */
Linear_Expression
operator-(const Linear_Expression& e, Variable v);

//! Returns the linear expression \p n - \p e.
/*! \relates Linear_Expression */
Linear_Expression
operator-(Coefficient_traits::const_reference n, const Linear_Expression& e);

//! Returns the linear expression \p e - \p n.
/*! \relates Linear_Expression */
Linear_Expression
operator-(const Linear_Expression& e, Coefficient_traits::const_reference n);

//! Returns the linear expression \p n * \p e.
/*! \relates Linear_Expression */
Linear_Expression
operator*(Coefficient_traits::const_reference n, const Linear_Expression& e);

//! Returns the linear expression \p e * \p n.
/*! \relates Linear_Expression */
Linear_Expression
operator*(const Linear_Expression& e, Coefficient_traits::const_reference n);

//! Returns the linear expression \p e1 + \p e2 and assigns it to \p e1.
/*! \relates Linear_Expression */
Linear_Expression&
operator+=(Linear_Expression& e1, const Linear_Expression& e2);

//! Returns the linear expression \p e + \p v and assigns it to \p e.
/*! \relates Linear_Expression
  \exception std::length_error
  Thrown if the space dimension of \p v exceeds
  <CODE>Linear_Expression::max_space_dimension()</CODE>.
 */
Linear_Expression&
operator+=(Linear_Expression& e, Variable v);

//! Returns the linear expression \p e + \p n and assigns it to \p e.
/*! \relates Linear_Expression */
Linear_Expression&
operator+=(Linear_Expression& e, Coefficient_traits::const_reference n);

//! Returns the linear expression \p e1 - \p e2 and assigns it to \p e1.
/*! \relates Linear_Expression */
Linear_Expression&
operator-=(Linear_Expression& e1, const Linear_Expression& e2);

//! Returns the linear expression \p e - \p v and assigns it to \p e.
/*! \relates Linear_Expression
  \exception std::length_error
  Thrown if the space dimension of \p v exceeds
  <CODE>Linear_Expression::max_space_dimension()</CODE>.
 */
Linear_Expression&
operator-=(Linear_Expression& e, Variable v);

//! Returns the linear expression \p e - \p n and assigns it to \p e.
/*! \relates Linear_Expression */
Linear_Expression&
operator-=(Linear_Expression& e, Coefficient_traits::const_reference n);

//! Returns the linear expression \p n * \p e and assigns it to \p e.
/*! \relates Linear_Expression */
Linear_Expression&
operator*=(Linear_Expression& e, Coefficient_traits::const_reference n);

namespace IO_Operators {

//! Output operator.
/*! \relates Parma_Polyhedra_Library::Linear_Expression */
std::ostream& operator<<(std::ostream& s, const Linear_Expression& e);

} // namespace IO_Operators

} // namespace Parma_Polyhedra_Library


namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Linear_Expression */
void swap(Parma_Polyhedra_Library::Linear_Expression& x,
	  Parma_Polyhedra_Library::Linear_Expression& y);

} // namespace std

//! A linear expression.
/*! \ingroup PPL_CXX_interface
  An object of the class Linear_Expression represents the linear expression
  \f[
    \sum_{i=0}^{n-1} a_i x_i + b
  \f]
  where \f$n\f$ is the dimension of the vector space,
  each \f$a_i\f$ is the integer coefficient
  of the \f$i\f$-th variable \f$x_i\f$
  and \f$b\f$ is the integer for the inhomogeneous term.

  \par How to build a linear expression.

  Linear expressions are the basic blocks for defining
  both constraints (i.e., linear equalities or inequalities)
  and generators (i.e., lines, rays, points and closure points).
  A full set of functions is defined to provide a convenient interface
  for building complex linear expressions starting from simpler ones
  and from objects of the classes Variable and Coefficient:
  available operators include unary negation,
  binary addition and subtraction,
  as well as multiplication by a Coefficient.
  The space dimension of a linear expression is defined as the maximum
  space dimension of the arguments used to build it:
  in particular, the space dimension of a Variable <CODE>x</CODE>
  is defined as <CODE>x.id()+1</CODE>,
  whereas all the objects of the class Coefficient have space dimension zero.

  \par Example
  The following code builds the linear expression \f$4x - 2y - z + 14\f$,
  having space dimension \f$3\f$:
  \code
  Linear_Expression e = 4*x - 2*y - z + 14;
  \endcode
  Another way to build the same linear expression is:
  \code
  Linear_Expression e1 = 4*x;
  Linear_Expression e2 = 2*y;
  Linear_Expression e3 = z;
  Linear_Expression e = Linear_Expression(14);
  e += e1 - e2 - e3;
  \endcode
  Note that \p e1, \p e2 and \p e3 have space dimension 1, 2 and 3,
  respectively; also, in the fourth line of code, \p e is created
  with space dimension zero and then extended to space dimension 3
  in the fifth line.
*/
class Parma_Polyhedra_Library::Linear_Expression : private Linear_Row {
public:
  //! Default constructor: returns a copy of Linear_Expression::zero().
  Linear_Expression();

  //! Ordinary copy-constructor.
  Linear_Expression(const Linear_Expression& e);

  //! Destructor.
  ~Linear_Expression();

  /*! \brief
    Builds the linear expression corresponding
    to the inhomogeneous term \p n.
  */
  explicit Linear_Expression(Coefficient_traits::const_reference n);

  //! Builds the linear expression corresponding to the variable \p v.
  /*! \relates Linear_Expression
    \exception std::length_error
    Thrown if the space dimension of \p v exceeds
    <CODE>Linear_Expression::max_space_dimension()</CODE>.
  */
  Linear_Expression(Variable v);

  //! Builds the linear expression corresponding to constraint \p c.
  /*!
    Given the constraint
    \f$c = \bigl(\sum_{i=0}^{n-1} a_i x_i + b \relsym 0\bigr)\f$,
    where \f$\mathord{\relsym} \in \{ =, \geq, > \}\f$,
    this builds the linear expression \f$\sum_{i=0}^{n-1} a_i x_i + b\f$.
    If \p c is an inequality (resp., equality) constraint, then
    the built linear expression is unique up to a positive
    (resp., non-zero) factor.
  */
  explicit Linear_Expression(const Constraint& c);

  /*! \brief
    Builds the linear expression corresponding to generator \p g
    (for points and closure points, the divisor is not copied).

    Given the generator
    \f$g = (\frac{a_0}{d}, \ldots, \frac{a_{n-1}}{d})^\transpose\f$
    (where, for lines and rays, we have \f$d = 1\f$),
    this builds the linear expression \f$\sum_{i=0}^{n-1} a_i x_i\f$.
    The inhomogeneous term of the linear expression will always be 0.
    If \p g is a ray, point or closure point (resp., a line), then
    the linear expression is unique up to a positive
    (resp., non-zero) factor.
  */
  explicit Linear_Expression(const Generator& g);

  //! Builds the linear expression corresponding to congruence \p cg.
  /*!
    Given the congruence
    \f$cg = \bigl(\sum_{i=0}^{n-1} a_i x_i + b = 0 \pmod{m}\bigr)\f$,
    this builds the linear expression \f$\sum_{i=0}^{n-1} a_i x_i + b\f$.
  */
  explicit Linear_Expression(const Congruence& cg);

  //! Returns the maximum space dimension a Linear_Expression can handle.
  static dimension_type max_space_dimension();

  //! Returns the dimension of the vector space enclosing \p *this.
  dimension_type space_dimension() const;

  //! Returns the coefficient of \p v in \p *this.
  Coefficient_traits::const_reference coefficient(Variable v) const;

  //! Returns the inhomogeneous term of \p *this.
  Coefficient_traits::const_reference inhomogeneous_term() const;

  //! Returns the (zero-dimension space) constant 0.
  static const Linear_Expression& zero();

  /*! \brief
    Returns a lower bound to the total size in bytes of the memory
    occupied by \p *this.
  */
  memory_size_type total_memory_in_bytes() const;

  //! Returns the size in bytes of the memory managed by \p *this.
  memory_size_type external_memory_in_bytes() const;

  //! Checks if all the invariants are satisfied.
  bool OK() const;

  //! Swaps \p *this with \p y.
  void swap(Linear_Expression& y);

private:
  friend class Parma_Polyhedra_Library::Scalar_Products;
  friend class Parma_Polyhedra_Library::Constraint;
  friend class Parma_Polyhedra_Library::Generator;
  // The following declaration grants access to Grid_Generator::parameter.
  friend class Parma_Polyhedra_Library::Grid_Generator;
  friend class Parma_Polyhedra_Library::Congruence;
  // FIXME: the following friend declaration should be avoided.
  friend class Parma_Polyhedra_Library::Polyhedron;
  friend class Parma_Polyhedra_Library::Grid;
  friend class Parma_Polyhedra_Library::LP_Problem;

  // FIXME: the following friend declaration is only to grant access to
  // Constraint_System::affine_preimage().
  friend class Parma_Polyhedra_Library::Constraint_System;

  // FIXME: the following friend declaration is only to grant access to
  // Generator_System::affine_image().
  friend class Parma_Polyhedra_Library::Generator_System;

  // FIXME: the following friend declaration is only to grant access to
  // Congruence_System::affine_preimage().
  friend class Parma_Polyhedra_Library::Congruence_System;

  // FIXME: the following friend declaration is only to grant access to
  // Grid_Generator_System::affine_image().
  friend class Parma_Polyhedra_Library::Grid_Generator_System;

  //! Copy-constructor with a specified space dimension.
  Linear_Expression(const Linear_Expression& e, dimension_type sz);

  //! Implementation sizing constructor.
  /*!
    The bool parameter is just to avoid problems with
    the constructor Linear_Expression(Coefficient_traits::const_reference n).
  */
  Linear_Expression(dimension_type sz, bool);

  friend Linear_Expression
  Parma_Polyhedra_Library::operator+(const Linear_Expression& e1,
				     const Linear_Expression& e2);
  friend Linear_Expression
  Parma_Polyhedra_Library::operator+(Coefficient_traits::const_reference n,
				     const Linear_Expression& e);
  friend Linear_Expression
  Parma_Polyhedra_Library::operator+(const Linear_Expression& e,
				     Coefficient_traits::const_reference n);

  friend Linear_Expression
  Parma_Polyhedra_Library::operator-(const Linear_Expression& e);

  friend Linear_Expression
  Parma_Polyhedra_Library::operator-(const Linear_Expression& e1,
				     const Linear_Expression& e2);
  friend Linear_Expression
  Parma_Polyhedra_Library::operator-(Coefficient_traits::const_reference n,
				     const Linear_Expression& e);
  friend Linear_Expression
  Parma_Polyhedra_Library::operator-(const Linear_Expression& e,
				     Coefficient_traits::const_reference n);

  friend Linear_Expression
  Parma_Polyhedra_Library::operator*(Coefficient_traits::const_reference n,
				     const Linear_Expression& e);
  friend Linear_Expression
  Parma_Polyhedra_Library::operator*(const Linear_Expression& e,
				     Coefficient_traits::const_reference n);

  friend Linear_Expression&
  Parma_Polyhedra_Library::operator+=(Linear_Expression& e1,
				      const Linear_Expression& e2);
  friend Linear_Expression&
  Parma_Polyhedra_Library::operator+=(Linear_Expression& e,
				      Variable v);
  friend Linear_Expression&
  Parma_Polyhedra_Library::operator+=(Linear_Expression& e,
				      Coefficient_traits::const_reference n);

  friend Linear_Expression&
  Parma_Polyhedra_Library::operator-=(Linear_Expression& e1,
				      const Linear_Expression& e2);
  friend Linear_Expression&
  Parma_Polyhedra_Library::operator-=(Linear_Expression& e,
				      Variable v);
  friend Linear_Expression&
  Parma_Polyhedra_Library::operator-=(Linear_Expression& e,
				      Coefficient_traits::const_reference n);

  friend Linear_Expression&
  Parma_Polyhedra_Library::operator*=(Linear_Expression& e,
				      Coefficient_traits::const_reference n);

  friend std::ostream&
  Parma_Polyhedra_Library::IO_Operators::operator<<(std::ostream& s,
						    const Linear_Expression& e);

  friend Congruence
  Parma_Polyhedra_Library::operator%=(const Linear_Expression& e1,
				      const Linear_Expression& e2);

  friend Congruence
  Parma_Polyhedra_Library::operator%=(const Linear_Expression& e,
				      Coefficient_traits::const_reference n);
};

// Automatically generated from PPL source file ../src/Linear_Expression.inlines.hh line 1
/* Linear_Expression class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/Linear_Expression.inlines.hh line 28
#include <stdexcept>

namespace Parma_Polyhedra_Library {

inline dimension_type
Linear_Expression::max_space_dimension() {
  return Linear_Row::max_space_dimension();
}

inline
Linear_Expression::Linear_Expression()
  : Linear_Row(1, Linear_Row::Flags()) {
}

inline
Linear_Expression::Linear_Expression(dimension_type sz, bool)
  : Linear_Row(sz, Linear_Row::Flags()) {
}

inline
Linear_Expression::Linear_Expression(const Variable v)
  : Linear_Row(v.space_dimension() <= max_space_dimension()
	       ? v.id() + 2
	       : (throw std::length_error("PPL::Linear_Expression::"
					  "Linear_Expression(v):\n"
					  "v exceeds the maximum allowed "
					  "space dimension."),
		  v.id() + 2)
	       , Linear_Row::Flags()) {
  (*this)[v.id() + 1] = 1;
}

inline
Linear_Expression::Linear_Expression(const Linear_Expression& e)
  : Linear_Row(e) {
}

inline
Linear_Expression::~Linear_Expression() {
}

inline
Linear_Expression::Linear_Expression(const Linear_Expression& e,
				     dimension_type sz)
  : Linear_Row(e, sz, sz) {
}

inline
Linear_Expression::Linear_Expression(Coefficient_traits::const_reference n)
  : Linear_Row(1, Linear_Row::Flags()) {
  (*this)[0] = n;
}

inline dimension_type
Linear_Expression::space_dimension() const {
  return size() - 1;
}

inline Coefficient_traits::const_reference
Linear_Expression::coefficient(Variable v) const {
  if (v.space_dimension() > space_dimension())
    return Coefficient_zero();
  return Linear_Row::coefficient(v.id());
}

inline Coefficient_traits::const_reference
Linear_Expression::inhomogeneous_term() const {
  return Linear_Row::inhomogeneous_term();
}

inline const Linear_Expression&
Linear_Expression::zero() {
  static Linear_Expression z = Linear_Expression(Coefficient_zero());
  return z;
}

inline memory_size_type
Linear_Expression::external_memory_in_bytes() const {
  return Linear_Row::external_memory_in_bytes();
}

inline memory_size_type
Linear_Expression::total_memory_in_bytes() const {
  return Linear_Row::total_memory_in_bytes();
}

/*! \relates Linear_Expression */
inline Linear_Expression
operator+(const Linear_Expression& e) {
  return e;
}

/*! \relates Linear_Expression */
inline Linear_Expression
operator+(const Linear_Expression& e, Coefficient_traits::const_reference n) {
  return n + e;
}

/*! \relates Linear_Expression */
inline Linear_Expression
operator+(const Variable v, const Variable w) {
  // FIXME: provide a better implementation.
  return Linear_Expression(v) + Linear_Expression(w);
}

/*! \relates Linear_Expression */
inline Linear_Expression
operator+(const Variable v, const Linear_Expression& e) {
  // FIXME: provide a better implementation.
  return e + Linear_Expression(v);
}

/*! \relates Linear_Expression */
inline Linear_Expression
operator+(const Linear_Expression& e, const Variable v) {
  return v + e;
}

/*! \relates Linear_Expression */
inline Linear_Expression
operator-(const Linear_Expression& e, Coefficient_traits::const_reference n) {
  return -n + e;
}

/*! \relates Linear_Expression */
inline Linear_Expression
operator-(const Variable v, const Variable w) {
  // FIXME: provide a better implementation.
  return Linear_Expression(v) - Linear_Expression(w);
}

/*! \relates Linear_Expression */
inline Linear_Expression
operator-(const Variable v, const Linear_Expression& e) {
  // FIXME: provide a better implementation.
  return Linear_Expression(v) - e;
}

/*! \relates Linear_Expression */
inline Linear_Expression
operator-(const Linear_Expression& e, const Variable v) {
  // FIXME: provide a better implementation.
  return e - Linear_Expression(v);
}

/*! \relates Linear_Expression */
inline Linear_Expression
operator*(const Linear_Expression& e, Coefficient_traits::const_reference n) {
  return n * e;
}

/*! \relates Linear_Expression */
inline Linear_Expression&
operator+=(Linear_Expression& e, Coefficient_traits::const_reference n) {
  e[0] += n;
  return e;
}

/*! \relates Linear_Expression */
inline Linear_Expression&
operator-=(Linear_Expression& e, Coefficient_traits::const_reference n) {
  e[0] -= n;
  return e;
}

inline void
Linear_Expression::swap(Linear_Expression& y) {
  Linear_Row::swap(y);
}

} // namespace Parma_Polyhedra_Library


namespace std {

/*! \relates Parma_Polyhedra_Library::Linear_Expression */
inline void
swap(Parma_Polyhedra_Library::Linear_Expression& x,
     Parma_Polyhedra_Library::Linear_Expression& y) {
  x.swap(y);
}

} // namespace std

// Automatically generated from PPL source file ../src/Linear_Expression.defs.hh line 443

// Automatically generated from PPL source file ../src/Constraint.defs.hh line 1
/* Constraint class declaration.
*/


// Automatically generated from PPL source file ../src/Constraint.defs.hh line 33
#include <iosfwd>

namespace Parma_Polyhedra_Library {

// Put them in the namespace here to declare them friend later.

//! Returns <CODE>true</CODE> if and only if \p x is equivalent to \p y.
/*! \relates Constraint */
bool
operator==(const Constraint& x, const Constraint& y);

//! Returns <CODE>true</CODE> if and only if \p x is not equivalent to \p y.
/*! \relates Constraint */
bool
operator!=(const Constraint& x, const Constraint& y);

//! Returns the constraint \p e1 = \p e2.
/*! \relates Constraint */
Constraint
operator==(const Linear_Expression& e1, const Linear_Expression& e2);
//! Returns the constraint \p e = \p n.
/*! \relates Constraint */
Constraint
operator==(const Linear_Expression& e, Coefficient_traits::const_reference n);
//! Returns the constraint \p n = \p e.
/*! \relates Constraint */
Constraint
operator==(Coefficient_traits::const_reference n, const Linear_Expression& e);

//! Returns the constraint \p e1 \<= \p e2.
/*! \relates Constraint */
Constraint
operator<=(const Linear_Expression& e1, const Linear_Expression& e2);
//! Returns the constraint \p e \<= \p n.
/*! \relates Constraint */
Constraint
operator<=(const Linear_Expression& e, Coefficient_traits::const_reference n);
//! Returns the constraint \p n \<= \p e.
/*! \relates Constraint */
Constraint
operator<=(Coefficient_traits::const_reference n, const Linear_Expression& e);

//! Returns the constraint \p e1 \>= \p e2.
/*! \relates Constraint */
Constraint
operator>=(const Linear_Expression& e1, const Linear_Expression& e2);
//! Returns the constraint \p e \>= \p n.
/*! \relates Constraint */
Constraint
operator>=(const Linear_Expression& e, Coefficient_traits::const_reference n);
//! Returns the constraint \p n \>= \p e.
/*! \relates Constraint */
Constraint
operator>=(Coefficient_traits::const_reference n, const Linear_Expression& e);

//! Returns the constraint \p e1 \< \p e2.
/*! \relates Constraint */
Constraint
operator<(const Linear_Expression& e1, const Linear_Expression& e2);
//! Returns the constraint \p e \< \p n.
/*! \relates Constraint */
Constraint
operator<(const Linear_Expression& e, Coefficient_traits::const_reference n);
//! Returns the constraint \p n \< \p e.
/*! \relates Constraint */
Constraint
operator<(Coefficient_traits::const_reference n, const Linear_Expression& e);

//! Returns the constraint \p e1 \> \p e2.
/*! \relates Constraint */
Constraint
operator>(const Linear_Expression& e1, const Linear_Expression& e2);
//! Returns the constraint \p e \> \p n.
/*! \relates Constraint */
Constraint
operator>(const Linear_Expression& e, Coefficient_traits::const_reference n);
//! Returns the constraint \p n \> \p e.
/*! \relates Constraint */
Constraint
operator>(Coefficient_traits::const_reference n, const Linear_Expression& e);

} // namespace Parma_Polyhedra_Library


namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Constraint */
void swap(Parma_Polyhedra_Library::Constraint& x,
	  Parma_Polyhedra_Library::Constraint& y);

} // namespace std

//! A linear equality or inequality.
/*! \ingroup PPL_CXX_interface
  An object of the class Constraint is either:
  - an equality: \f$\sum_{i=0}^{n-1} a_i x_i + b = 0\f$;
  - a non-strict inequality: \f$\sum_{i=0}^{n-1} a_i x_i + b \geq 0\f$; or
  - a strict inequality: \f$\sum_{i=0}^{n-1} a_i x_i + b > 0\f$;

  where \f$n\f$ is the dimension of the space,
  \f$a_i\f$ is the integer coefficient of variable \f$x_i\f$
  and \f$b\f$ is the integer inhomogeneous term.

  \par How to build a constraint
  Constraints are typically built by applying a relation symbol
  to a pair of linear expressions.
  Available relation symbols are equality (<CODE>==</CODE>),
  non-strict inequalities (<CODE>\>=</CODE> and <CODE>\<=</CODE>) and
  strict inequalities (<CODE>\<</CODE> and <CODE>\></CODE>).
  The space dimension of a constraint is defined as the maximum
  space dimension of the arguments of its constructor.

  \par
  In the following examples it is assumed that variables
  <CODE>x</CODE>, <CODE>y</CODE> and <CODE>z</CODE>
  are defined as follows:
  \code
  Variable x(0);
  Variable y(1);
  Variable z(2);
  \endcode

  \par Example 1
  The following code builds the equality constraint
  \f$3x + 5y - z = 0\f$, having space dimension \f$3\f$:
  \code
  Constraint eq_c(3*x + 5*y - z == 0);
  \endcode
  The following code builds the (non-strict) inequality constraint
  \f$4x \geq 2y - 13\f$, having space dimension \f$2\f$:
  \code
  Constraint ineq_c(4*x >= 2*y - 13);
  \endcode
  The corresponding strict inequality constraint
  \f$4x > 2y - 13\f$ is obtained as follows:
  \code
  Constraint strict_ineq_c(4*x > 2*y - 13);
  \endcode
  An unsatisfiable constraint on the zero-dimension space \f$\Rset^0\f$
  can be specified as follows:
  \code
  Constraint false_c = Constraint::zero_dim_false();
  \endcode
  Equivalent, but more involved ways are the following:
  \code
  Constraint false_c1(Linear_Expression::zero() == 1);
  Constraint false_c2(Linear_Expression::zero() >= 1);
  Constraint false_c3(Linear_Expression::zero() > 0);
  \endcode
  In contrast, the following code defines an unsatisfiable constraint
  having space dimension \f$3\f$:
  \code
  Constraint false_c(0*z == 1);
  \endcode

  \par How to inspect a constraint
  Several methods are provided to examine a constraint and extract
  all the encoded information: its space dimension, its type
  (equality, non-strict inequality, strict inequality) and
  the value of its integer coefficients.

  \par Example 2
  The following code shows how it is possible to access each single
  coefficient of a constraint. Given an inequality constraint
  (in this case \f$x - 5y + 3z \leq 4\f$), we construct a new constraint
  corresponding to its complement (thus, in this case we want to obtain
  the strict inequality constraint \f$x - 5y + 3z > 4\f$).
  \code
  Constraint c1(x - 5*y + 3*z <= 4);
  cout << "Constraint c1: " << c1 << endl;
  if (c1.is_equality())
    cout << "Constraint c1 is not an inequality." << endl;
  else {
    Linear_Expression e;
    for (int i = c1.space_dimension() - 1; i >= 0; i--)
      e += c1.coefficient(Variable(i)) * Variable(i);
    e += c1.inhomogeneous_term();
    Constraint c2 = c1.is_strict_inequality() ? (e <= 0) : (e < 0);
    cout << "Complement c2: " << c2 << endl;
  }
  \endcode
  The actual output is the following:
  \code
  Constraint c1: -A + 5*B - 3*C >= -4
  Complement c2: A - 5*B + 3*C > 4
  \endcode
  Note that, in general, the particular output obtained can be
  syntactically different from the (semantically equivalent)
  constraint considered.
*/
class Parma_Polyhedra_Library::Constraint : private Linear_Row {
public:
  //! Ordinary copy-constructor.
  Constraint(const Constraint& c);

  //! Destructor.
  ~Constraint();

  //! Assignment operator.
  Constraint& operator=(const Constraint& c);

  //! Returns the maximum space dimension a Constraint can handle.
  static dimension_type max_space_dimension();

  //! Returns the dimension of the vector space enclosing \p *this.
  dimension_type space_dimension() const;

  //! The constraint type.
  enum Type {
    /*! The constraint is an equality. */
    EQUALITY,
    /*! The constraint is a non-strict inequality. */
    NONSTRICT_INEQUALITY,
    /*! The constraint is a strict inequality. */
    STRICT_INEQUALITY
  };

  //! Returns the constraint type of \p *this.
  Type type() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if
    \p *this is an equality constraint.
  */
  bool is_equality() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if
    \p *this is an inequality constraint (either strict or non-strict).
  */
  bool is_inequality() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if
    \p *this is a non-strict inequality constraint.
  */
  bool is_nonstrict_inequality() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if
    \p *this is a strict inequality constraint.
  */
  bool is_strict_inequality() const;

  //! Returns the coefficient of \p v in \p *this.
  /*!
    \exception std::invalid_argument thrown if the index of \p v
    is greater than or equal to the space dimension of \p *this.
  */
  Coefficient_traits::const_reference coefficient(Variable v) const;

  //! Returns the inhomogeneous term of \p *this.
  Coefficient_traits::const_reference inhomogeneous_term() const;

  //! The unsatisfiable (zero-dimension space) constraint \f$0 = 1\f$.
  static const Constraint& zero_dim_false();

  /*! \brief
    The true (zero-dimension space) constraint \f$0 \leq 1\f$,
    also known as <EM>positivity constraint</EM>.
  */
  static const Constraint& zero_dim_positivity();

  /*! \brief
    Returns a lower bound to the total size in bytes of the memory
    occupied by \p *this.
  */
  memory_size_type total_memory_in_bytes() const;

  //! Returns the size in bytes of the memory managed by \p *this.
  memory_size_type external_memory_in_bytes() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if
    \p *this is a tautology (i.e., an always true constraint).

    A tautology can have either one of the following forms:
    - an equality: \f$\sum_{i=0}^{n-1} 0 x_i + 0 = 0\f$; or
    - a non-strict inequality: \f$\sum_{i=0}^{n-1} 0 x_i + b \geq 0\f$,
      where \f$b \geq 0\f$; or
    - a strict inequality: \f$\sum_{i=0}^{n-1} 0 x_i + b > 0\f$,
      where \f$b > 0\f$.
  */
  bool is_tautological() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if
    \p *this is inconsistent (i.e., an always false constraint).

    An inconsistent constraint can have either one of the following forms:
    - an equality: \f$\sum_{i=0}^{n-1} 0 x_i + b = 0\f$,
      where \f$b \neq 0\f$; or
    - a non-strict inequality: \f$\sum_{i=0}^{n-1} 0 x_i + b \geq 0\f$,
      where \f$b < 0\f$; or
    - a strict inequality: \f$\sum_{i=0}^{n-1} 0 x_i + b > 0\f$,
      where \f$b \leq 0\f$.
  */
  bool is_inconsistent() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this and \p y
    are equivalent constraints.

    Constraints having different space dimensions are not equivalent.
    Note that constraints having different types may nonetheless be
    equivalent, if they both are tautologies or inconsistent.
  */
  bool is_equivalent_to(const Constraint& y) const;

  PPL_OUTPUT_DECLARATIONS;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    \ref ascii_dump) and sets \p *this accordingly.
    Returns <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise.
  */
#endif
  bool ascii_load(std::istream& s);

  //! Checks if all the invariants are satisfied.
  bool OK() const;

  //! Swaps \p *this with \p y.
  void swap(Constraint& y);

private:
  friend class Parma_Polyhedra_Library::Congruence;
  friend class Parma_Polyhedra_Library::Scalar_Products;
  friend class Parma_Polyhedra_Library::Topology_Adjusted_Scalar_Product_Sign;
  friend class Parma_Polyhedra_Library::Constraint_System;
  friend class Parma_Polyhedra_Library::Constraint_System::const_iterator;
  // FIXME: the following friend declaration should be avoided.
  friend class Parma_Polyhedra_Library::Polyhedron;

  friend
  Parma_Polyhedra_Library
  ::Linear_Expression::Linear_Expression(const Constraint& c);

  //! Default constructor: private and not implemented.
  Constraint();

  /*! \brief
    Builds a constraint of type \p type and topology \p topology,
    stealing the coefficients from \p e.
  */
  Constraint(Linear_Expression& e, Type type, Topology topology);

  /*! \brief
    Throws a <CODE>std::invalid_argument</CODE> exception
    containing the appropriate error message.
  */
  void
  throw_dimension_incompatible(const char* method,
			       const char* name_var,
			       Variable v) const;

  friend Constraint
  Parma_Polyhedra_Library::operator==(const Linear_Expression& e1,
				      const Linear_Expression& e2);
  friend Constraint
  Parma_Polyhedra_Library::operator==(const Linear_Expression& e,
				      Coefficient_traits::const_reference n);
  friend Constraint
  Parma_Polyhedra_Library::operator==(Coefficient_traits::const_reference n,
				      const Linear_Expression& e);

  friend Constraint
  Parma_Polyhedra_Library::operator>=(const Linear_Expression& e1,
				      const Linear_Expression& e2);
  friend Constraint
  Parma_Polyhedra_Library::operator>=(const Linear_Expression& e,
				      Coefficient_traits::const_reference n);
  friend Constraint
  Parma_Polyhedra_Library::operator>=(Coefficient_traits::const_reference n,
				      const Linear_Expression& e);

  friend Constraint
  Parma_Polyhedra_Library::operator<=(const Linear_Expression& e1,
				      const Linear_Expression& e2);
  friend Constraint
  Parma_Polyhedra_Library::operator<=(const Linear_Expression& e,
				      Coefficient_traits::const_reference n);
  friend Constraint
  Parma_Polyhedra_Library::operator<=(Coefficient_traits::const_reference n,
				      const Linear_Expression& e);

  friend Constraint
  Parma_Polyhedra_Library::operator>(const Linear_Expression& e1,
				     const Linear_Expression& e2);
  friend Constraint
  Parma_Polyhedra_Library::operator>(const Linear_Expression& e,
				     Coefficient_traits::const_reference n);
  friend Constraint
  Parma_Polyhedra_Library::operator>(Coefficient_traits::const_reference n,
				     const Linear_Expression& e);

  friend Constraint
  Parma_Polyhedra_Library::operator<(const Linear_Expression& e1,
				     const Linear_Expression& e2);
  friend Constraint
  Parma_Polyhedra_Library::operator<(const Linear_Expression& e,
				     Coefficient_traits::const_reference n);
  friend Constraint
  Parma_Polyhedra_Library::operator<(Coefficient_traits::const_reference n,
				     const Linear_Expression& e);

  //! Copy-constructor with given size.
  Constraint(const Constraint& c, dimension_type sz);

  /*! \brief
    Builds a new copy of the zero-dimension space constraint
    \f$\epsilon \geq 0\f$ (used to implement NNC polyhedra).
  */
  static Constraint construct_epsilon_geq_zero();

  //! Returns the zero-dimension space constraint \f$\epsilon \geq 0\f$.
  static const Constraint& epsilon_geq_zero();

  /*! \brief
    The zero-dimension space constraint \f$\epsilon \leq 1\f$
    (used to implement NNC polyhedra).
  */
  static const Constraint& epsilon_leq_one();

  //! Sets the constraint type to <CODE>EQUALITY</CODE>.
  void set_is_equality();

  //! Sets the constraint to be an inequality.
  /*!
    Whether the constraint type will become <CODE>NONSTRICT_INEQUALITY</CODE>
    or <CODE>STRICT_INEQUALITY</CODE> depends on the topology and the value
    of the low-level coefficients of the constraint.
  */
  void set_is_inequality();
};

namespace Parma_Polyhedra_Library {

namespace IO_Operators {

//! Output operator.
/*! \relates Parma_Polyhedra_Library::Constraint */
std::ostream& operator<<(std::ostream& s, const Constraint& c);

//! Output operator.
/*! \relates Parma_Polyhedra_Library::Constraint */
std::ostream& operator<<(std::ostream& s, const Constraint::Type& t);

} // namespace IO_Operators

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Constraint.inlines.hh line 1
/* Constraint class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/Constraint.inlines.hh line 27

namespace Parma_Polyhedra_Library {

inline
Constraint::Constraint(Linear_Expression& e, Type type, Topology topology) {
  assert(type != STRICT_INEQUALITY || topology == NOT_NECESSARILY_CLOSED);
  Linear_Row::swap(e);
  flags() = Flags(topology, (type == EQUALITY
			     ? LINE_OR_EQUALITY
			     : RAY_OR_POINT_OR_INEQUALITY));
}

inline
Constraint::Constraint(const Constraint& c)
  : Linear_Row(c) {
}

inline
Constraint::Constraint(const Constraint& c, const dimension_type sz)
  : Linear_Row(c, sz, sz) {
}

inline
Constraint::~Constraint() {
}

inline Constraint&
Constraint::operator=(const Constraint& c) {
  Linear_Row::operator=(c);
  return *this;
}

inline dimension_type
Constraint::max_space_dimension() {
  return Linear_Row::max_space_dimension();
}

inline dimension_type
Constraint::space_dimension() const {
  return Linear_Row::space_dimension();
}

inline bool
Constraint::is_equality() const {
  return is_line_or_equality();
}

inline bool
Constraint::is_inequality() const {
  return is_ray_or_point_or_inequality();
}

inline Constraint::Type
Constraint::type() const {
  if (is_equality())
    return EQUALITY;
  if (is_necessarily_closed())
    return NONSTRICT_INEQUALITY;
  else
    return ((*this)[size() - 1] < 0)
      ? STRICT_INEQUALITY
      : NONSTRICT_INEQUALITY;
}

inline bool
Constraint::is_nonstrict_inequality() const {
  return type() == NONSTRICT_INEQUALITY;
}

inline bool
Constraint::is_strict_inequality() const {
  return type() == STRICT_INEQUALITY;
}

inline void
Constraint::set_is_equality() {
  set_is_line_or_equality();
}

inline void
Constraint::set_is_inequality() {
  set_is_ray_or_point_or_inequality();
}

inline Coefficient_traits::const_reference
Constraint::coefficient(const Variable v) const {
  if (v.space_dimension() > space_dimension())
    throw_dimension_incompatible("coefficient(v)", "v", v);
  return Linear_Row::coefficient(v.id());
}

inline Coefficient_traits::const_reference
Constraint::inhomogeneous_term() const {
  return Linear_Row::inhomogeneous_term();
}

inline memory_size_type
Constraint::external_memory_in_bytes() const {
  return Linear_Row::external_memory_in_bytes();
}

inline memory_size_type
Constraint::total_memory_in_bytes() const {
  return Linear_Row::total_memory_in_bytes();
}

/*! \relates Constraint */
inline bool
operator==(const Constraint& x, const Constraint& y) {
  return x.is_equivalent_to(y);
}

/*! \relates Constraint */
inline bool
operator!=(const Constraint& x, const Constraint& y) {
  return !x.is_equivalent_to(y);
}

/*! \relates Constraint */
inline Constraint
operator==(const Linear_Expression& e1, const Linear_Expression& e2) {
  Linear_Expression diff = e1 - e2;
  Constraint c(diff, Constraint::EQUALITY, NECESSARILY_CLOSED);
  // Enforce normalization.
  c.strong_normalize();
  return c;
}

/*! \relates Constraint */
inline Constraint
operator>=(const Linear_Expression& e1, const Linear_Expression& e2) {
  Linear_Expression diff = e1 - e2;
  Constraint c(diff, Constraint::NONSTRICT_INEQUALITY, NECESSARILY_CLOSED);
  // Enforce normalization.
  c.normalize();
  return c;
}

/*! \relates Constraint */
inline Constraint
operator>(const Linear_Expression& e1, const Linear_Expression& e2) {
  Linear_Expression diff;
  // Setting the epsilon coefficient to -1.
  // NOTE: this also enforces normalization.
  const dimension_type e1_dim = e1.space_dimension();
  const dimension_type e2_dim = e2.space_dimension();
  if (e1_dim > e2_dim)
    diff -= Variable(e1_dim);
  else
    diff -= Variable(e2_dim);
  diff += e1;
  diff -= e2;

  Constraint c(diff, Constraint::STRICT_INEQUALITY, NOT_NECESSARILY_CLOSED);
  return c;
}

/*! \relates Constraint */
inline Constraint
operator==(Coefficient_traits::const_reference n, const Linear_Expression& e) {
  Linear_Expression diff = n - e;
  Constraint c(diff, Constraint::EQUALITY, NECESSARILY_CLOSED);
  // Enforce normalization.
  c.strong_normalize();
  return c;
}

/*! \relates Constraint */
inline Constraint
operator>=(Coefficient_traits::const_reference n, const Linear_Expression& e) {
  Linear_Expression diff = n - e;
  Constraint c(diff, Constraint::NONSTRICT_INEQUALITY, NECESSARILY_CLOSED);
  // Enforce normalization.
  c.normalize();
  return c;
}

/*! \relates Constraint */
inline Constraint
operator>(Coefficient_traits::const_reference n, const Linear_Expression& e) {
  Linear_Expression diff;
  // Setting the epsilon coefficient to -1.
  // NOTE: this also enforces normalization.
  diff -= Variable(e.space_dimension());
  diff += n;
  diff -= e;

  Constraint c(diff, Constraint::STRICT_INEQUALITY, NOT_NECESSARILY_CLOSED);
  return c;
}

/*! \relates Constraint */
inline Constraint
operator==(const Linear_Expression& e, Coefficient_traits::const_reference n) {
  Linear_Expression diff = e - n;
  Constraint c(diff, Constraint::EQUALITY, NECESSARILY_CLOSED);
  // Enforce normalization.
  c.strong_normalize();
  return c;
}

/*! \relates Constraint */
inline Constraint
operator>=(const Linear_Expression& e, Coefficient_traits::const_reference n) {
  Linear_Expression diff = e - n;
  Constraint c(diff, Constraint::NONSTRICT_INEQUALITY, NECESSARILY_CLOSED);
  // Enforce normalization.
  c.normalize();
  return c;
}

/*! \relates Constraint */
inline Constraint
operator>(const Linear_Expression& e, Coefficient_traits::const_reference n) {
  Linear_Expression diff;
  // Setting the epsilon coefficient to -1.
  // NOTE: this also enforces normalization.
  diff -= Variable(e.space_dimension());
  diff += e;
  diff -= n;

  Constraint c(diff, Constraint::STRICT_INEQUALITY, NOT_NECESSARILY_CLOSED);
  c.set_not_necessarily_closed();
  c.set_is_inequality();
  return c;
}

/*! \relates Constraint */
inline Constraint
operator<=(const Linear_Expression& e1, const Linear_Expression& e2) {
  return e2 >= e1;
}

/*! \relates Constraint */
inline Constraint
operator<=(Coefficient_traits::const_reference n, const Linear_Expression& e) {
  return e >= n;
}

/*! \relates Constraint */
inline Constraint
operator<=(const Linear_Expression& e, Coefficient_traits::const_reference n) {
  return n >= e;
}

/*! \relates Constraint */
inline Constraint
operator<(const Linear_Expression& e1, const Linear_Expression& e2) {
  return e2 > e1;
}

/*! \relates Constraint */
inline Constraint
operator<(Coefficient_traits::const_reference n, const Linear_Expression& e) {
  return e > n;
}

/*! \relates Constraint */
inline Constraint
operator<(const Linear_Expression& e, Coefficient_traits::const_reference n) {
  return n > e;
}

inline const Constraint&
Constraint::zero_dim_false() {
  static const Constraint zdf(Linear_Expression::zero() == Coefficient_one());
  return zdf;
}

inline const Constraint&
Constraint::zero_dim_positivity() {
  static const Constraint zdp(Linear_Expression::zero() <= Coefficient_one());
  return zdp;
}

inline const Constraint&
Constraint::epsilon_geq_zero() {
  static const Constraint eps_geq_zero = construct_epsilon_geq_zero();
  return eps_geq_zero;
}

inline const Constraint&
Constraint::epsilon_leq_one() {
  static const Constraint
    eps_leq_one(Linear_Expression::zero() < Coefficient_one());
  return eps_leq_one;
}

inline void
Constraint::ascii_dump(std::ostream& s) const {
  Linear_Row::ascii_dump(s);
}

inline bool
Constraint::ascii_load(std::istream& s) {
  return Linear_Row::ascii_load(s);
}

inline void
Constraint::swap(Constraint& y) {
  Linear_Row::swap(y);
}

} // namespace Parma_Polyhedra_Library

namespace std {

/*! \relates Parma_Polyhedra_Library::Constraint */
inline void
swap(Parma_Polyhedra_Library::Constraint& x,
     Parma_Polyhedra_Library::Constraint& y) {
  x.swap(y);
}

} // namespace std

// Automatically generated from PPL source file ../src/Constraint.defs.hh line 488

// Automatically generated from PPL source file ../src/Constraint_System.inlines.hh line 1
/* Constraint_System class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/Constraint_System.inlines.hh line 27

namespace Parma_Polyhedra_Library {

inline
Constraint_System::Constraint_System()
  : Linear_System(NECESSARILY_CLOSED) {
}

inline
Constraint_System::Constraint_System(const Constraint& c)
  : Linear_System(c.topology()) {
  Linear_System::insert(c);
}

inline
Constraint_System::Constraint_System(const Constraint_System& cs)
  : Linear_System(cs) {
}

inline
Constraint_System::Constraint_System(const Topology topol)
  : Linear_System(topol) {
}

inline
Constraint_System::Constraint_System(const Topology topol,
				     const dimension_type n_rows,
				     const dimension_type n_columns)
  : Linear_System(topol, n_rows, n_columns) {
}

inline
Constraint_System::~Constraint_System() {
}

inline Constraint_System&
Constraint_System::operator=(const Constraint_System& y) {
  Linear_System::operator=(y);
  return *this;
}

inline Constraint&
Constraint_System::operator[](const dimension_type k) {
  return static_cast<Constraint&>(Linear_System::operator[](k));
}

inline const Constraint&
Constraint_System::operator[](const dimension_type k) const {
  return static_cast<const Constraint&>(Linear_System::operator[](k));
}

inline dimension_type
Constraint_System::max_space_dimension() {
  return Linear_System::max_space_dimension();
}

inline dimension_type
Constraint_System::space_dimension() const {
  return Linear_System::space_dimension();
}

inline void
Constraint_System::clear() {
  Linear_System::clear();
}

inline const Constraint_System&
Constraint_System::zero_dim_empty() {
  static const Constraint_System zdf(Constraint::zero_dim_false());
  return zdf;
}

inline
Constraint_System::const_iterator::const_iterator()
  : i(), csp(0) {
}

inline
Constraint_System::const_iterator::const_iterator(const const_iterator& y)
  : i(y.i), csp(y.csp) {
}

inline
Constraint_System::const_iterator::~const_iterator() {
}

inline Constraint_System::const_iterator&
Constraint_System::const_iterator::operator=(const const_iterator& y) {
  i = y.i;
  csp = y.csp;
  return *this;
}

inline const Constraint&
Constraint_System::const_iterator::operator*() const {
  return static_cast<const Constraint&>(*i);
}

inline const Constraint*
Constraint_System::const_iterator::operator->() const {
  return static_cast<const Constraint*>(i.operator->());
}

inline Constraint_System::const_iterator&
Constraint_System::const_iterator::operator++() {
  ++i;
  skip_forward();
  return *this;
}

inline Constraint_System::const_iterator
Constraint_System::const_iterator::operator++(int) {
  const const_iterator tmp = *this;
  operator++();
  return tmp;
}

inline bool
Constraint_System::const_iterator::operator==(const const_iterator& y) const {
  return i == y.i;
}

inline bool
Constraint_System::const_iterator::operator!=(const const_iterator& y) const {
  return i != y.i;
}

inline
Constraint_System::const_iterator::
const_iterator(const Linear_System::const_iterator& iter,
	       const Constraint_System& csys)
  : i(iter), csp(&csys) {
}

inline Constraint_System::const_iterator
Constraint_System::begin() const {
  const_iterator i(Linear_System::begin(), *this);
  i.skip_forward();
  return i;
}

inline Constraint_System::const_iterator
Constraint_System::end() const {
  const const_iterator i(Linear_System::end(), *this);
  return i;
}

inline void
Constraint_System::add_low_level_constraints() {
  if (is_necessarily_closed())
    // The positivity constraint.
    insert(Constraint::zero_dim_positivity());
  else {
    // Add the epsilon constraints.
    insert(Constraint::epsilon_leq_one());
    insert(Constraint::epsilon_geq_zero());
  }
}

inline void
Constraint_System::swap(Constraint_System& y) {
  Linear_System::swap(y);
}

inline memory_size_type
Constraint_System::external_memory_in_bytes() const {
  return Linear_System::external_memory_in_bytes();
}

inline memory_size_type
Constraint_System::total_memory_in_bytes() const {
  return Linear_System::total_memory_in_bytes();
}

inline void
Constraint_System::simplify() {
  Linear_System::simplify();
}

} // namespace Parma_Polyhedra_Library


namespace std {

/*! \relates Parma_Polyhedra_Library::Constraint_System */
inline void
swap(Parma_Polyhedra_Library::Constraint_System& x,
     Parma_Polyhedra_Library::Constraint_System& y) {
  x.swap(y);
}

} // namespace std

// Automatically generated from PPL source file ../src/Generator.defs.hh line 1
/* Generator class declaration.
*/


// Automatically generated from PPL source file ../src/Generator.defs.hh line 37
#include <iosfwd>

namespace Parma_Polyhedra_Library {

// Put them in the namespace here to declare them friend later.

namespace IO_Operators {

//! Output operator.
/*! \relates Parma_Polyhedra_Library::Generator */
std::ostream& operator<<(std::ostream& s, const Generator& g);

} // namespace IO_Operators

} // namespace Parma_Polyhedra_Library

namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Generator */
void swap(Parma_Polyhedra_Library::Generator& x,
	  Parma_Polyhedra_Library::Generator& y);

} // namespace std


//! A line, ray, point or closure point.
/*! \ingroup PPL_CXX_interface
  An object of the class Generator is one of the following:

  - a line \f$\vect{l} = (a_0, \ldots, a_{n-1})^\transpose\f$;

  - a ray \f$\vect{r} = (a_0, \ldots, a_{n-1})^\transpose\f$;

  - a point
    \f$\vect{p} = (\frac{a_0}{d}, \ldots, \frac{a_{n-1}}{d})^\transpose\f$;

  - a closure point
    \f$\vect{c} = (\frac{a_0}{d}, \ldots, \frac{a_{n-1}}{d})^\transpose\f$;

  where \f$n\f$ is the dimension of the space
  and, for points and closure points, \f$d > 0\f$ is the divisor.

  \par A note on terminology.
  As observed in Section \ref representation, there are cases when,
  in order to represent a polyhedron \f$\cP\f$ using the generator system
  \f$\cG = (L, R, P, C)\f$, we need to include in the finite set
  \f$P\f$ even points of \f$\cP\f$ that are <EM>not</EM> vertices
  of \f$\cP\f$.
  This situation is even more frequent when working with NNC polyhedra
  and it is the reason why we prefer to use the word `point'
  where other libraries use the word `vertex'.

  \par How to build a generator.
  Each type of generator is built by applying the corresponding
  function (<CODE>line</CODE>, <CODE>ray</CODE>, <CODE>point</CODE>
  or <CODE>closure_point</CODE>) to a linear expression,
  representing a direction in the space;
  the space dimension of the generator is defined as the space dimension
  of the corresponding linear expression.
  Linear expressions used to define a generator should be homogeneous
  (any constant term will be simply ignored).
  When defining points and closure points, an optional Coefficient argument
  can be used as a common <EM>divisor</EM> for all the coefficients
  occurring in the provided linear expression;
  the default value for this argument is 1.

  \par
  In all the following examples it is assumed that variables
  <CODE>x</CODE>, <CODE>y</CODE> and <CODE>z</CODE>
  are defined as follows:
  \code
  Variable x(0);
  Variable y(1);
  Variable z(2);
  \endcode

  \par Example 1
  The following code builds a line with direction \f$x-y-z\f$
  and having space dimension \f$3\f$:
  \code
  Generator l = line(x - y - z);
  \endcode
  As mentioned above, the constant term of the linear expression
  is not relevant. Thus, the following code has the same effect:
  \code
  Generator l = line(x - y - z + 15);
  \endcode
  By definition, the origin of the space is not a line, so that
  the following code throws an exception:
  \code
  Generator l = line(0*x);
  \endcode

  \par Example 2
  The following code builds a ray with the same direction as the
  line in Example 1:
  \code
  Generator r = ray(x - y - z);
  \endcode
  As is the case for lines, when specifying a ray the constant term
  of the linear expression is not relevant; also, an exception is thrown
  when trying to build a ray from the origin of the space.

  \par Example 3
  The following code builds the point
  \f$\vect{p} = (1, 0, 2)^\transpose \in \Rset^3\f$:
  \code
  Generator p = point(1*x + 0*y + 2*z);
  \endcode
  The same effect can be obtained by using the following code:
  \code
  Generator p = point(x + 2*z);
  \endcode
  Similarly, the origin \f$\vect{0} \in \Rset^3\f$ can be defined
  using either one of the following lines of code:
  \code
  Generator origin3 = point(0*x + 0*y + 0*z);
  Generator origin3_alt = point(0*z);
  \endcode
  Note however that the following code would have defined
  a different point, namely \f$\vect{0} \in \Rset^2\f$:
  \code
  Generator origin2 = point(0*y);
  \endcode
  The following two lines of code both define the only point
  having space dimension zero, namely \f$\vect{0} \in \Rset^0\f$.
  In the second case we exploit the fact that the first argument
  of the function <CODE>point</CODE> is optional.
  \code
  Generator origin0 = Generator::zero_dim_point();
  Generator origin0_alt = point();
  \endcode

  \par Example 4
  The point \f$\vect{p}\f$ specified in Example 3 above
  can also be obtained with the following code,
  where we provide a non-default value for the second argument
  of the function <CODE>point</CODE> (the divisor):
  \code
  Generator p = point(2*x + 0*y + 4*z, 2);
  \endcode
  Obviously, the divisor can be usefully exploited to specify
  points having some non-integer (but rational) coordinates.
  For instance, the point
  \f$\vect{q} = (-1.5, 3.2, 2.1)^\transpose \in \Rset^3\f$
  can be specified by the following code:
  \code
  Generator q = point(-15*x + 32*y + 21*z, 10);
  \endcode
  If a zero divisor is provided, an exception is thrown.

  \par Example 5
  Closure points are specified in the same way we defined points,
  but invoking their specific constructor function.
  For instance, the closure point
  \f$\vect{c} = (1, 0, 2)^\transpose \in \Rset^3\f$ is defined by
  \code
  Generator c = closure_point(1*x + 0*y + 2*z);
  \endcode
  For the particular case of the (only) closure point
  having space dimension zero, we can use any of the following:
  \code
  Generator closure_origin0 = Generator::zero_dim_closure_point();
  Generator closure_origin0_alt = closure_point();
  \endcode

  \par How to inspect a generator
  Several methods are provided to examine a generator and extract
  all the encoded information: its space dimension, its type and
  the value of its integer coefficients.

  \par Example 6
  The following code shows how it is possible to access each single
  coefficient of a generator.
  If <CODE>g1</CODE> is a point having coordinates
  \f$(a_0, \ldots, a_{n-1})^\transpose\f$,
  we construct the closure point <CODE>g2</CODE> having coordinates
  \f$(a_0, 2 a_1, \ldots, (i+1)a_i, \ldots, n a_{n-1})^\transpose\f$.
  \code
  if (g1.is_point()) {
    cout << "Point g1: " << g1 << endl;
    Linear_Expression e;
    for (int i = g1.space_dimension() - 1; i >= 0; i--)
      e += (i + 1) * g1.coefficient(Variable(i)) * Variable(i);
    Generator g2 = closure_point(e, g1.divisor());
    cout << "Closure point g2: " << g2 << endl;
  }
  else
    cout << "Generator g1 is not a point." << endl;
  \endcode
  Therefore, for the point
  \code
  Generator g1 = point(2*x - y + 3*z, 2);
  \endcode
  we would obtain the following output:
  \code
  Point g1: p((2*A - B + 3*C)/2)
  Closure point g2: cp((2*A - 2*B + 9*C)/2)
  \endcode
  When working with (closure) points, be careful not to confuse
  the notion of <EM>coefficient</EM> with the notion of <EM>coordinate</EM>:
  these are equivalent only when the divisor of the (closure) point is 1.
*/
class Parma_Polyhedra_Library::Generator : private Linear_Row {
public:
  //! Returns the line of direction \p e.
  /*!
    \exception std::invalid_argument
    Thrown if the homogeneous part of \p e represents the origin of
    the vector space.
  */
  static Generator line(const Linear_Expression& e);

  //! Returns the ray of direction \p e.
  /*!
    \exception std::invalid_argument
    Thrown if the homogeneous part of \p e represents the origin of
    the vector space.
  */
  static Generator ray(const Linear_Expression& e);

  //! Returns the point at \p e / \p d.
  /*!
    Both \p e and \p d are optional arguments, with default values
    Linear_Expression::zero() and Coefficient_one(), respectively.

    \exception std::invalid_argument
    Thrown if \p d is zero.
  */
  static Generator point(const Linear_Expression& e
			 = Linear_Expression::zero(),
			 Coefficient_traits::const_reference d
			 = Coefficient_one());

  //! Returns the closure point at \p e / \p d.
  /*!
    Both \p e and \p d are optional arguments, with default values
    Linear_Expression::zero() and Coefficient_one(), respectively.

    \exception std::invalid_argument
    Thrown if \p d is zero.
  */
  static Generator
  closure_point(const Linear_Expression& e = Linear_Expression::zero(),
		Coefficient_traits::const_reference d = Coefficient_one());

  //! Ordinary copy-constructor.
  Generator(const Generator& g);

  //! Destructor.
  ~Generator();

  //! Assignment operator.
  Generator& operator=(const Generator& g);

  //! Returns the maximum space dimension a Generator can handle.
  static dimension_type max_space_dimension();

  //! Returns the dimension of the vector space enclosing \p *this.
  dimension_type space_dimension() const;

  //! The generator type.
  enum Type {
    /*! The generator is a line. */
    LINE,
    /*! The generator is a ray. */
    RAY,
    /*! The generator is a point. */
    POINT,
    /*! The generator is a closure point. */
    CLOSURE_POINT
  };

  //! Returns the generator type of \p *this.
  Type type() const;

  //! Returns <CODE>true</CODE> if and only if \p *this is a line.
  bool is_line() const;

  //! Returns <CODE>true</CODE> if and only if \p *this is a ray.
  bool is_ray() const;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  //! Returns <CODE>true</CODE> if and only if \p *this is a line or a ray.
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  bool is_line_or_ray() const;

  //! Returns <CODE>true</CODE> if and only if \p *this is a point.
  bool is_point() const;

  //! Returns <CODE>true</CODE> if and only if \p *this is a closure point.
  bool is_closure_point() const;

  //! Returns the coefficient of \p v in \p *this.
  /*!
    \exception std::invalid_argument
    Thrown if the index of \p v is greater than or equal to the
    space dimension of \p *this.
  */
  Coefficient_traits::const_reference coefficient(Variable v) const;

  //! If \p *this is either a point or a closure point, returns its divisor.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this is neither a point nor a closure point.
  */
  Coefficient_traits::const_reference divisor() const;

  //! Returns the origin of the zero-dimensional space \f$\Rset^0\f$.
  static const Generator& zero_dim_point();

  /*! \brief
    Returns, as a closure point,
    the origin of the zero-dimensional space \f$\Rset^0\f$.
  */
  static const Generator& zero_dim_closure_point();

  /*! \brief
    Returns a lower bound to the total size in bytes of the memory
    occupied by \p *this.
  */
  memory_size_type total_memory_in_bytes() const;

  //! Returns the size in bytes of the memory managed by \p *this.
  memory_size_type external_memory_in_bytes() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this and \p y
    are equivalent generators.

    Generators having different space dimensions are not equivalent.
  */
  bool is_equivalent_to(const Generator& y) const;

  PPL_OUTPUT_DECLARATIONS;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    \ref ascii_dump) and sets \p *this accordingly.
    Returns <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise.
  */
#endif
  bool ascii_load(std::istream& s);

  //! Checks if all the invariants are satisfied.
  bool OK() const;

  //! Swaps \p *this with \p y.
  void swap(Generator& y);

private:
  /*! \brief
    Builds a generator of type \p type and topology \p topology,
    stealing the coefficients from \p e.
  */
  Generator(Linear_Expression& e, Type type, Topology topology);

  /*! \brief
    Throw a <CODE>std::invalid_argument</CODE> exception
    containing the appropriate error message.
  */
  void
  throw_dimension_incompatible(const char* method,
			       const char* name_var,
			       Variable v) const;

  /*! \brief
    Throw a <CODE>std::invalid_argument</CODE> exception
    containing the appropriate error message.
  */
  void
  throw_invalid_argument(const char* method, const char* reason) const;

  friend class Parma_Polyhedra_Library::Scalar_Products;
  friend class Parma_Polyhedra_Library::Topology_Adjusted_Scalar_Product_Sign;
  friend class Parma_Polyhedra_Library::Topology_Adjusted_Scalar_Product_Assign;
  friend class Parma_Polyhedra_Library::Generator_System;
  friend class Parma_Polyhedra_Library::Generator_System::const_iterator;
  // FIXME: the following friend declaration should be avoided.
  friend class Parma_Polyhedra_Library::Polyhedron;
  friend class Parma_Polyhedra_Library::Grid_Generator;
  // This is for access to Row and Linear_Row in `insert'.
  friend class Parma_Polyhedra_Library::Grid_Generator_System;

  friend
  Parma_Polyhedra_Library
  ::Linear_Expression::Linear_Expression(const Generator& g);

  friend std::ostream&
  Parma_Polyhedra_Library::IO_Operators::operator<<(std::ostream& s,
						    const Generator& g);

  //! Copy-constructor with given space dimension.
  Generator(const Generator& g, dimension_type dimension);

  //! Returns <CODE>true</CODE> if and only if \p *this is not a line.
  bool is_ray_or_point() const;

  //! Sets the Linear_Row kind to <CODE>LINE_OR_EQUALITY</CODE>.
  void set_is_line();

  //! Sets the Linear_Row kind to <CODE>RAY_OR_POINT_OR_INEQUALITY</CODE>.
  void set_is_ray_or_point();

  /*! \brief
    Returns <CODE>true</CODE> if and only if the closure point
    \p *this has the same \e coordinates of the point \p p.

    It is \e assumed that \p *this is a closure point, \p p is a point
    and both topologies and space dimensions agree.
  */
  bool is_matching_closure_point(const Generator& p) const;

  //! Default constructor: private and not implemented.
  Generator();
};


namespace Parma_Polyhedra_Library {

//! Shorthand for Generator Generator::line(const Linear_Expression& e).
/*! \relates Generator */
Generator line(const Linear_Expression& e);

//! Shorthand for Generator Generator::ray(const Linear_Expression& e).
/*! \relates Generator */
Generator ray(const Linear_Expression& e);

/*! \brief
  Shorthand for Generator
  Generator::point(const Linear_Expression& e, Coefficient_traits::const_reference d).

  \relates Generator
*/
Generator
point(const Linear_Expression& e = Linear_Expression::zero(),
      Coefficient_traits::const_reference d = Coefficient_one());

/*! \brief
  Shorthand for Generator
  Generator::closure_point(const Linear_Expression& e, Coefficient_traits::const_reference d).

  \relates Generator
*/
Generator
closure_point(const Linear_Expression& e = Linear_Expression::zero(),
	      Coefficient_traits::const_reference d = Coefficient_one());

//! Returns <CODE>true</CODE> if and only if \p x is equivalent to \p y.
/*! \relates Generator */
bool operator==(const Generator& x, const Generator& y);

//! Returns <CODE>true</CODE> if and only if \p x is not equivalent to \p y.
/*! \relates Generator */
bool operator!=(const Generator& x, const Generator& y);


namespace IO_Operators {

//! Output operator.
/*! \relates Parma_Polyhedra_Library::Generator */
std::ostream& operator<<(std::ostream& s, const Generator::Type& t);

} // namespace IO_Operators

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Generator.inlines.hh line 1
/* Generator class implementation: inline functions.
*/


namespace Parma_Polyhedra_Library {

inline
Generator::Generator(Linear_Expression& e, Type type, Topology topology) {
  assert(type != CLOSURE_POINT || topology == NOT_NECESSARILY_CLOSED);
  Linear_Row::swap(e);
  flags() = Flags(topology, (type == LINE
			     ? LINE_OR_EQUALITY
			     : RAY_OR_POINT_OR_INEQUALITY));
}

inline
Generator::Generator(const Generator& g)
  : Linear_Row(g) {
}

inline
Generator::Generator(const Generator& g, dimension_type dimension)
  : Linear_Row(g, dimension, dimension) {
}

inline
Generator::~Generator() {
}

inline Generator&
Generator::operator=(const Generator& g) {
  Linear_Row::operator=(g);
  return *this;
}

inline dimension_type
Generator::max_space_dimension() {
  return Linear_Row::max_space_dimension();
}

inline dimension_type
Generator::space_dimension() const {
  return Linear_Row::space_dimension();
}

inline bool
Generator::is_line() const {
  return is_line_or_equality();
}

inline bool
Generator::is_ray_or_point() const {
  return is_ray_or_point_or_inequality();
}

inline bool
Generator::is_line_or_ray() const {
  return (*this)[0] == 0;
}

inline bool
Generator::is_ray() const {
  return is_ray_or_point() && is_line_or_ray();
}

inline Generator::Type
Generator::type() const {
  if (is_line())
    return LINE;
  if (is_line_or_ray())
    return RAY;
  if (is_necessarily_closed())
    return POINT;
  else {
    // Checking the value of the epsilon coefficient.
    const Generator& g = *this;
    return (g[size() - 1] == 0) ? CLOSURE_POINT : POINT;
  }
}

inline bool
Generator::is_point() const {
  return type() == POINT;
}

inline bool
Generator::is_closure_point() const {
  return type() == CLOSURE_POINT;
}

inline void
Generator::set_is_line() {
  set_is_line_or_equality();
}

inline void
Generator::set_is_ray_or_point() {
  set_is_ray_or_point_or_inequality();
}

inline Coefficient_traits::const_reference
Generator::coefficient(const Variable v) const {
  if (v.space_dimension() > space_dimension())
    throw_dimension_incompatible("coefficient(v)", "v", v);
  return Linear_Row::coefficient(v.id());
}

inline Coefficient_traits::const_reference
Generator::divisor() const {
  Coefficient_traits::const_reference d = Linear_Row::inhomogeneous_term();
  if (!is_ray_or_point() || d == 0)
    throw_invalid_argument("divisor()",
			   "*this is neither a point nor a closure point");
  return d;
}

inline memory_size_type
Generator::external_memory_in_bytes() const {
  return Linear_Row::external_memory_in_bytes();
}

inline memory_size_type
Generator::total_memory_in_bytes() const {
  return Linear_Row::total_memory_in_bytes();
}

inline const Generator&
Generator::zero_dim_point() {
  static const Generator zdp = point();
  return zdp;
}

inline const Generator&
Generator::zero_dim_closure_point() {
  static const Generator zdcp = closure_point();
  return zdcp;
}

/*! \relates Generator */
inline Generator
line(const Linear_Expression& e) {
  return Generator::line(e);
}

/*! \relates Generator */
inline Generator
ray(const Linear_Expression& e) {
  return Generator::ray(e);
}

/*! \relates Generator */
inline Generator
point(const Linear_Expression& e, Coefficient_traits::const_reference d) {
  return Generator::point(e, d);
}

/*! \relates Generator */
inline Generator
closure_point(const Linear_Expression& e,
	      Coefficient_traits::const_reference d) {
  return Generator::closure_point(e, d);
}

/*! \relates Generator */
inline bool
operator==(const Generator& x, const Generator& y) {
  return x.is_equivalent_to(y);
}

/*! \relates Generator */
inline bool
operator!=(const Generator& x, const Generator& y) {
  return !x.is_equivalent_to(y);
}

inline void
Generator::ascii_dump(std::ostream& s) const {
  Linear_Row::ascii_dump(s);
}

inline bool
Generator::ascii_load(std::istream& s) {
  return Linear_Row::ascii_load(s);
}

inline void
Generator::swap(Generator& y) {
  Linear_Row::swap(y);
}

} // namespace Parma_Polyhedra_Library

namespace std {

/*! \relates Parma_Polyhedra_Library::Generator */
inline void
swap(Parma_Polyhedra_Library::Generator& x,
     Parma_Polyhedra_Library::Generator& y) {
  x.swap(y);
}

} // namespace std

// Automatically generated from PPL source file ../src/Generator.defs.hh line 507

// Automatically generated from PPL source file ../src/Grid_Generator.inlines.hh line 1
/* Grid Generator class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/Grid_Generator.defs.hh line 1
/* Grid_Generator class declaration.
*/


// Automatically generated from PPL source file ../src/Grid_Generator.defs.hh line 30
#include <iosfwd>

namespace Parma_Polyhedra_Library {

// Put these in the namespace here to declare them friend later.

namespace IO_Operators {

//! Output operator.
/*! \relates Parma_Polyhedra_Library::Grid_Generator */
std::ostream& operator<<(std::ostream& s, const Grid_Generator& g);

} // namespace IO_Operators

} // namespace Parma_Polyhedra_Library

namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Grid_Generator */
void swap(Parma_Polyhedra_Library::Grid_Generator& x,
	  Parma_Polyhedra_Library::Grid_Generator& y);

} // namespace std

//! A line, parameter or point.
/*! \ingroup PPL_CXX_interface
  An object of the class Grid_Generator is one of the following:

  - a line \f$\vect{l} = (a_0, \ldots, a_{n-1})^\transpose\f$;

  - a parameter
    \f$\vect{q} = (\frac{a_0}{d}, \ldots, \frac{a_{n-1}}{d})^\transpose\f$;

  - a point
    \f$\vect{p} = (\frac{a_0}{d}, \ldots, \frac{a_{n-1}}{d})^\transpose\f$;

  where \f$n\f$ is the dimension of the space
  and, for points and parameters, \f$d > 0\f$ is the divisor.

  \par How to build a grid generator.
  Each type of generator is built by applying the corresponding
  function (<CODE>line</CODE>, <CODE>parameter</CODE> or <CODE>point</CODE>)
  to a linear expression;
  the space dimension of the generator is defined as the space dimension
  of the corresponding linear expression.
  Linear expressions used to define a generator should be homogeneous
  (any constant term will be simply ignored).
  When defining points and parameters, an optional Coefficient argument
  can be used as a common <EM>divisor</EM> for all the coefficients
  occurring in the provided linear expression;
  the default value for this argument is 1.

  \par
  In all the following examples it is assumed that variables
  <CODE>x</CODE>, <CODE>y</CODE> and <CODE>z</CODE>
  are defined as follows:
  \code
  Variable x(0);
  Variable y(1);
  Variable z(2);
  \endcode

  \par Example 1
  The following code builds a line with direction \f$x-y-z\f$
  and having space dimension \f$3\f$:
  \code
  Grid_Generator l = grid_line(x - y - z);
  \endcode
  By definition, the origin of the space is not a line, so that
  the following code throws an exception:
  \code
  Grid_Generator l = grid_line(0*x);
  \endcode

  \par Example 2
  The following code builds the parameter as the vector
  \f$\vect{p} = (1, -1, -1)^\transpose \in \Rset^3\f$
  which has the same direction as the line in Example 1:
  \code
  Grid_Generator q = parameter(x - y - z);
  \endcode
  Note that, unlike lines, for parameters, the length as well
  as the direction of the vector represented by the code is significant.
  Thus \p q is \e not the same as the parameter \p q1 defined by
  \code
  Grid_Generator q1 = parameter(2x - 2y - 2z);
  \endcode
  By definition, the origin of the space is not a parameter, so that
  the following code throws an exception:
  \code
  Grid_Generator q = parameter(0*x);
  \endcode

  \par Example 3
  The following code builds the point
  \f$\vect{p} = (1, 0, 2)^\transpose \in \Rset^3\f$:
  \code
  Grid_Generator p = grid_point(1*x + 0*y + 2*z);
  \endcode
  The same effect can be obtained by using the following code:
  \code
  Grid_Generator p = grid_point(x + 2*z);
  \endcode
  Similarly, the origin \f$\vect{0} \in \Rset^3\f$ can be defined
  using either one of the following lines of code:
  \code
  Grid_Generator origin3 = grid_point(0*x + 0*y + 0*z);
  Grid_Generator origin3_alt = grid_point(0*z);
  \endcode
  Note however that the following code would have defined
  a different point, namely \f$\vect{0} \in \Rset^2\f$:
  \code
  Grid_Generator origin2 = grid_point(0*y);
  \endcode
  The following two lines of code both define the only point
  having space dimension zero, namely \f$\vect{0} \in \Rset^0\f$.
  In the second case we exploit the fact that the first argument
  of the function <CODE>point</CODE> is optional.
  \code
  Grid_Generator origin0 = Generator::zero_dim_point();
  Grid_Generator origin0_alt = grid_point();
  \endcode

  \par Example 4
  The point \f$\vect{p}\f$ specified in Example 3 above
  can also be obtained with the following code,
  where we provide a non-default value for the second argument
  of the function <CODE>grid_point</CODE> (the divisor):
  \code
  Grid_Generator p = grid_point(2*x + 0*y + 4*z, 2);
  \endcode
  Obviously, the divisor can be used to specify
  points having some non-integer (but rational) coordinates.
  For instance, the point
  \f$\vect{p1} = (-1.5, 3.2, 2.1)^\transpose \in \Rset^3\f$
  can be specified by the following code:
  \code
  Grid_Generator p1 = grid_point(-15*x + 32*y + 21*z, 10);
  \endcode
  If a zero divisor is provided, an exception is thrown.

  \par Example 5
  Parameters, like points can have a divisor.
  For instance, the parameter
  \f$\vect{q} = (1, 0, 2)^\transpose \in \Rset^3\f$ can be defined:
  \code
  Grid_Generator q = parameter(2*x + 0*y + 4*z, 2);
  \endcode
  Also, the divisor can be used to specify
  parameters having some non-integer (but rational) coordinates.
  For instance, the parameter
  \f$\vect{q} = (-1.5, 3.2, 2.1)^\transpose \in \Rset^3\f$
  can be defined:
  \code
  Grid_Generator q = parameter(-15*x + 32*y + 21*z, 10);
  \endcode
  If a zero divisor is provided, an exception is thrown.

  \par How to inspect a grid generator
  Several methods are provided to examine a grid generator and extract
  all the encoded information: its space dimension, its type and
  the value of its integer coefficients and the value of the denominator.

  \par Example 6
  The following code shows how it is possible to access each single
  coefficient of a grid generator.
  If <CODE>g1</CODE> is a point having coordinates
  \f$(a_0, \ldots, a_{n-1})^\transpose\f$,
  we construct the parameter <CODE>g2</CODE> having coordinates
  \f$(a_0, 2 a_1, \ldots, (i+1)a_i, \ldots, n a_{n-1})^\transpose\f$.
  \code
  if (g1.is_point()) {
    cout << "Point g1: " << g1 << endl;
    Linear_Expression e;
    for (int i = g1.space_dimension() - 1; i >= 0; i--)
      e += (i + 1) * g1.coefficient(Variable(i)) * Variable(i);
    Grid_Generator g2 = parameter(e, g1.divisor());
    cout << "Parameter g2: " << g2 << endl;
  }
  else
    cout << "Grid Generator g1 is not a point." << endl;
  \endcode
  Therefore, for the point
  \code
  Grid_Generator g1 = grid_point(2*x - y + 3*z, 2);
  \endcode
  we would obtain the following output:
  \code
  Point g1: p((2*A - B + 3*C)/2)
  Parameter g2: parameter((2*A - 2*B + 9*C)/2)
  \endcode
  When working with points and parameters, be careful not to confuse
  the notion of <EM>coefficient</EM> with the notion of <EM>coordinate</EM>:
  these are equivalent only when the divisor is 1.
*/
class Parma_Polyhedra_Library::Grid_Generator : private Generator {
public:
  // FIXME: Add wrappers of any other public Generator methods.

  //! Returns the dimension of the vector space enclosing \p *this.
  dimension_type space_dimension() const;

  //! The generator type.
  enum Type {
    /*! The generator is a line. */
    LINE,
    /*! The generator is a parameter. */
    PARAMETER,
    /*! The generator is a point. */
    POINT
  };

  //! Returns the generator type of \p *this.
  Type type() const;

  //! Returns <CODE>true</CODE> if and only if \p *this is a line.
  bool is_line() const;

  //! Returns <CODE>true</CODE> if and only if \p *this is a parameter.
  bool is_parameter() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is a line or
    a parameter.
  */
  bool is_line_or_parameter() const;

  //! Returns <CODE>true</CODE> if and only if \p *this is a point.
  bool is_point() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this row represents a
    parameter or a point.
  */
  bool is_parameter_or_point() const;

  //! Returns the line of direction \p e.
  /*!
    \exception std::invalid_argument
    Thrown if the homogeneous part of \p e represents the origin of
    the vector space.
  */
  static Grid_Generator line(const Linear_Expression& e);

  //! Returns the parameter at \p e.
  /*!
    Both \p e and \p d are optional arguments, with default values
    Linear_Expression::zero() and Coefficient_one(), respectively.

    \exception std::invalid_argument
    Thrown if \p d is zero.
  */
  static Grid_Generator parameter(const Linear_Expression& e
				  = Linear_Expression::zero(),
				  Coefficient_traits::const_reference d
				  = Coefficient_one());

  //! Returns the point at \p e / \p d.
  /*!
    Both \p e and \p d are optional arguments, with default values
    Linear_Expression::zero() and Coefficient_one(), respectively.

    \exception std::invalid_argument
    Thrown if \p d is zero.
  */
  static Grid_Generator point(const Linear_Expression& e
			      = Linear_Expression::zero(),
			      Coefficient_traits::const_reference d
			      = Coefficient_one());

  //! Assignment operator.
  Grid_Generator& operator=(const Grid_Generator& g);

  //! Assignment operator.
  Grid_Generator& operator=(const Generator& g);

  //! Returns the divisor of \p *this.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this is a line.
  */
  Coefficient_traits::const_reference divisor() const;

  /*! \brief
    Returns a lower bound to the total size in bytes of the memory
    occupied by \p *this.
  */
  memory_size_type total_memory_in_bytes() const;

  //! Returns the size in bytes of the memory managed by \p *this.
  memory_size_type external_memory_in_bytes() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this and \p y are
    equivalent generators.

    Generators having different space dimensions are not equivalent.
  */
  bool is_equivalent_to(const Grid_Generator& y) const;

  //! Returns <CODE>true</CODE> if \p *this is exactly equal to \p y.
  bool is_equal_to(const Grid_Generator& y) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if all the homogeneous terms
    of \p *this are \f$0\f$.
  */
  bool all_homogeneous_terms_are_zero() const;

  /*! \brief
    Scales \p *this to be represented with a divisor of \p d (if
    \*this is a parameter or point).

    \exception std::invalid_argument
    Thrown if \p d is zero.
  */
  void scale_to_divisor(Coefficient_traits::const_reference d);

  //! Checks if all the invariants are satisfied.
  bool OK() const;

  //! Swaps \p *this with \p y.
  void swap(Grid_Generator& y);

  /*! \brief
    Swaps \p *this with \p y, leaving \p *this with the original
    capacity.

    All up to and including the last element of the smaller of \p
    *this and \p y are swapped.  The parameter divisor element of \p y
    is swapped with the divisor element of \p *this.
  */
  void coefficient_swap(Grid_Generator& y);

  PPL_OUTPUT_DECLARATIONS;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    \ref ascii_dump) and sets \p *this accordingly.
    Returns <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  bool ascii_load(std::istream& s);

private:
  /*! \brief
    Constructs from polyhedron generator \p g, stealing the underlying
    data structures from \p g.

    The last column in \p g becomes the parameter divisor column of
    the new Grid_Generator.
  */
  explicit Grid_Generator(Generator g);

  //! Returns the actual size of \p this.
  dimension_type size() const;

  //! Negates the elements from index \p start to index \p end.
  void negate(dimension_type start, dimension_type end);

  //! Returns the divisor of \p *this.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this is a line.
  */
  Coefficient& divisor();

  //! Sets the Linear_Row kind to <CODE>LINE_OR_EQUALITY</CODE>.
  void set_is_line();

  //! Sets the Linear_Row kind to <CODE>RAY_OR_POINT_OR_INEQUALITY</CODE>.
  void set_is_parameter_or_point();

  /*! \brief
    Strong normalization: ensures that different Grid_Generator
    objects represent different hyperplanes or hyperspaces.

    Applies both Linear_Row::normalize() and Linear_Row::sign_normalize().

    This is simply a wrapper around the Generator::strong_normalize,
    which means applying it to a parameter may change the parameter.
  */
  void strong_normalize();

  //! Returns a reference to the element of the row indexed by \p k.
  Coefficient& operator[](dimension_type k);

  //! Returns a constant reference to the element of the row indexed by \p k.
  Coefficient_traits::const_reference operator[](dimension_type k) const;

  /*! \brief
    Throw a <CODE>std::invalid_argument</CODE> exception containing
    the appropriate error message.
  */
  void
  throw_invalid_argument(const char* method, const char* reason) const;

  friend std::ostream&
  IO_Operators::operator<<(std::ostream& s, const Grid_Generator& g);
  // FIXME: The following friend declaration is for operator[] and
  //        divisor() access in Grid::conversion and Grid::simplify.
  friend class Grid;

  friend class Grid_Generator_System;
  friend class Grid_Generator_System::const_iterator;
  friend class Congruence_System;
  friend class Scalar_Products;
  friend class Topology_Adjusted_Scalar_Product_Sign;
};


namespace Parma_Polyhedra_Library {

/*! \brief
  Shorthand for Grid_Generator
  Grid_Generator::line(const Linear_Expression& e).
*/
/*! \relates Grid_Generator */
Grid_Generator grid_line(const Linear_Expression& e);

/*! \brief
  Shorthand for Grid_Generator
  Grid_Generator::parameter(const Linear_Expression& e,
  Coefficient_traits::const_reference d).
*/
/*! \relates Grid_Generator */
Grid_Generator
parameter(const Linear_Expression& e = Linear_Expression::zero(),
	  Coefficient_traits::const_reference d = Coefficient_one());

/*! \brief
  Shorthand for Grid_Generator
  Grid_Generator::point(const Linear_Expression& e,
  Coefficient_traits::const_reference d).
*/
/*! \relates Grid_Generator */
Grid_Generator
grid_point(const Linear_Expression& e = Linear_Expression::zero(),
	   Coefficient_traits::const_reference d = Coefficient_one());

//! Returns <CODE>true</CODE> if and only if \p x is equivalent to \p y.
/*! \relates Grid_Generator */
bool operator==(const Grid_Generator& x, const Grid_Generator& y);

//! Returns <CODE>true</CODE> if and only if \p x is not equivalent to \p y.
/*! \relates Grid_Generator */
bool operator!=(const Grid_Generator& x, const Grid_Generator& y);


namespace IO_Operators {

//! Output operator.
/*! \relates Parma_Polyhedra_Library::Grid_Generator */
std::ostream& operator<<(std::ostream& s, const Grid_Generator::Type& t);

} // namespace IO_Operators

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Grid_Generator.defs.hh line 492

// Automatically generated from PPL source file ../src/Grid_Generator.inlines.hh line 27

namespace Parma_Polyhedra_Library {

inline
Grid_Generator::Grid_Generator(Generator g)
  : Generator(Generator::point()) {
  Generator::swap(g);
}

inline dimension_type
Grid_Generator::space_dimension() const {
  return Generator::space_dimension() - 1;
}

inline Grid_Generator::Type
Grid_Generator::type() const {
  switch (Generator::type()) {
  case Generator::POINT:
    return POINT;
  case Generator::RAY:
    return PARAMETER;
  case Generator::LINE:
    return LINE;
  case Generator::CLOSURE_POINT:
  default:
    assert(false);
    return POINT;
  }
}

inline bool
Grid_Generator::is_line() const {
  return Generator::is_line();
}

inline bool
Grid_Generator::is_parameter() const {
  return is_ray();
}

inline bool
Grid_Generator::is_line_or_parameter() const {
  return is_line_or_ray();
}

inline bool
Grid_Generator::is_point() const {
  return Generator::is_point();
}

inline bool
Grid_Generator::is_parameter_or_point() const {
  return is_ray_or_point_or_inequality();
}

inline void
Grid_Generator::set_is_line() {
  Generator::set_is_line();
}

inline void
Grid_Generator::set_is_parameter_or_point() {
  Generator::set_is_ray_or_point();
}

inline Grid_Generator&
Grid_Generator::operator=(const Grid_Generator& g) {
  Generator::operator=(g);
  return *this;
}

inline Grid_Generator&
Grid_Generator::operator=(const Generator& g) {
  Generator::operator=(g);
  return *this;
}

inline void
Grid_Generator::negate(dimension_type start, dimension_type end) {
  while (start <= end)
    neg_assign(operator[](start++));
}

inline Coefficient&
Grid_Generator::divisor() {
  if (is_line())
    throw_invalid_argument("divisor()", "*this is a line");
  if (is_line_or_parameter())
    return Generator::operator[](size() - 1);
  return Generator::operator[](0);
}

inline Coefficient_traits::const_reference
Grid_Generator::divisor() const {
  if (is_line())
    throw_invalid_argument("divisor()", "*this is a line");
  if (is_line_or_parameter())
    return Generator::operator[](size() - 1);
  return Generator::operator[](0);
}

inline memory_size_type
Grid_Generator::total_memory_in_bytes() const {
  return Generator::total_memory_in_bytes();
}

inline memory_size_type
Grid_Generator::external_memory_in_bytes() const {
  return Generator::external_memory_in_bytes();
}

inline void
Grid_Generator::strong_normalize() {
  Generator::strong_normalize();
}

inline dimension_type
Grid_Generator::size() const {
  return Generator::size();
}

inline void
Grid_Generator::swap(Grid_Generator& y) {
  Generator::swap(y);
}

inline void
Grid_Generator::ascii_dump(std::ostream& s) const {
  Generator::ascii_dump(s);
}

inline bool
Grid_Generator::ascii_load(std::istream& s) {
  return Generator::ascii_load(s);
}

inline Coefficient&
Grid_Generator::operator[](dimension_type k) {
  return Generator::operator[](k);
}

inline Coefficient_traits::const_reference
Grid_Generator::operator[](dimension_type k) const {
  return Generator::operator[](k);
}

/*! \relates Grid_Generator */
inline bool
operator==(const Grid_Generator& x, const Grid_Generator& y) {
  return x.is_equivalent_to(y);
}

/*! \relates Grid_Generator */
inline bool
operator!=(const Grid_Generator& x, const Grid_Generator& y) {
  return !(x == y);
}

/*! \relates Grid_Generator */
inline Grid_Generator
grid_line(const Linear_Expression& e) {
  return Grid_Generator::line(e);
}

/*! \relates Grid_Generator */
inline Grid_Generator
parameter(const Linear_Expression& e,
	  Coefficient_traits::const_reference d) {
  return Grid_Generator::parameter(e, d);
}

/*! \relates Grid_Generator */
inline Grid_Generator
grid_point(const Linear_Expression& e,
	   Coefficient_traits::const_reference d) {
  return Grid_Generator::point(e, d);
}

} // namespace Parma_Polyhedra_Library

namespace std {

/*! \relates Parma_Polyhedra_Library::Grid_Generator */
inline void
swap(Parma_Polyhedra_Library::Grid_Generator& x,
     Parma_Polyhedra_Library::Grid_Generator& y) {
  x.swap(y);
}

} // namespace std

// Automatically generated from PPL source file ../src/Congruence.defs.hh line 1
/* Congruence class declaration.
*/


// Automatically generated from PPL source file ../src/Congruence.defs.hh line 36
#include <iosfwd>

namespace PPL = Parma_Polyhedra_Library;

namespace Parma_Polyhedra_Library {

namespace IO_Operators {

//! Output operators.

/*! \relates Parma_Polyhedra_Library::Congruence */
std::ostream&
operator<<(std::ostream& s, const Congruence& c);

// Put this in the namespace here to declare it a friend later.

/*! \relates Parma_Polyhedra_Library::Congruence_System */
std::ostream&
operator<<(std::ostream& s, const Congruence_System& cgs);


} // namespace IO_Operators

// Put these in the namespace here to declare them friend later.

//! Returns <CODE>true</CODE> if and only if \p x and \p y are equivalent.
/*! \relates Congruence */
bool
operator==(const Congruence& x, const Congruence& y);

//! Returns <CODE>false</CODE> if and only if \p x and \p y are equivalent.
/*! \relates Congruence */
bool
operator!=(const Congruence& x, const Congruence& y);

//! Returns the congruence \f$e1 = e2 \pmod{1}\f$.
/*! \relates Congruence */
Congruence
operator%=(const Linear_Expression& e1, const Linear_Expression& e2);

//! Returns the congruence \f$e = n \pmod{1}\f$.
/*! \relates Congruence */
Congruence
operator%=(const Linear_Expression& e,
	   const Coefficient_traits::const_reference n);

//! Returns a copy of \p cg, multiplying \p k into the copy's modulus.
/*!
    If \p cg represents the congruence \f$ e_1 = e_2
    \pmod{m}\f$, then the result represents the
    congruence \f$ e_1 = e_2 \pmod{mk}\f$.
  \relates Congruence
*/
Congruence
operator/(const Congruence& cg,
	  const Coefficient_traits::const_reference k);

//! Creates a congruence from \p c, with \p m as the modulus.
/*! \relates Congruence */
Congruence
operator/(const Constraint& c,
	  const Coefficient_traits::const_reference m);

} // namespace Parma_Polyhedra_Library

namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Congruence */
void
swap(Parma_Polyhedra_Library::Congruence& x,
     Parma_Polyhedra_Library::Congruence& y);

} // namespace std

//! A linear congruence.
/*! \ingroup PPL_CXX_interface
  An object of the class Congruence is a congruence:
  - \f$\cg = \sum_{i=0}^{n-1} a_i x_i + b = 0 \pmod m\f$

  where \f$n\f$ is the dimension of the space,
  \f$a_i\f$ is the integer coefficient of variable \f$x_i\f$,
  \f$b\f$ is the integer inhomogeneous term and \f$m\f$ is the integer modulus;
  if \f$m = 0\f$, then \f$\cg\f$ represents the equality congruence
  \f$\sum_{i=0}^{n-1} a_i x_i + b = 0\f$
  and, if \f$m \neq 0\f$, then the congruence \f$\cg\f$ is
  said to be a proper congruence.

  \par How to build a congruence
  Congruences \f$\pmod{1}\f$ are typically built by
  applying the congruence symbol `<CODE>\%=</CODE>'
  to a pair of linear expressions.
  Congruences with modulus \p m
  are typically constructed by building a congruence \f$\pmod{1}\f$
  using the given pair of linear expressions
  and then adding the modulus \p m
  using the modulus symbol is `<CODE>/</CODE>'.

  The space dimension of a congruence is defined as the maximum
  space dimension of the arguments of its constructor.

  \par
  In the following examples it is assumed that variables
  <CODE>x</CODE>, <CODE>y</CODE> and <CODE>z</CODE>
  are defined as follows:
  \code
  Variable x(0);
  Variable y(1);
  Variable z(2);
  \endcode

  \par Example 1
  The following code builds the equality congruence
  \f$3x + 5y - z = 0\f$, having space dimension \f$3\f$:
  \code
  Congruence eq_cg((3*x + 5*y - z %= 0) / 0);
  \endcode
  The following code builds the congruence
  \f$4x = 2y - 13 \pmod{1}\f$, having space dimension \f$2\f$:
  \code
  Congruence mod1_cg(4*x %= 2*y - 13);
  \endcode
  The following code builds the congruence
  \f$4x = 2y - 13 \pmod{2}\f$, having space dimension \f$2\f$:
  \code
  Congruence mod2_cg((4*x %= 2*y - 13) / 2);
  \endcode
  An unsatisfiable congruence on the zero-dimension space \f$\Rset^0\f$
  can be specified as follows:
  \code
  Congruence false_cg = Congruence::zero_dim_false();
  \endcode
  Equivalent, but more involved ways are the following:
  \code
  Congruence false_cg1((Linear_Expression::zero() %= 1) / 0);
  Congruence false_cg2((Linear_Expression::zero() %= 1) / 2);
  \endcode
  In contrast, the following code defines an unsatisfiable congruence
  having space dimension \f$3\f$:
  \code
  Congruence false_cg3((0*z %= 1) / 0);
  \endcode

  \par How to inspect a congruence
  Several methods are provided to examine a congruence and extract
  all the encoded information: its space dimension, its modulus
  and the value of its integer coefficients.

  \par Example 2
  The following code shows how it is possible to access the modulus
  as well as each of the coefficients.
  Given a congruence with linear expression \p e and modulus \p m
  (in this case \f$x - 5y + 3z = 4 \pmod{5}\f$), we construct a new
  congruence with the same modulus \p m but where the linear
  expression is \f$2 e\f$ (\f$2x - 10y + 6z = 8 \pmod{5}\f$).
  \code
  Congruence cg1((x - 5*y + 3*z %= 4) / 5);
  cout << "Congruence cg1: " << cg1 << endl;
  Coefficient m = cg1.modulus();
  if (m == 0)
    cout << "Congruence cg1 is an equality." << endl;
  else {
    Linear_Expression e;
    for (int i = cg1.space_dimension() - 1; i >= 0; --i)
      e += 2 * cg1.coefficient(Variable(i)) * Variable(i);
      e += 2 * cg1.inhomogeneous_term();
    Congruence cg2((e %= 0) / m);
    cout << "Congruence cg2: " << cg2 << endl;
  }
  \endcode
  The actual output could be the following:
  \code
  Congruence cg1: A - 5*B + 3*C %= 4 / 5
  Congruence cg2: 2*A - 10*B + 6*C %= 8 / 5
  \endcode
  Note that, in general, the particular output obtained can be
  syntactically different from the (semantically equivalent)
  congruence considered.
*/
class Parma_Polyhedra_Library::Congruence : private Row {
public:
  //! Ordinary copy-constructor.
  Congruence(const Congruence& cg);

  //! Copy-constructs (modulo 0) from equality constraint \p c.
  /*!
    \exception std::invalid_argument
    Thrown if \p c is a relation.
  */
  explicit Congruence(const Constraint& c);

  //! Destructor.
  ~Congruence();

  //! Assignment operator.
  Congruence& operator=(const Congruence& cg);

  //! Returns the maximum space dimension a Congruence can handle.
  static dimension_type max_space_dimension();

  //! Returns the dimension of the vector space enclosing \p *this.
  dimension_type space_dimension() const;

  //! Returns the coefficient of \p v in \p *this.
  /*!
    \exception std::invalid_argument thrown if the index of \p v
    is greater than or equal to the space dimension of \p *this.
  */
  Coefficient_traits::const_reference coefficient(Variable v) const;

  //! Returns the inhomogeneous term of \p *this.
  Coefficient_traits::const_reference inhomogeneous_term() const;

  //! Returns a const reference to the modulus of \p *this.
  Coefficient_traits::const_reference modulus() const;

  //! Multiplies \p k into the modulus of \p *this.
  /*!
    If called with \p *this representing the congruence \f$ e_1 = e_2
    \pmod{m}\f$, then it returns with *this representing
    the congruence \f$ e_1 = e_2 \pmod{mk}\f$.
  */
  Congruence&
  operator/=(const Coefficient_traits::const_reference k);

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is a trivially
    true congruence.

    Trivially true congruences are of one the following two forms:
    - an equality: \f$\sum_{i=0}^{n-1} 0 x_i + 0 == 0\f$; or
    - a proper congruence: \f$\sum_{i=0}^{n-1} 0 x_i + b \%= 0 / m\f$,
    where n is the space dimension and m is the modulus.
  */
  bool is_trivial_true() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is a trivially
    false congruence.

    Trivially false congruences have one of the following two forms:
    - an equality: \f$\sum_{i=0}^{n-1} 0 x_i + b == 0\f$
      where \f$b \neq 0\f$; or
    - a congruence: \f$\sum_{i=0}^{n-1} 0 x_i + b \%= 0 / m\f$,
      where \f$b \neq 0 \pmod{m}\f$.
  */
  bool is_trivial_false() const;

  //! Returns <CODE>true</CODE> if the modulus is greater than zero.
  /*!
    A congruence with a modulus of 0 is a linear equality.
  */
  bool is_proper_congruence() const;

  //! Returns <CODE>true</CODE> if \p *this is an equality.
  /*!
    A modulus of zero denotes a linear equality.
  */
  bool is_equality() const;

  /*! \brief
    Returns <CODE>true</CODE> if \p *this is equal to \p cg in
    dimension \p dim.
  */
  bool is_equal_at_dimension(dimension_type dim,
			     const Congruence& cg) const;

  /*! \brief
    Returns a reference to the true (zero-dimension space) congruence
    \f$0 = 1 \pmod{1}\f$, also known as the <EM>integrality
    congruence</EM>.
  */
  static const Congruence& zero_dim_integrality();

  /*! \brief
    Returns a reference to the false (zero-dimension space) congruence
    \f$0 = 1 \pmod{0}\f$.
  */
  static const Congruence& zero_dim_false();

  /*! \brief
    Returns a lower bound to the total size in bytes of the memory
    occupied by \p *this.
  */
  memory_size_type total_memory_in_bytes() const;

  //! Returns the size in bytes of the memory managed by \p *this.
  memory_size_type external_memory_in_bytes() const;

  PPL_OUTPUT_DECLARATIONS;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Loads from \p s an ASCII representation of the internal
    representation of \p *this.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  bool ascii_load(std::istream& s);

  //! Checks if all the invariants are satisfied.
  bool OK() const;

protected:

  //! Normalizes the signs.
  /*!
    The signs of the coefficients and the inhomogeneous term are
    normalized, leaving the first non-zero homogeneous coefficient
    positive.
  */
  void sign_normalize();

  //! Normalizes signs and the inhomogeneous term.
  /*!
    Applies sign_normalize, then reduces the inhomogeneous term to the
    smallest possible positive number.
  */
  void normalize();

  //! Calls normalize, then divides out common factors.
  /*!
    Strongly normalized Congruences have equivalent semantics if and
    only if their syntaxes (as output by operator<<) are equal.
  */
  void strong_normalize();

private:

  //! Returns a reference to the modulus of \p *this.
  Coefficient& modulus();

  //! Marks this congruence as a linear equality.
  void set_is_equality();

  //! Negates the elements from index \p start to index \p end.
  void negate(dimension_type start, dimension_type end);

  //! Default constructor: private and not implemented.
  Congruence();

  //! Copy-constructs with specified size and capacity.
  Congruence(const Congruence& cg,
	     dimension_type sz,
	     dimension_type capacity);

  //! Constructs from a constraint, with specified size and capacity.
  Congruence(const Constraint& c,
	     dimension_type sz,
	     dimension_type capacity);

  //! Copy-constructs from \p cg, multiplying \p k into the modulus.
  /*!
    If \p cg represents the congruence \f$ e_1 = e_2
    \pmod{m}\f$, then the result represents the
    congruence \f$ e_1 = e_2 \pmod{mk}\f$.
  */
  Congruence(const Congruence& cg, Coefficient_traits::const_reference k);

  //! Constructs from Linear_Expression \p le, using modulus \p m.
  /*!
     Builds a congruence with modulus \p m, stealing the coefficients
     from \p le.

     \param le
     The Linear_Expression holding the coefficients.

     \param m
     The modulus for the congruence.

     \param capacity
     If <CODE>true</CODE> then the size of the \p le row is expanded
     and the modulus is stored in the extra space.  In this case it is
     assumed that \p le has spare capacity of at least one element.
     If <CODE>false</CODE> then the modulus is stored in the last
     element of the \p le row.
  */
  Congruence(Linear_Expression& le,
	     Coefficient_traits::const_reference m,
	     bool capacity = true);

  //! Swaps \p *this with \p y.
  void swap(Congruence& y);

  /*! \brief
    Throws a <CODE>std::invalid_argument</CODE> exception containing
    error message \p message.
  */
  void
  throw_invalid_argument(const char* method, const char* message) const;

  /*! \brief
    Throws a <CODE>std::invalid_argument</CODE> exception containing
    the appropriate error message.
  */
  void
  throw_dimension_incompatible(const char* method,
			       const char* v_name,
			       Variable v) const;

  friend Congruence
  PPL::operator%=(const Linear_Expression& e1, const Linear_Expression& e2);

  friend Congruence
  PPL::operator%=(const Linear_Expression& e,
		  const Coefficient_traits::const_reference n);

  friend Congruence
  PPL::operator/(const Congruence& cg,
		 const Coefficient_traits::const_reference k);

  friend Congruence
  PPL::operator/(const Constraint& c,
		 const Coefficient_traits::const_reference m);

  friend bool
  PPL::operator==(const Congruence& x, const Congruence& y);

  friend bool
  PPL::operator!=(const Congruence& x, const Congruence& y);

  friend std::ostream&
  PPL::IO_Operators::operator<<(std::ostream& s,
				const Congruence_System& cgs);

  friend class PPL::Scalar_Products;
  friend class PPL::Congruence_System;
  friend class PPL::Congruence_System::const_iterator;
  // FIXME: The following friend declaration is at least for
  //        operator[] access in Grid::conversion.
  friend class PPL::Grid;
  friend class PPL::Linear_Expression;

  friend void
  std::swap(PPL::Congruence& x, PPL::Congruence& y);
};

// Automatically generated from PPL source file ../src/Congruence.inlines.hh line 1
/* Congruence class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/Congruence.inlines.hh line 28

#include <sstream>

namespace Parma_Polyhedra_Library {

inline
Congruence::Congruence(const Congruence& cg)
  : Row(cg) {
}

inline
Congruence::Congruence(const Congruence& cg,
		       dimension_type sz, dimension_type capacity)
  : Row(cg, sz, capacity) {
}

inline
Congruence::Congruence(const Congruence& cg,
		       Coefficient_traits::const_reference k)
  : Row(cg) {
  if (k >= 0)
    (*this)[size()-1] *= k;
  else
    (*this)[size()-1] *= -k;
}

inline
Congruence::~Congruence() {
}

inline const Congruence&
Congruence::zero_dim_integrality() {
  static const Congruence zdi(Linear_Expression::zero() %= Coefficient(-1));
  return zdi;
}

inline const Congruence&
Congruence::zero_dim_false() {
  static const Congruence
    zdf((Linear_Expression::zero() %= Coefficient_one()) / 0);
  return zdf;
}

inline Congruence&
Congruence::operator=(const Congruence& c) {
  Row::operator=(c);
  return *this;
}

/*! \relates Parma_Polyhedra_Library::Congruence */
inline Congruence
operator%=(const Linear_Expression& e,
	   const Coefficient_traits::const_reference n) {
  // Ensure that diff has capacity for the modulus.
  Linear_Expression diff(e, e.space_dimension() + 2);
  diff -= n;
  Congruence cg(diff, 1, false);
  return cg;
}

/*! \relates Parma_Polyhedra_Library::Congruence */
inline Congruence
operator/(const Congruence& cg,
	  const Coefficient_traits::const_reference k) {
  Congruence ret (cg, k);
  return ret;
}

/*! \relates Congruence */
inline Congruence
operator/(const Constraint& c,
	  const Coefficient_traits::const_reference m) {
  Congruence ret (c);
  return ret / m;
}

inline Congruence&
Congruence::operator/=(const Coefficient_traits::const_reference k) {
  if (k >= 0)
    (*this)[size()-1] *= k;
  else
    (*this)[size()-1] *= -k;
  return *this;
}

/*! \relates Congruence */
inline bool
operator==(const Congruence& x, const Congruence& y) {
  Congruence x_temp(x);
  Congruence y_temp(y);
  x_temp.strong_normalize();
  y_temp.strong_normalize();
  return static_cast<const Row&>(x_temp) == static_cast<const Row&>(y_temp);
}

/*! \relates Congruence */
inline bool
operator!=(const Congruence& x, const Congruence& y) {
  return !(x == y);
}

inline dimension_type
Congruence::max_space_dimension() {
  // The first coefficient holds the inhomogeneous term, while
  // the last coefficient is for the modulus.
  return max_size() - 2;
}

inline dimension_type
Congruence::space_dimension() const {
  return size() - 2;
}

inline Coefficient_traits::const_reference
Congruence::coefficient(const Variable v) const {
  if (v.space_dimension() > space_dimension())
    throw_dimension_incompatible("coefficient(v)", "v", v);
  return (*this)[v.id()+1];
}

inline Coefficient_traits::const_reference
Congruence::inhomogeneous_term() const {
  return (*this)[0];
}

inline Coefficient_traits::const_reference
Congruence::modulus() const {
  assert(size() > 0);
  return (*this)[size()-1];
}

inline Coefficient&
Congruence::modulus() {
  assert(size() > 0);
  return (*this)[size()-1];
}

inline bool
Congruence::is_proper_congruence() const {
  return modulus() > 0;
}

inline bool
Congruence::is_equality() const {
  return modulus() == 0;
}

inline bool
Congruence::is_equal_at_dimension(dimension_type dim,
				  const Congruence& cg) const {
  return operator[](dim) * cg.modulus() == cg[dim] * modulus();
}

inline void
Congruence::set_is_equality() {
  modulus() = 0;
}

inline void
Congruence::negate(dimension_type start, dimension_type end) {
  while (start <= end)
    neg_assign(operator[](start++));
}

inline memory_size_type
Congruence::external_memory_in_bytes() const {
  return Row::external_memory_in_bytes();
}

inline memory_size_type
Congruence::total_memory_in_bytes() const {
  return Row::total_memory_in_bytes();
}

inline
Congruence::Congruence(Linear_Expression& le,
		       Coefficient_traits::const_reference m,
		       bool capacity) {
  Row::swap(static_cast<Row&>(le));
  if (capacity)
    Row::expand_within_capacity(size()+1);
  if (m >= 0)
    (*this)[size()-1] = m;
  else
    (*this)[size()-1] = -m;
}

inline void
Congruence::swap(Congruence& y) {
  Row::swap(y);
}

} // namespace Parma_Polyhedra_Library

namespace std {

/*! \relates Parma_Polyhedra_Library::Congruence */
inline void
swap(Parma_Polyhedra_Library::Congruence& x,
     Parma_Polyhedra_Library::Congruence& y) {
  x.swap(y);
}

} // namespace std

// Automatically generated from PPL source file ../src/Congruence.defs.hh line 473

// Automatically generated from PPL source file ../src/Generator_System.inlines.hh line 1
/* Generator_System class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/Generator_System.inlines.hh line 27

namespace Parma_Polyhedra_Library {

inline
Generator_System::Generator_System()
  : Linear_System(NECESSARILY_CLOSED) {
}

inline
Generator_System::Generator_System(const Generator& g)
  : Linear_System(g.topology()) {
  Linear_System::insert(g);
}

inline
Generator_System::Generator_System(const Generator_System& gs)
  : Linear_System(gs) {
}

inline
Generator_System::Generator_System(const Topology topol)
  : Linear_System(topol) {
}

inline
Generator_System::Generator_System(const Topology topol,
				   const dimension_type n_rows,
				   const dimension_type n_columns)
  : Linear_System(topol, n_rows, n_columns) {
}

inline
Generator_System::~Generator_System() {
}

inline Generator_System&
Generator_System::operator=(const Generator_System& y) {
  Linear_System::operator=(y);
  return *this;
}

inline dimension_type
Generator_System::max_space_dimension() {
  return Linear_System::max_space_dimension();
}

inline dimension_type
Generator_System::space_dimension() const {
  return Linear_System::space_dimension();
}

inline void
Generator_System::clear() {
  Linear_System::clear();
}

inline Generator&
Generator_System::operator[](const dimension_type k) {
  return static_cast<Generator&>(Linear_System::operator[](k));
}

inline const Generator&
Generator_System::operator[](const dimension_type k) const {
  return static_cast<const Generator&>(Linear_System::operator[](k));
}

inline
Generator_System::const_iterator::const_iterator()
  : i(), gsp(0) {
}

inline
Generator_System::const_iterator::const_iterator(const const_iterator& y)
  : i(y.i), gsp(y.gsp) {
}

inline
Generator_System::const_iterator::~const_iterator() {
}

inline
Generator_System::const_iterator&
Generator_System::const_iterator::operator=(const const_iterator& y) {
  i = y.i;
  gsp = y.gsp;
  return *this;
}

inline const Generator&
Generator_System::const_iterator::operator*() const {
  return static_cast<const Generator&>(*i);
}

inline const Generator*
Generator_System::const_iterator::operator->() const {
  return static_cast<const Generator*>(i.operator->());
}

inline Generator_System::const_iterator&
Generator_System::const_iterator::operator++() {
  ++i;
  if (!gsp->is_necessarily_closed())
    skip_forward();
  return *this;
}

inline Generator_System::const_iterator
Generator_System::const_iterator::operator++(int) {
  const const_iterator tmp = *this;
  operator++();
  return tmp;
}

inline bool
Generator_System::const_iterator::operator==(const const_iterator& y) const {
  return i == y.i;
}

inline bool
Generator_System::const_iterator::operator!=(const const_iterator& y) const {
  return i != y.i;
}

inline
Generator_System::const_iterator::
const_iterator(const Linear_System::const_iterator& iter,
	       const Generator_System& gsys)
  : i(iter), gsp(&gsys) {
}

inline Generator_System::const_iterator
Generator_System::begin() const {
  const_iterator i(Linear_System::begin(), *this);
  if (!is_necessarily_closed())
    i.skip_forward();
  return i;
}

inline Generator_System::const_iterator
Generator_System::end() const {
  const const_iterator i(Linear_System::end(), *this);
  return i;
}

inline const Generator_System&
Generator_System::zero_dim_univ() {
  static const Generator_System zdu(Generator::zero_dim_point());
  return zdu;
}

inline void
Generator_System::swap(Generator_System& y) {
  Linear_System::swap(y);
}

inline memory_size_type
Generator_System::external_memory_in_bytes() const {
  return Linear_System::external_memory_in_bytes();
}

inline memory_size_type
Generator_System::total_memory_in_bytes() const {
  return Linear_System::total_memory_in_bytes();
}

inline void
Generator_System::simplify() {
  Linear_System::simplify();
  remove_invalid_lines_and_rays();
}

} // namespace Parma_Polyhedra_Library


namespace std {

/*! \relates Parma_Polyhedra_Library::Constraint_System */
inline void
swap(Parma_Polyhedra_Library::Generator_System& x,
     Parma_Polyhedra_Library::Generator_System& y) {
  x.swap(y);
}

} // namespace std

// Automatically generated from PPL source file ../src/Grid_Generator_System.inlines.hh line 1
/* Grid_Generator_System class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/Grid_Generator_System.inlines.hh line 28

namespace Parma_Polyhedra_Library {

inline
Grid_Generator_System::Grid_Generator_System()
  : Generator_System(NECESSARILY_CLOSED) {
  adjust_topology_and_space_dimension(NECESSARILY_CLOSED, 1);
  set_sorted(false);
}

inline
Grid_Generator_System::Grid_Generator_System(const Grid_Generator_System& gs)
  : Generator_System(gs) {
}

inline
Grid_Generator_System::Grid_Generator_System(dimension_type dim)
  : Generator_System(NECESSARILY_CLOSED) {
  adjust_topology_and_space_dimension(NECESSARILY_CLOSED, dim + 1);
  set_sorted(false);
}

inline
Grid_Generator_System::Grid_Generator_System(const Grid_Generator& g)
  : Generator_System(g) {
  set_sorted(false);
}

inline dimension_type
Grid_Generator_System::max_space_dimension() {
  // Grid generators use an extra column for the parameter divisor.
  return Generator_System::max_space_dimension() - 1;
}

inline dimension_type
Grid_Generator_System::space_dimension() const {
  assert(Generator_System::space_dimension() > 0);
  // Grid generators use an extra column for the parameter divisor.
  return Generator_System::space_dimension() - 1;
}

inline void
Grid_Generator_System::clear() {
  Generator_System::clear();
  // For grid generators, two extra columns are needed.
  add_zero_columns(2);
  set_sorted(false);
  unset_pending_rows();
}

inline void
Grid_Generator_System::swap(Grid_Generator_System& y) {
  Generator_System::swap(y);
}

inline memory_size_type
Grid_Generator_System::external_memory_in_bytes() const {
  return Generator_System::external_memory_in_bytes();
}

inline memory_size_type
Grid_Generator_System::total_memory_in_bytes() const {
  return Generator_System::total_memory_in_bytes();
}

inline dimension_type
Grid_Generator_System::num_generators() const {
  return Generator_System::num_rows();
}

inline dimension_type
Grid_Generator_System::num_parameters() const {
  return Generator_System::num_rays();
}

inline dimension_type
Grid_Generator_System::num_lines() const {
  return Generator_System::num_lines();
}

inline
Grid_Generator_System::const_iterator::const_iterator()
  : Generator_System::const_iterator() {
}

inline
Grid_Generator_System::const_iterator::const_iterator(const const_iterator& y)
  : Generator_System::const_iterator(y) {
}

inline
Grid_Generator_System::const_iterator::~const_iterator() {
}

inline
Grid_Generator_System::const_iterator&
Grid_Generator_System::const_iterator::operator=(const const_iterator& y) {
  return static_cast<Grid_Generator_System::const_iterator&>
    (Generator_System::const_iterator::operator=(y));
}

inline const Grid_Generator&
Grid_Generator_System::const_iterator::operator*() const {
  return static_cast<const Grid_Generator&>
    (Generator_System::const_iterator::operator*());
}

inline const Grid_Generator*
Grid_Generator_System::const_iterator::operator->() const {
  return static_cast<const Grid_Generator*>
    (Generator_System::const_iterator::operator->());
}

inline Grid_Generator_System::const_iterator&
Grid_Generator_System::const_iterator::operator++() {
  return static_cast<Grid_Generator_System::const_iterator&>
    (Generator_System::const_iterator::operator++());
}

inline Grid_Generator_System::const_iterator
Grid_Generator_System::const_iterator::operator++(int) {
  const const_iterator tmp = *this;
  operator++();
  return tmp;
}

inline bool
Grid_Generator_System
::const_iterator::operator==(const const_iterator& y) const {
  return Generator_System::const_iterator::operator==(y);
}

inline bool
Grid_Generator_System
::const_iterator::operator!=(const const_iterator& y) const {
  return Generator_System::const_iterator::operator!=(y);
}

inline Grid_Generator_System::const_iterator
Grid_Generator_System::begin() const {
  return static_cast<Grid_Generator_System::const_iterator>
    (Generator_System::begin());
}

inline Grid_Generator_System::const_iterator
Grid_Generator_System::end() const {
  return static_cast<Grid_Generator_System::const_iterator>
    (Generator_System::end());
}

inline
Grid_Generator_System
::const_iterator::const_iterator(const Generator_System::const_iterator& y)
  : Generator_System::const_iterator::const_iterator(y) {
}

inline bool
Grid_Generator_System::has_points() const {
  return Generator_System::has_points();
}

inline Grid_Generator&
Grid_Generator_System::operator[](const dimension_type k) {
  return static_cast<Grid_Generator&>(Generator_System::operator[](k));
}

inline const Grid_Generator&
Grid_Generator_System::operator[](const dimension_type k) const {
  return static_cast<const Grid_Generator&>(Generator_System::operator[](k));
}

inline void
Grid_Generator_System::ascii_dump(std::ostream& s) const {
  return Generator_System::ascii_dump(s);
}

inline void
Grid_Generator_System::set_sorted(bool b) {
  Generator_System::set_sorted(b);
}

inline void
Grid_Generator_System::unset_pending_rows() {
  Generator_System::unset_pending_rows();
}

inline void
Grid_Generator_System::set_index_first_pending_row(const dimension_type i) {
  Generator_System::set_index_first_pending_row(i);
}

inline void
Grid_Generator_System::resize_no_copy(const dimension_type new_n_rows,
				      const dimension_type new_n_columns) {
  Generator_System::resize_no_copy(new_n_rows, new_n_columns);
}

inline dimension_type
Grid_Generator_System::num_columns() const {
  return Generator_System::num_columns();
}

inline void
Grid_Generator_System::erase_to_end(dimension_type first_to_erase) {
  return Generator_System::erase_to_end(first_to_erase);
}

inline void
Grid_Generator_System
::permute_columns(const std::vector<dimension_type>& cycles) {
  return Generator_System::permute_columns(cycles);
}

inline bool
Grid_Generator_System::is_equal_to(const Grid_Generator_System y) const {
  return operator==(static_cast<const Generator_System&>(*this),
		    static_cast<const Generator_System&>(y));
}

/*! \relates Grid_Generator_System */
inline bool
operator==(const Grid_Generator_System& x,
	   const Grid_Generator_System& y) {
  return x.is_equal_to(y);
}

} // namespace Parma_Polyhedra_Library


namespace std {

/*! \relates Parma_Polyhedra_Library::Constraint_System */
inline void
swap(Parma_Polyhedra_Library::Grid_Generator_System& x,
     Parma_Polyhedra_Library::Grid_Generator_System& y) {
  x.swap(y);
}

} // namespace std

// Automatically generated from PPL source file ../src/Congruence_System.inlines.hh line 1
/* Congruence_System class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/Congruence_System.inlines.hh line 27

namespace Parma_Polyhedra_Library {

inline
Congruence_System::Congruence_System()
  : Matrix(0, 2) {
}

inline
Congruence_System::Congruence_System(const Congruence& cg)
  : Matrix(0, 2) {
  insert(cg);
}

inline
Congruence_System::Congruence_System(const Constraint& c)
  : Matrix(0, 2) {
  insert(c);
}

inline
Congruence_System::Congruence_System(const Congruence_System& cs)
  : Matrix(cs) {
}

inline
Congruence_System::~Congruence_System() {
}

inline Congruence_System&
Congruence_System::operator=(const Congruence_System& y) {
  Matrix::operator=(y);
  return *this;
}

inline Congruence&
Congruence_System::operator[](const dimension_type k) {
  return static_cast<Congruence&>(Matrix::operator[](k));
}

inline const Congruence&
Congruence_System::operator[](const dimension_type k) const {
  return static_cast<const Congruence&>(Matrix::operator[](k));
}

inline dimension_type
Congruence_System::max_space_dimension() {
  return Matrix::max_num_columns() - 2;
}

inline dimension_type
Congruence_System::space_dimension() const {
  return Matrix::num_columns() - 2;
}

inline void
Congruence_System::clear() {
  Matrix::clear();
  add_zero_columns(2);		// Modulus and constant term.
}

inline void
Congruence_System::insert(const Congruence& cg) {
  insert_verbatim(cg);
  static_cast<Congruence&>(operator[](rows.size()-1)).strong_normalize();
  assert(OK());
}

inline void
Congruence_System::resize_no_copy(const dimension_type new_n_rows,
				  const dimension_type new_n_columns) {
  Matrix::resize_no_copy(new_n_rows, new_n_columns, Row::Flags());
}

inline const Congruence_System&
Congruence_System::zero_dim_empty() {
  static const Congruence_System zdf(Congruence::zero_dim_false());
  return zdf;
}

inline
Congruence_System::const_iterator::const_iterator()
  : i(), csp(0) {
}

inline
Congruence_System::const_iterator::const_iterator(const const_iterator& y)
  : i(y.i), csp(y.csp) {
}

inline
Congruence_System::const_iterator::~const_iterator() {
}

inline Congruence_System::const_iterator&
Congruence_System::const_iterator::operator=(const const_iterator& y) {
  i = y.i;
  csp = y.csp;
  return *this;
}

inline const Congruence&
Congruence_System::const_iterator::operator*() const {
  return static_cast<const Congruence&>(*i);
}

inline const Congruence*
Congruence_System::const_iterator::operator->() const {
  return static_cast<const Congruence*>(i.operator->());
}

inline Congruence_System::const_iterator&
Congruence_System::const_iterator::operator++() {
  ++i;
  skip_forward();
  return *this;
}

inline Congruence_System::const_iterator
Congruence_System::const_iterator::operator++(int) {
  const const_iterator tmp = *this;
  operator++();
  return tmp;
}

inline bool
Congruence_System::const_iterator::operator==(const const_iterator& y) const {
  return i == y.i;
}

inline bool
Congruence_System::const_iterator::operator!=(const const_iterator& y) const {
  return i != y.i;
}

inline
Congruence_System::const_iterator::
const_iterator(const Matrix::const_iterator& iter,
	       const Congruence_System& csys)
  : i(iter), csp(&csys) {
}

inline Congruence_System::const_iterator
Congruence_System::begin() const {
  const_iterator i(Matrix::begin(), *this);
  i.skip_forward();
  return i;
}

inline Congruence_System::const_iterator
Congruence_System::end() const {
  const const_iterator i(Matrix::end(), *this);
  return i;
}

inline void
Congruence_System::swap(Congruence_System& y) {
  Matrix::swap(y);
}

inline memory_size_type
Congruence_System::external_memory_in_bytes() const {
  return Matrix::external_memory_in_bytes();
}

inline memory_size_type
Congruence_System::total_memory_in_bytes() const {
  return Matrix::total_memory_in_bytes();
}

} // namespace Parma_Polyhedra_Library


namespace std {

/*! \relates Parma_Polyhedra_Library::Congruence_System */
inline void
swap(Parma_Polyhedra_Library::Congruence_System& x,
     Parma_Polyhedra_Library::Congruence_System& y) {
  x.swap(y);
}

} // namespace std

// Automatically generated from PPL source file ../src/Scalar_Products.defs.hh line 1
/* Scalar_Products class definition.
*/


// Automatically generated from PPL source file ../src/Scalar_Products.defs.hh line 34

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A class implementing various scalar product functions.
/*! \ingroup PPL_CXX_interface
  When computing the scalar product of (Linear_Row or Constraint or
  Generator) objects <CODE>x</CODE> and <CODE>y</CODE>, it is assumed
  that the space dimension of the first object <CODE>x</CODE> is less
  than or equal to the space dimension of the second object <CODE>y</CODE>.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
class Parma_Polyhedra_Library::Scalar_Products {
public:
  //! Computes the scalar product of \p x and \p y and assigns it to \p z.
  static void assign(Coefficient& z, const Linear_Row& x, const Linear_Row& y);
  //! Computes the scalar product of \p c and \p g and assigns it to \p z.
  static void assign(Coefficient& z, const Constraint& c, const Generator& g);
  //! Computes the scalar product of \p g and \p c and assigns it to \p z.
  static void assign(Coefficient& z, const Generator& g, const Constraint& c);
  //! Computes the scalar product of \p g and \p cg and assigns it to \p z.
  static void assign(Coefficient& z,
		     const Grid_Generator& g, const Congruence& cg);
  //! Computes the scalar product of \p cg and \p g and assigns it to \p z.
  static void assign(Coefficient& z,
		     const Congruence& cg, const Grid_Generator& g);

  //! Returns the sign of the scalar product between \p x and \p y.
  static int sign(const Linear_Row& x, const Linear_Row& y);
  //! Returns the sign of the scalar product between \p c and \p g.
  static int sign(const Constraint& c, const Generator& g);
  //! Returns the sign of the scalar product between \p g and \p c.
  static int sign(const Generator& g, const Constraint& c);

  /*! \brief
    Computes the \e reduced scalar product of \p x and \p y,
    where the \f$\epsilon\f$ coefficient of \p x is ignored,
    and assigns the result to \p z.
  */
  static void reduced_assign(Coefficient& z,
			     const Linear_Row& x, const Linear_Row& y);
  /*! \brief
    Computes the \e reduced scalar product of \p c and \p g,
    where the \f$\epsilon\f$ coefficient of \p c is ignored,
    and assigns the result to \p z.
  */
  static void reduced_assign(Coefficient& z,
			     const Constraint& c, const Generator& g);
  /*! \brief
    Computes the \e reduced scalar product of \p g and \p c,
    where the \f$\epsilon\f$ coefficient of \p g is ignored,
    and assigns the result to \p z.
  */
  static void reduced_assign(Coefficient& z,
			     const Generator& g, const Constraint& c);
  //! \brief
  //! Computes the \e reduced scalar product of \p g and \p cg,
  //! where the \f$\epsilon\f$ coefficient of \p g is ignored,
  //! and assigns the result to \p z.
  static void reduced_assign(Coefficient& z,
			     const Grid_Generator& g, const Congruence& cg);

  /*! \brief
    Returns the sign of the \e reduced scalar product of \p x and \p y,
    where the \f$\epsilon\f$ coefficient of \p x is ignored.
  */
  static int reduced_sign(const Linear_Row& x, const Linear_Row& y);
  /*! \brief
    Returns the sign of the \e reduced scalar product of \p c and \p g,
    where the \f$\epsilon\f$ coefficient of \p c is ignored.
  */
  static int reduced_sign(const Constraint& c, const Generator& g);
  /*! \brief
    Returns the sign of the \e reduced scalar product of \p g and \p c,
    where the \f$\epsilon\f$ coefficient of \p g is ignored.
  */
  static int reduced_sign(const Generator& g, const Constraint& c);

  /*! \brief
    Computes the \e homogeneous scalar product of \p x and \p y,
    where the inhomogeneous terms are ignored,
    and assigns the result to \p z.
  */
  static void homogeneous_assign(Coefficient& z,
				 const Linear_Row& x, const Linear_Row& y);
  /*! \brief
    Computes the \e homogeneous scalar product of \p e and \p g,
    where the inhomogeneous terms are ignored,
    and assigns the result to \p z.
  */
  static void homogeneous_assign(Coefficient& z,
				 const Linear_Expression& e,
				 const Generator& g);
  //! \brief
  //! Computes the \e homogeneous scalar product of \p g and \p cg,
  //! where the inhomogeneous terms are ignored,
  //! and assigns the result to \p z.
  static void homogeneous_assign(Coefficient& z,
				 const Grid_Generator& g, const Congruence& cg);
  //! \brief
  //! Computes the \e homogeneous scalar product of \p e and \p g,
  //! where the inhomogeneous terms are ignored,
  //! and assigns the result to \p z.
  static void homogeneous_assign(Coefficient& z,
				 const Linear_Expression& e,
				 const Grid_Generator& g);

  /*! \brief
    Returns the sign of the \e homogeneous scalar product of \p x and \p y,
    where the inhomogeneous terms are ignored.
  */
  static int homogeneous_sign(const Linear_Row& x, const Linear_Row& y);
  /*! \brief
    Returns the sign of the \e homogeneous scalar product of \p e and \p g,
    where the inhomogeneous terms are ignored.
  */
  static int homogeneous_sign(const Linear_Expression& e, const Generator& g);
  //! \brief
  //! Returns the sign of the \e homogeneous scalar product of \p e and \p g,
  //! where the inhomogeneous terms are ignored,
  static int homogeneous_sign(const Linear_Expression& e,
			      const Grid_Generator& g);
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Scalar product sign function object depending on topology.
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
class Parma_Polyhedra_Library::Topology_Adjusted_Scalar_Product_Sign {
public:
  //! Constructs the function object according to the topology of \p c.
  Topology_Adjusted_Scalar_Product_Sign(const Constraint& c);
  //! Constructs the function object according to the topology of \p g.
  Topology_Adjusted_Scalar_Product_Sign(const Generator& g);

  //! Computes the (topology adjusted) scalar product sign of \p c and \p g.
  int operator()(const Constraint&, const Generator&) const;
  //! Computes the (topology adjusted) scalar product sign of \p g and \p c.
  int operator()(const Generator&, const Constraint&) const;

private:
  //! The type of the scalar product sign function pointer.
  typedef int (*SPS_type)(const Linear_Row&, const Linear_Row&);

  //! The scalar product sign function pointer.
  SPS_type sps_fp;
};

// Automatically generated from PPL source file ../src/Scalar_Products.inlines.hh line 1
/* Scalar_Products class implementation (inline functions).
*/


// Automatically generated from PPL source file ../src/Scalar_Products.inlines.hh line 32

namespace Parma_Polyhedra_Library {

inline int
Scalar_Products::sign(const Linear_Row& x, const Linear_Row& y) {
  TEMP_INTEGER(z);
  assign(z, x, y);
  return sgn(z);
}

inline int
Scalar_Products::reduced_sign(const Linear_Row& x, const Linear_Row& y) {
  TEMP_INTEGER(z);
  reduced_assign(z, x, y);
  return sgn(z);
}

inline int
Scalar_Products::homogeneous_sign(const Linear_Row& x, const Linear_Row& y) {
  TEMP_INTEGER(z);
  homogeneous_assign(z, x, y);
  return sgn(z);
}

inline int
Scalar_Products::sign(const Constraint& c, const Generator& g) {
  return sign(static_cast<const Linear_Row&>(c),
	      static_cast<const Linear_Row&>(g));
}

inline int
Scalar_Products::sign(const Generator& g, const Constraint& c) {
  return sign(static_cast<const Linear_Row&>(g),
	      static_cast<const Linear_Row&>(c));
}

inline int
Scalar_Products::reduced_sign(const Constraint& c, const Generator& g) {
  return reduced_sign(static_cast<const Linear_Row&>(c),
		      static_cast<const Linear_Row&>(g));
}

inline int
Scalar_Products::reduced_sign(const Generator& g, const Constraint& c) {
  return reduced_sign(static_cast<const Linear_Row&>(g),
		      static_cast<const Linear_Row&>(c));
}

inline void
Scalar_Products::homogeneous_assign(Coefficient& z,
				    const Linear_Expression& e,
				    const Generator& g) {
  homogeneous_assign(z,
		     static_cast<const Linear_Row&>(e),
		     static_cast<const Linear_Row&>(g));
}

inline void
Scalar_Products::homogeneous_assign(Coefficient& z,
				    const Linear_Expression& e,
				    const Grid_Generator& g) {
  homogeneous_assign(z,
		     static_cast<const Linear_Row&>(e),
		     static_cast<const Linear_Row&>(g));
}

inline int
Scalar_Products::homogeneous_sign(const Linear_Expression& e,
				  const Generator& g) {
  return homogeneous_sign(static_cast<const Linear_Row&>(e),
			  static_cast<const Linear_Row&>(g));
}

inline int
Scalar_Products::homogeneous_sign(const Linear_Expression& e,
				  const Grid_Generator& g) {
  return homogeneous_sign(static_cast<const Linear_Row&>(e),
			  static_cast<const Linear_Row&>(g));
}

inline
Topology_Adjusted_Scalar_Product_Sign
::Topology_Adjusted_Scalar_Product_Sign(const Constraint& c)
  : sps_fp(c.is_necessarily_closed()
	   ? static_cast<SPS_type>(&Scalar_Products::sign)
	   : static_cast<SPS_type>(&Scalar_Products::reduced_sign)) {
}

inline
Topology_Adjusted_Scalar_Product_Sign
::Topology_Adjusted_Scalar_Product_Sign(const Generator& g)
  : sps_fp(g.is_necessarily_closed()
	   ? static_cast<SPS_type>(&Scalar_Products::sign)
	   : static_cast<SPS_type>(&Scalar_Products::reduced_sign)) {
}

inline int
Topology_Adjusted_Scalar_Product_Sign::operator()(const Constraint& c,
						  const Generator& g) const {
  assert(c.space_dimension() <= g.space_dimension());
  assert(sps_fp == (c.is_necessarily_closed()
		    ? static_cast<SPS_type>(&Scalar_Products::sign)
		    : static_cast<SPS_type>(&Scalar_Products::reduced_sign)));
  return sps_fp(static_cast<const Linear_Row&>(c),
		static_cast<const Linear_Row&>(g));
}

inline int
Topology_Adjusted_Scalar_Product_Sign::operator()(const Generator& g,
						  const Constraint& c) const {
  assert(g.space_dimension() <= c.space_dimension());
  assert(sps_fp == (g.is_necessarily_closed()
		    ? static_cast<SPS_type>(&Scalar_Products::sign)
		    : static_cast<SPS_type>(&Scalar_Products::reduced_sign)));
  return sps_fp(static_cast<const Linear_Row&>(g),
		static_cast<const Linear_Row&>(c));
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Scalar_Products.defs.hh line 181

// Automatically generated from PPL source file ../src/LP_Problem.defs.hh line 1
/* LP_Problem class declaration.
*/


// Automatically generated from PPL source file ../src/LP_Problem.defs.hh line 34
#include <vector>
#include <map>
#include <iosfwd>

//! A Linear Programming problem.
/*! \ingroup PPL_CXX_interface */
class Parma_Polyhedra_Library::LP_Problem {
public:
  //! Default constructor: builds a trivial LP problem.
  /*!
    The trivial LP problem requires to maximize the objective function
    \f$0\f$ on the zero-dimensional vector space under no constraints
    at all: the origin of the vector space is the optimal solution.
  */
  LP_Problem();

  /*! \brief
    Builds an LP problem from the constraint system \p cs, the objective
    function \p obj and optimization mode \p mode.

    \param cs
    The constraint system defining the feasible region for the LP problem.

    \param obj
    The objective function for the LP problem (optional argument with
    default value \f$0\f$).

    \param mode
    The optimization mode (optional argument with default value
    <CODE>MAXIMIZATION</CODE>).

    \exception std::invalid_argument
    Thrown if the constraint system contains any strict inequality
    or if the space dimension of the objective function is strictly
    greater than the space dimension of the constraint system.
  */
  explicit LP_Problem(const Constraint_System& cs,
		      const Linear_Expression& obj = Linear_Expression::zero(),
		      Optimization_Mode mode = MAXIMIZATION);

  //! Ordinary copy-constructor.
  LP_Problem(const LP_Problem& y);

  //! Destructor.
  ~LP_Problem();

  //! Assignment operator.
  LP_Problem& operator=(const LP_Problem& y);

  //! Returns the maximum space dimension a LP_Problem can handle.
  static dimension_type max_space_dimension();

  //! Returns the space dimension of the current LP problem.
  dimension_type space_dimension() const;

  //! Returns the constraints defining the current feasible region.
  const Constraint_System& constraints() const;

  //! Returns the current objective function.
  const Linear_Expression& objective_function() const;

  //! Returns the current optimization mode.
  Optimization_Mode optimization_mode() const;

  //! Resets \p *this to be equal to the trivial LP problem.
  void clear();

  /*! \brief
    Adds a copy of constraint \p c to the current LP problem,
    increasing the number of space dimensions if needed.

    \exception std::invalid_argument
    Thrown if the constraint \p c is a strict inequality.
  */
  void add_constraint(const Constraint& c);

  /*! \brief
    Adds a copy of the constraints in \p cs to the current LP problem,
    increasing the number of space dimensions if needed.

    \exception std::invalid_argument
    Thrown if the constraint system \p cs contains any strict inequality.
  */
  void add_constraints(const Constraint_System& cs);

  //! Sets the objective function to \p obj.
  /*!
    \exception std::invalid_argument
    Thrown if the space dimension of \p obj is strictly greater than
    the space dimension of \p *this.
  */
  void set_objective_function(const Linear_Expression& obj);

  //! Sets the optimization mode to \p mode.
  void set_optimization_mode(Optimization_Mode mode);

  //! Checks satisfiability of \p *this.
  /*!
    \return
    <CODE>true</CODE> if and only if the LP problem is satisfiable.
  */
  bool is_satisfiable() const;

  //! Optimizes the current LP problem using the primal simplex algorithm.
  /*!
    \return
    An LP_Problem_Status flag indicating the outcome of the optimization
    attempt (unfeasible, unbounded or optimized problem).
  */
  LP_Problem_Status solve() const;

  /*! \brief
    Sets \p num and \p den so that \f$\frac{num}{den}\f$ is the result
    of evaluating the objective function on \p evaluating_point.

    \param evaluating_point
    The point on which the objective function will be evaluated.

    \param num
    On exit will contain the numerator of the evaluated value.

    \param den
    On exit will contain the denominator of the evaluated value.

    \exception std::invalid_argument
    Thrown if \p *this and \p evaluating_point are dimension-incompatible
    or if the generator \p evaluating_point is not a point.
  */
  void evaluate_objective_function(const Generator& evaluating_point,
				   Coefficient& num,
				   Coefficient& den) const;

  //! Returns a feasible point for \p *this, if it exists.
  /*!
    \exception std::domain_error
    Thrown if the LP problem is not satisfiable.
  */
  const Generator& feasible_point() const;

  //! Returns an optimal point for \p *this, if it exists.
  /*!
    \exception std::domain_error
    Thrown if \p *this doesn't not have an optimizing point, i.e.,
    if the LP problem is unbounded or not satisfiable.
  */
  const Generator& optimizing_point() const;

  /*! \brief
    Sets \p num and \p den so that \f$\frac{num}{den}\f$ is
    the solution of the optimization problem.

    \exception std::domain_error
    Thrown if \p *this doesn't not have an optimizing point, i.e.,
    if the LP problem is unbounded or not satisfiable.
  */
  void optimal_value(Coefficient& num, Coefficient& den) const;

  //! Checks if all the invariants are satisfied.
  bool OK() const;

  PPL_OUTPUT_DECLARATIONS;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    \ref ascii_dump) and sets \p *this accordingly.
    Returns <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  bool ascii_load(std::istream& s);

  //! Returns the total size in bytes of the memory occupied by \p *this.
  memory_size_type total_memory_in_bytes() const;

  //! Returns the size in bytes of the memory managed by \p *this.
  memory_size_type external_memory_in_bytes() const;

  //! Swaps \p *this with \p y.
  void swap(LP_Problem& y);

private:
  //! The matrix encoding the current feasible region in tableau form.
  Matrix tableau;
  //! The working cost function.
  Row working_cost;
  //! The current basic solution.
  std::vector<dimension_type> base;
  //! A mapping between original variables and split ones.
  /*!
    Contains all the pairs (i, j) such that Variable(i) (that was not found
    to be constrained in sign) has been split into two nonnegative variables.
    The "positive" one is represented again by Variable(i), and
    the "negative" one is represented by Variable(j).
  */
  std::map<dimension_type, dimension_type> dim_map;

  //! An enumerated type describing the internal status of the LP problem.
  enum Status {
    //! The LP problem has not been solved yet.
    UNSOLVED,
    //! The LP problem is unsatisfiable.
    UNSATISFIABLE,
    //! The LP problem is satisfiable; a feasible solution has been computed.
    SATISFIABLE,
    //! The LP problem is unbounded; a feasible solution has been computed.
    UNBOUNDED,
    //! The LP problem is optimized; an optimal solution has been computed.
    OPTIMIZED,
    /*! \brief
      The feasible region of the LP problem has been changed by adding
      new constraints; a feasible solution for the old constraints has
      been computed.
    */
    PARTIALLY_SATISFIABLE
  };

  //! The internal state of the LP problem.
  Status status;

  //! The constraint system describing the feasible region.
  Constraint_System input_cs;

  //! The objective function to be optimized.
  Linear_Expression input_obj_function;

  //! The optimization mode requested.
  Optimization_Mode opt_mode;

  //! The last successfully computed feasible or optimizing point.
  Generator last_generator;

  /*! \brief
    Optimizes the current LP problem using the second phase of the
    primal simplex algorithm.
  */
  void second_phase();

  /*! \brief
    Assigns to \p this->tableau a simplex tableau representing the
    current LP problem, inserting into \p this->dim_map the information
    that is required to recover the original LP problem.

    \return
    <CODE>UNFEASIBLE_LP_PROBLEM</CODE> if the constraint system contains
    any trivially unfeasible constraint (tableau was not computed);
    <CODE>UNBOUNDED_LP_PROBLEM</CODE> if the problem is trivially unbounded
    (the computed tableau contains no constraints);
    <CODE>OPTIMIZED_LP_PROBLEM></CODE> if the problem is neither trivially
    unfeasible nor trivially unbounded (the tableau was computed successfully).
  */
  LP_Problem_Status compute_tableau();

  /*! \brief
    Checks for optimality and, if it does not hold, computes the column
    index of the variable entering the base of the LP problem.
    Implemented with anti-cycling rule.

    \return
    The column index of the variable that enters the base. If no such
    variable exists, optimality was achieved and <CODE>0</CODE> is retuned.
  */
  dimension_type get_entering_var_index() const;

  /*! \brief
    Computes the row index of the variable exiting the base
    of the LP problem. Implemented with anti-cycling rules.

    \return
    The row index of the variable exiting the base.

    \param entering_var_index
    The column index of the variable entering the base.
  */
  dimension_type
  get_exiting_base_index(dimension_type entering_var_index) const;

  //! Linearly combines \p x with \p y so that <CODE>*this[k]</CODE> is 0.
  /*!
    \param x
    The Row that will be combined with \p y object.

    \param y
    The Row that will be combined with \p x object.

    \param k
    The position of \p *this that have to be \f$0\f$.

    Computes a linear combination of \p x and \p y having
    the element of index \p k equal to \f$0\f$. Then it assigns
    the resulting Linear_Row to \p x and normalizes it.
  */
  static void linear_combine(Row& x, const Row& y, const dimension_type k);

  /*! \brief
    Swaps two variables in base during the simplex algorithm,
    performing the needed linear combinations.

    \param entering_var_index
    The index of the variable entering the base.

    \param exiting_base_index
    The index of the row exiting the base.
  */
  void swap_base(const dimension_type entering_var_index,
		 const dimension_type exiting_base_index);

  /*! \brief
    Checks for optimality and, if it does not hold, computes the column
    index of the variable entering the base of the LP problem.

    \return
    The column index of the variable that enters the base. If no such
    variable exists, optimality was achieved and <CODE>0</CODE> is retuned.

    To compute the entering_index, the steepest edge algorithm chooses
    the index `j' such that \f$\frac{d_{j}}{\|\Delta x^{j} \|}\f$ is the
    largest in absolute value, where
    \f[
      \|\Delta x^{j} \|
        = \left(
            1+\sum_{i=1}^{m} \alpha_{ij}^2
          \right)^{\frac{1}{2}}.
    \f]
    Recall that, due to the Integer implementation of the algorithm, our
    tableau doesn't contain the ``real'' \f$\alpha\f$ values, but these
    can be computed dividing the value of the cofficient by the value of
    the variable in base. Obviously the result may not be an Integer, so
    we will proceed in another way: the following code will compute the
    lcm of all the variables in base to get the good ``weight'' of each
    Coefficient of the tableau.
  */
  dimension_type steepest_edge() const;

  /*! \brief
    Returns <CODE>true</CODE> if and if only the algorithm successfully
    computed a feasible solution.
  */
  bool compute_simplex();

  /*! \brief
    Adds the slack variables to satisfy the standard form of a LP problem,
    inserts the "sign" to the cost functions, and makes the
    necessary swaps to express the problem with the 1st phase base.
  */
  void prepare_first_phase();

  /*! \brief
    Drop unnecessary slack variables from the tableau and get ready
    for the second phase of the simplex algorithm.
  */
  void erase_slacks();

  bool is_in_base(const dimension_type var_index,
		  dimension_type& row_index) const;

  Generator compute_generator() const;
};

// Automatically generated from PPL source file ../src/LP_Problem.inlines.hh line 1
/* LP_Problem class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/LP_Problem.inlines.hh line 28
#include <stdexcept>

namespace Parma_Polyhedra_Library {

inline
LP_Problem::LP_Problem()
  : tableau(), working_cost(0, Row::Flags()),
    base(),  dim_map(), status(OPTIMIZED),
    input_cs(), input_obj_function(), opt_mode(MAXIMIZATION),
    last_generator(point()) {
  assert(OK());
}

inline
LP_Problem::LP_Problem(const Constraint_System& cs,
		       const Linear_Expression& obj,
		       const Optimization_Mode mode)
  : tableau(), working_cost(0, Row::Flags()),
    base(), dim_map(), status(UNSOLVED),
    input_cs(!cs.has_strict_inequalities()
	     ? cs
	     : (throw std::invalid_argument("PPL::LP_Problem::"
			   "LP_Problem(cs, obj, m):\n"
			   "cs contains strict inequalities."),
		cs)),
    input_obj_function(obj.space_dimension() <= cs.space_dimension()
		       ? obj
		       : (throw std::invalid_argument("PPL::LP_Problem::"
			             "LP_Problem(cs, obj, m):\n"
				     "cs and obj have "
				     "incompatible space dimensions."),
			  obj)),
    opt_mode(mode),
    last_generator(point()) {
  assert(OK());
}

inline
LP_Problem::LP_Problem(const LP_Problem& y)
  : tableau(y.tableau), working_cost(y.working_cost),
    base(y.base), dim_map(y.dim_map), status(y.status),
    input_cs(y.input_cs), input_obj_function(y.input_obj_function),
    opt_mode(y.opt_mode), last_generator(y.last_generator) {
  assert(OK());
}

inline
LP_Problem::~LP_Problem() {
}

inline void
LP_Problem::swap(LP_Problem& y) {
  std::swap(tableau, y.tableau);
  std::swap(working_cost, y.working_cost);
  std::swap(base, y.base);
  std::swap(dim_map, y.dim_map);
  std::swap(status, y.status);
  std::swap(input_cs, y.input_cs);
  std::swap(input_obj_function, y.input_obj_function);
  std::swap(opt_mode, y.opt_mode);
  std::swap(last_generator, y.last_generator);
}

inline LP_Problem&
LP_Problem::operator=(const LP_Problem& y) {
  LP_Problem tmp(y);
  swap(tmp);
  return *this;
}

inline dimension_type
LP_Problem::max_space_dimension() {
  return Constraint_System::max_space_dimension();
}

inline dimension_type
LP_Problem::space_dimension() const {
  return input_cs.space_dimension();
}

inline const Constraint_System&
LP_Problem::constraints() const {
  return input_cs;
}

inline const Linear_Expression&
LP_Problem::objective_function() const {
  return input_obj_function;
}

inline Optimization_Mode
LP_Problem::optimization_mode() const {
  return opt_mode;
}

inline void
LP_Problem::clear() {
  LP_Problem tmp;
  swap(tmp);
}

inline void
LP_Problem::add_constraint(const Constraint& c) {
  if (c.is_strict_inequality())
    throw std::invalid_argument("PPL::LP_Problem::add_constraint(c):\n"
				"c is a strict inequality.");
  input_cs.insert(c);
  if (status != UNSATISFIABLE)
    // TODO: apply an incremental version of the simplex algorithm,
    // setting `status' to PARTIALLY_SATISFIABLE;
    status = UNSOLVED;
}

inline void
LP_Problem::add_constraints(const Constraint_System& cs) {
  if (cs.has_strict_inequalities())
    throw std::invalid_argument("PPL::LP_Problem::add_constraints(cs):\n"
				"cs contains strict inequalities.");
  const dimension_type cs_num_rows = cs.num_rows();
  for (dimension_type i = cs_num_rows; i-- > 0; )
    input_cs.insert(cs[i]);
  if (status != UNSATISFIABLE)
    // TODO: apply an incremental version of the simplex algorithm,
    // setting `status' to PARTIALLY_SATISFIABLE;
    status = UNSOLVED;
  assert(OK());
}

inline void
LP_Problem::set_objective_function(const Linear_Expression& obj) {
  if (space_dimension() < obj.space_dimension())
    throw std::invalid_argument("PPL::LP_Problem::"
				"set_objective_function(obj):\n"
				"*this and obj are dimension incompatible.");
  switch (status) {
  case UNBOUNDED:
    status = SATISFIABLE;
    break;
  case OPTIMIZED:
    status = SATISFIABLE;
    break;
  default:
    break;
  }
  input_obj_function = obj;
  assert(OK());
}

inline void
LP_Problem::set_optimization_mode(Optimization_Mode mode) {
  if (opt_mode == mode)
    return;
  switch (status) {
  case UNBOUNDED:
    status = SATISFIABLE;
    break;
  case OPTIMIZED:
    status = SATISFIABLE;
    break;
  default:
    break;
  }
  opt_mode = mode;
  assert(OK());
}

inline LP_Problem_Status
LP_Problem::solve() const {
  if (is_satisfiable()) {
    LP_Problem& x = const_cast<LP_Problem&>(*this);
    x.second_phase();
    if (x.status == UNBOUNDED)
      return UNBOUNDED_LP_PROBLEM;
    if (x.status == OPTIMIZED)
      return OPTIMIZED_LP_PROBLEM;
  }
  return UNFEASIBLE_LP_PROBLEM;
}

inline const Generator&
LP_Problem::feasible_point() const {
  if (is_satisfiable()) {
    assert(OK());
    return last_generator;
  }
  throw std::domain_error("PPL::LP_Problem::feasible_point():\n"
			  "*this is not satisfiable.");
}

inline const Generator&
LP_Problem::optimizing_point() const {
  if (solve() == OPTIMIZED_LP_PROBLEM)
    return last_generator;
  throw std::domain_error("PPL::LP_Problem::optimizing_point():\n"
			  "*this doesn't have an optimizing point.");
}

inline void
LP_Problem::optimal_value(Coefficient& num, Coefficient& den) const {
  const Generator& g_ref = optimizing_point();
  evaluate_objective_function(g_ref, num, den);
  assert(OK());
}

inline memory_size_type
LP_Problem::external_memory_in_bytes() const {
  memory_size_type n
    = tableau.external_memory_in_bytes()
    + working_cost.external_memory_in_bytes()
    + input_cs.external_memory_in_bytes()
    + input_obj_function.external_memory_in_bytes()
    + last_generator.external_memory_in_bytes();
  // Adding the external memory for `base'.
  n += base.capacity() * sizeof(dimension_type);
  // Adding the external memory for `dim_map'.
  // CHECK ME: just a lower approximation?
  n += dim_map.size()
    * sizeof(std::map<dimension_type, dimension_type>::value_type);
  return n;
}

inline memory_size_type
LP_Problem::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

} // namespace Parma_Polyhedra_Library

namespace std {

/*! \relates Parma_Polyhedra_Library::LP_Problem */
inline void
swap(Parma_Polyhedra_Library::LP_Problem& x,
     Parma_Polyhedra_Library::LP_Problem& y) {
  x.swap(y);
}

} // namespace std

// Automatically generated from PPL source file ../src/LP_Problem.defs.hh line 393

// Automatically generated from PPL source file ../src/Poly_Gen_Relation.defs.hh line 1
/* Poly_Gen_Relation class declaration.
*/


// Automatically generated from PPL source file ../src/Poly_Gen_Relation.defs.hh line 28
#include <iosfwd>

namespace Parma_Polyhedra_Library {

// Put them in the namespace here to declare them friend later.

//! True if and only if \p x and \p y are logically equivalent.
/*! \relates Poly_Gen_Relation */
bool operator==(const Poly_Gen_Relation& x, const Poly_Gen_Relation& y);

//! True if and only if \p x and \p y are not logically equivalent.
/*! \relates Poly_Gen_Relation */
bool operator!=(const Poly_Gen_Relation& x, const Poly_Gen_Relation& y);

//! Yields the logical conjunction of \p x and \p y.
/*! \relates Poly_Gen_Relation */
Poly_Gen_Relation operator&&(const Poly_Gen_Relation& x,
			     const Poly_Gen_Relation& y);

/*! \brief
  Yields the assertion with all the conjuncts of \p x
  that are not in \p y.

  \relates Poly_Gen_Relation
*/
Poly_Gen_Relation operator-(const Poly_Gen_Relation& x,
			    const Poly_Gen_Relation& y);

namespace IO_Operators {

//! Output operator.
/*! \relates Parma_Polyhedra_Library::Poly_Gen_Relation */
std::ostream& operator<<(std::ostream& s, const Poly_Gen_Relation& r);

} // namespace IO_Operators

} // namespace Parma_Polyhedra_Library


//! The relation between a polyhedron and a generator
/*! \ingroup PPL_CXX_interface
  This class implements conjunctions of assertions on the relation
  between a polyhedron and a generator.
*/
class Parma_Polyhedra_Library::Poly_Gen_Relation {
private:
  //! Poly_Gen_Relation is implemented by means of a finite bitset.
  typedef unsigned int flags_t;

  //! \name Bit-masks for the individual assertions
  //@{
  static const flags_t NOTHING  = 0U;
  static const flags_t SUBSUMES = 1U << 0;
  //@} // Bit-masks for the individual assertions

  //! All assertions together.
  static const flags_t EVERYTHING
  = SUBSUMES;

  //! This holds the current bitset.
  flags_t flags;

  //! True if and only if the conjunction \p x implies the conjunction \p y.
  static bool implies(flags_t x, flags_t y);

  //! Construct from a bit-mask.
  Poly_Gen_Relation(flags_t mask);

  friend bool
  Parma_Polyhedra_Library::operator==(const Poly_Gen_Relation& x,
				      const Poly_Gen_Relation& y);

  friend bool
  Parma_Polyhedra_Library::operator!=(const Poly_Gen_Relation& x,
				      const Poly_Gen_Relation& y);

  friend Poly_Gen_Relation
  Parma_Polyhedra_Library::operator&&(const Poly_Gen_Relation& x,
				      const Poly_Gen_Relation& y);

  friend Poly_Gen_Relation
  Parma_Polyhedra_Library::operator-(const Poly_Gen_Relation& x,
				     const Poly_Gen_Relation& y);

  friend std::ostream&
  Parma_Polyhedra_Library::
  IO_Operators::operator<<(std::ostream& s, const Poly_Gen_Relation& r);

public:
#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Access the internal flags: this is needed for some foreign
    language interfaces.
  */
#endif
  flags_t get_flags() const;

public:
  //! The assertion that says nothing.
  static Poly_Gen_Relation nothing();

  //! Adding the generator would not change the polyhedron.
  static Poly_Gen_Relation subsumes();

  PPL_OUTPUT_DECLARATIONS;

  //! True if and only if \p *this implies \p y.
  bool implies(const Poly_Gen_Relation& y) const;

  //! Checks if all the invariants are satisfied.
  bool OK() const;
};

// Automatically generated from PPL source file ../src/Poly_Gen_Relation.inlines.hh line 1
/* Poly_Gen_Relation class implementation: inline functions.
*/


namespace Parma_Polyhedra_Library {

inline
Poly_Gen_Relation::Poly_Gen_Relation(flags_t mask)
  : flags(mask) {
}

inline Poly_Gen_Relation::flags_t
Poly_Gen_Relation::get_flags() const {
  return flags;
}

inline Poly_Gen_Relation
Poly_Gen_Relation::nothing() {
  return Poly_Gen_Relation(NOTHING);
}

inline Poly_Gen_Relation
Poly_Gen_Relation::subsumes() {
  return Poly_Gen_Relation(SUBSUMES);
}

inline bool
Poly_Gen_Relation::implies(flags_t x, flags_t y) {
  return (x & y) == y;
}

inline bool
Poly_Gen_Relation::implies(const Poly_Gen_Relation& y) const {
  return implies(flags, y.flags);
}

/*! \relates Poly_Gen_Relation */
inline bool
operator==(const Poly_Gen_Relation& x, const Poly_Gen_Relation& y) {
  return x.flags == y.flags;
}

/*! \relates Poly_Gen_Relation */
inline bool
operator!=(const Poly_Gen_Relation& x, const Poly_Gen_Relation& y) {
  return x.flags != y.flags;
}

/*! \relates Poly_Gen_Relation */
inline Poly_Gen_Relation
operator&&(const Poly_Gen_Relation& x, const Poly_Gen_Relation& y) {
  return Poly_Gen_Relation(x.flags | y.flags);
}

/*! \relates Poly_Gen_Relation */
inline Poly_Gen_Relation
operator-(const Poly_Gen_Relation& x, const Poly_Gen_Relation& y) {
  return Poly_Gen_Relation(x.flags & ~y.flags);
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Poly_Gen_Relation.defs.hh line 142

// Automatically generated from PPL source file ../src/BHRZ03_Certificate.defs.hh line 1
/* BHRZ03_Certificate class declaration.
*/


// Automatically generated from PPL source file ../src/BHRZ03_Certificate.defs.hh line 29
#include <cassert>
#include <vector>

//! The convergence certificate for the BHRZ03 widening operator.
/*! \ingroup PPL_CXX_interface
  Convergence certificates are used to instantiate the BHZ03 framework
  so as to define widening operators for the finite powerset domain.

  \note
  Each convergence certificate has to be used together with a
  compatible widening operator. In particular, BHRZ03_Certificate
  can certify the convergence of both the BHRZ03 and the H79 widenings.
*/
class Parma_Polyhedra_Library::BHRZ03_Certificate {
public:
  //! Default constructor.
  BHRZ03_Certificate();

  //! Constructor: computes the certificate for \p ph.
  BHRZ03_Certificate(const Polyhedron& ph);

  //! Copy constructor.
  BHRZ03_Certificate(const BHRZ03_Certificate& y);

  //! Destructor.
  ~BHRZ03_Certificate();

  //! The comparison function for certificates.
  /*!
    \return
    \f$-1\f$, \f$0\f$ or \f$1\f$ depending on whether \p *this
    is smaller than, equal to, or greater than \p y, respectively.

    Compares \p *this with \p y, using a total ordering which is a
    refinement of the limited growth ordering relation for the
    BHRZ03 widening.
  */
  int compare(const BHRZ03_Certificate& y) const;

  //! Compares \p *this with the certificate for polyhedron \p ph.
  int compare(const Polyhedron& ph) const;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Returns <CODE>true</CODE> if and only if the certificate for
    polyhedron \p ph is strictly smaller than \p *this.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  bool is_stabilizing(const Polyhedron& ph) const;

  //! A total ordering on BHRZ03 certificates.
  /*! \ingroup PPL_CXX_interface
    This binary predicate defines a total ordering on BHRZ03 certificates
    which is used when storing information about sets of polyhedra.
  */
  struct Compare {
    //! Returns <CODE>true</CODE> if and only if \p x comes before \p y.
    bool operator()(const BHRZ03_Certificate& x,
		    const BHRZ03_Certificate& y) const;
  };

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  //! Check if gathered information is meaningful.
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  bool OK() const;

private:
  //! Affine dimension of the polyhedron.
  dimension_type affine_dim;
  //! Dimension of the lineality space of the polyhedron.
  dimension_type lin_space_dim;
  //! Cardinality of a non-redundant constraint system for the polyhedron.
  dimension_type num_constraints;
  /*! \brief
    Number of non-redundant points in a generator system
    for the polyhedron.
  */
  dimension_type num_points;
  /*! \brief
    A vector containing, for each index `0 <= i < space_dim',
    the number of non-redundant rays in a generator system of the
    polyhedron having exactly `i' null coordinates.
  */
  std::vector<dimension_type> num_rays_null_coord;
};

// Automatically generated from PPL source file ../src/BHRZ03_Certificate.inlines.hh line 1
/* BHRZ03_Certificate class implementation: inline functions.
*/


namespace Parma_Polyhedra_Library {

inline
BHRZ03_Certificate::BHRZ03_Certificate()
  : affine_dim(0), lin_space_dim(0), num_constraints(0), num_points(1),
    num_rays_null_coord() {
  // This is the certificate for a zero-dim universe polyhedron.
  assert(OK());
}

inline
BHRZ03_Certificate::BHRZ03_Certificate(const BHRZ03_Certificate& y)
  : affine_dim(y.affine_dim), lin_space_dim(y.lin_space_dim),
    num_constraints(y.num_constraints), num_points(y.num_points),
    num_rays_null_coord(y.num_rays_null_coord) {
}

inline
BHRZ03_Certificate::~BHRZ03_Certificate() {
}

inline bool
BHRZ03_Certificate::is_stabilizing(const Polyhedron& ph) const {
  return compare(ph) == 1;
}

inline bool
BHRZ03_Certificate::Compare::operator()(const BHRZ03_Certificate& x,
					const BHRZ03_Certificate& y) const {
  // For an efficient evaluation of the multiset ordering based
  // on this lgo relation, we want larger elements to come first.
  return x.compare(y) == 1;
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/BHRZ03_Certificate.defs.hh line 116

// Automatically generated from PPL source file ../src/H79_Certificate.defs.hh line 1
/* H79_Certificate class declaration.
*/


// Automatically generated from PPL source file ../src/H79_Certificate.defs.hh line 29
#include <cassert>
#include <vector>

//! A convergence certificate for the H79 widening operator.
/*! \ingroup PPL_CXX_interface
  Convergence certificates are used to instantiate the BHZ03 framework
  so as to define widening operators for the finite powerset domain.
  \note
  The convergence of the H79 widening can also be certified by
  BHRZ03_Certificate.
*/
class Parma_Polyhedra_Library::H79_Certificate {
public:
  //! Default constructor.
  H79_Certificate();

  //! Constructor: computes the certificate for \p ph.
  template <typename PH>
  H79_Certificate(const PH& ph);

  //! Constructor: computes the certificate for \p ph.
  H79_Certificate(const Polyhedron& ph);

  //! Copy constructor.
  H79_Certificate(const H79_Certificate& y);

  //! Destructor.
  ~H79_Certificate();

  //! The comparison function for certificates.
  /*!
    \return
    \f$-1\f$, \f$0\f$ or \f$1\f$ depending on whether \p *this
    is smaller than, equal to, or greater than \p y, respectively.

    Compares \p *this with \p y, using a total ordering which is a
    refinement of the limited growth ordering relation for the
    H79 widening.
  */
  int compare(const H79_Certificate& y) const;

  //! Compares \p *this with the certificate for polyhedron \p ph.
  template <typename PH>
  int compare(const PH& ph) const;

  //! Compares \p *this with the certificate for polyhedron \p ph.
  int compare(const Polyhedron& ph) const;

  //! A total ordering on H79 certificates.
  /*! \ingroup PPL_CXX_interface
    This binary predicate defines a total ordering on H79 certificates
    which is used when storing information about sets of polyhedra.
  */
  struct Compare {
    //! Returns <CODE>true</CODE> if and only if \p x comes before \p y.
    bool operator()(const H79_Certificate& x,
		    const H79_Certificate& y) const;
  };

private:
  //! Affine dimension of the polyhedron.
  dimension_type affine_dim;
  //! Cardinality of a non-redundant constraint system for the polyhedron.
  dimension_type num_constraints;
};

// Automatically generated from PPL source file ../src/H79_Certificate.inlines.hh line 1
/* H79_Certificate class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/Polyhedron.defs.hh line 1
/* Polyhedron class declaration.
*/


// Automatically generated from PPL source file ../src/Polyhedron.defs.hh line 44
#include <vector>
#include <iosfwd>

namespace Parma_Polyhedra_Library {

namespace IO_Operators {

//! Output operator.
/*!
  \relates Parma_Polyhedra_Library::Polyhedron
  Writes a textual representation of \p ph on \p s:
  <CODE>false</CODE> is written if \p ph is an empty polyhedron;
  <CODE>true</CODE> is written if \p ph is a universe polyhedron;
  a minimized system of constraints defining \p ph is written otherwise,
  all constraints in one row separated by ", ".
*/
std::ostream&
operator<<(std::ostream& s, const Polyhedron& ph);

} // namespace IO_Operators

/*! \brief
  Returns <CODE>true</CODE> if and only if
  \p x and \p y are the same polyhedron.

  \relates Polyhedron
  Note that \p x and \p y may be topology- and/or dimension-incompatible
  polyhedra: in those cases, the value <CODE>false</CODE> is returned.
*/
bool operator==(const Polyhedron& x, const Polyhedron& y);

/*! \brief
  Returns <CODE>true</CODE> if and only if
  \p x and \p y are different polyhedra.

  \relates Polyhedron
  Note that \p x and \p y may be topology- and/or dimension-incompatible
  polyhedra: in those cases, the value <CODE>true</CODE> is returned.
*/
bool operator!=(const Polyhedron& x, const Polyhedron& y);

} // namespace Parma_Polyhedra_Library


//! The base class for convex polyhedra.
/*! \ingroup PPL_CXX_interface
  An object of the class Polyhedron represents a convex polyhedron
  in the vector space \f$\Rset^n\f$.

  A polyhedron can be specified as either a finite system of constraints
  or a finite system of generators (see Section \ref representation)
  and it is always possible to obtain either representation.
  That is, if we know the system of constraints, we can obtain
  from this the system of generators that define the same polyhedron
  and vice versa.
  These systems can contain redundant members: in this case we say
  that they are not in the minimal form.
  Most operators on polyhedra are provided with two implementations:
  one of these, denoted <CODE>\<operator-name\>_and_minimize</CODE>,
  also enforces the minimization of the representations,
  and returns the Boolean value <CODE>false</CODE> whenever
  the resulting polyhedron turns out to be empty.

  Two key attributes of any polyhedron are its topological kind
  (recording whether it is a C_Polyhedron or an NNC_Polyhedron object)
  and its space dimension (the dimension \f$n \in \Nset\f$ of
  the enclosing vector space):

  - all polyhedra, the empty ones included, are endowed with
    a specific topology and space dimension;
  - most operations working on a polyhedron and another object
    (i.e., another polyhedron, a constraint or generator,
    a set of variables, etc.) will throw an exception if
    the polyhedron and the object are not both topology-compatible
    and dimension-compatible (see Section \ref representation);
  - the topology of a polyhedron cannot be changed;
    rather, there are constructors for each of the two derived classes
    that will build a new polyhedron with the topology of that class
    from another polyhedron from either class and any topology;
  - the only ways in which the space dimension of a polyhedron can
    be changed are:
    - <EM>explicit</EM> calls to operators provided for that purpose;
    - standard copy, assignment and swap operators.

  Note that four different polyhedra can be defined on
  the zero-dimension space:
  the empty polyhedron, either closed or NNC,
  and the universe polyhedron \f$R^0\f$, again either closed or NNC.

  \par
  In all the examples it is assumed that variables
  <CODE>x</CODE> and <CODE>y</CODE> are defined (where they are
  used) as follows:
  \code
  Variable x(0);
  Variable y(1);
  \endcode

  \par Example 1
  The following code builds a polyhedron corresponding to
  a square in \f$\Rset^2\f$, given as a system of constraints:
  \code
  Constraint_System cs;
  cs.insert(x >= 0);
  cs.insert(x <= 3);
  cs.insert(y >= 0);
  cs.insert(y <= 3);
  C_Polyhedron ph(cs);
  \endcode
  The following code builds the same polyhedron as above,
  but starting from a system of generators specifying
  the four vertices of the square:
  \code
  Generator_System gs;
  gs.insert(point(0*x + 0*y));
  gs.insert(point(0*x + 3*y));
  gs.insert(point(3*x + 0*y));
  gs.insert(point(3*x + 3*y));
  C_Polyhedron ph(gs);
  \endcode

  \par Example 2
  The following code builds an unbounded polyhedron
  corresponding to a half-strip in \f$\Rset^2\f$,
  given as a system of constraints:
  \code
  Constraint_System cs;
  cs.insert(x >= 0);
  cs.insert(x - y <= 0);
  cs.insert(x - y + 1 >= 0);
  C_Polyhedron ph(cs);
  \endcode
  The following code builds the same polyhedron as above,
  but starting from the system of generators specifying
  the two vertices of the polyhedron and one ray:
  \code
  Generator_System gs;
  gs.insert(point(0*x + 0*y));
  gs.insert(point(0*x + y));
  gs.insert(ray(x - y));
  C_Polyhedron ph(gs);
  \endcode

  \par Example 3
  The following code builds the polyhedron corresponding to
  a half-plane by adding a single constraint
  to the universe polyhedron in \f$\Rset^2\f$:
  \code
  C_Polyhedron ph(2);
  ph.add_constraint(y >= 0);
  \endcode
  The following code builds the same polyhedron as above,
  but starting from the empty polyhedron in the space \f$\Rset^2\f$
  and inserting the appropriate generators
  (a point, a ray and a line).
  \code
  C_Polyhedron ph(2, EMPTY);
  ph.add_generator(point(0*x + 0*y));
  ph.add_generator(ray(y));
  ph.add_generator(line(x));
  \endcode
  Note that, although the above polyhedron has no vertices, we must add
  one point, because otherwise the result of the Minkowski's sum
  would be an empty polyhedron.
  To avoid subtle errors related to the minimization process,
  it is required that the first generator inserted in an empty
  polyhedron is a point (otherwise, an exception is thrown).

  \par Example 4
  The following code shows the use of the function
  <CODE>add_space_dimensions_and_embed</CODE>:
  \code
  C_Polyhedron ph(1);
  ph.add_constraint(x == 2);
  ph.add_space_dimensions_and_embed(1);
  \endcode
  We build the universe polyhedron in the 1-dimension space \f$\Rset\f$.
  Then we add a single equality constraint,
  thus obtaining the polyhedron corresponding to the singleton set
  \f$\{ 2 \} \sseq \Rset\f$.
  After the last line of code, the resulting polyhedron is
  \f[
    \bigl\{\,
      (2, y)^\transpose \in \Rset^2
    \bigm|
      y \in \Rset
    \,\bigr\}.
  \f]

  \par Example 5
  The following code shows the use of the function
  <CODE>add_space_dimensions_and_project</CODE>:
  \code
  C_Polyhedron ph(1);
  ph.add_constraint(x == 2);
  ph.add_space_dimensions_and_project(1);
  \endcode
  The first two lines of code are the same as in Example 4 for
  <CODE>add_space_dimensions_and_embed</CODE>.
  After the last line of code, the resulting polyhedron is
  the singleton set
  \f$\bigl\{ (2, 0)^\transpose \bigr\} \sseq \Rset^2\f$.

  \par Example 6
  The following code shows the use of the function
  <CODE>affine_image</CODE>:
  \code
  C_Polyhedron ph(2, EMPTY);
  ph.add_generator(point(0*x + 0*y));
  ph.add_generator(point(0*x + 3*y));
  ph.add_generator(point(3*x + 0*y));
  ph.add_generator(point(3*x + 3*y));
  Linear_Expression expr = x + 4;
  ph.affine_image(x, expr);
  \endcode
  In this example the starting polyhedron is a square in
  \f$\Rset^2\f$, the considered variable is \f$x\f$ and the affine
  expression is \f$x+4\f$.  The resulting polyhedron is the same
  square translated to the right.  Moreover, if the affine
  transformation for the same variable \p x is \f$x+y\f$:
  \code
  Linear_Expression expr = x + y;
  \endcode
  the resulting polyhedron is a parallelogram with the height equal to
  the side of the square and the oblique sides parallel to the line
  \f$x-y\f$.
  Instead, if we do not use an invertible transformation for the same
  variable; for example, the affine expression \f$y\f$:
  \code
  Linear_Expression expr = y;
  \endcode
  the resulting polyhedron is a diagonal of the square.

  \par Example 7
  The following code shows the use of the function
  <CODE>affine_preimage</CODE>:
  \code
  C_Polyhedron ph(2);
  ph.add_constraint(x >= 0);
  ph.add_constraint(x <= 3);
  ph.add_constraint(y >= 0);
  ph.add_constraint(y <= 3);
  Linear_Expression expr = x + 4;
  ph.affine_preimage(x, expr);
  \endcode
  In this example the starting polyhedron, \p var and the affine
  expression and the denominator are the same as in Example 6,
  while the resulting polyhedron is again the same square,
  but translated to the left.
  Moreover, if the affine transformation for \p x is \f$x+y\f$
  \code
  Linear_Expression expr = x + y;
  \endcode
  the resulting polyhedron is a parallelogram with the height equal to
  the side of the square and the oblique sides parallel to the line
  \f$x+y\f$.
  Instead, if we do not use an invertible transformation for the same
  variable \p x, for example, the affine expression \f$y\f$:
  \code
  Linear_Expression expr = y;
  \endcode
  the resulting polyhedron is a line that corresponds to the \f$y\f$ axis.

  \par Example 8
  For this example we use also the variables:
  \code
  Variable z(2);
  Variable w(3);
  \endcode
  The following code shows the use of the function
  <CODE>remove_space_dimensions</CODE>:
  \code
  Generator_System gs;
  gs.insert(point(3*x + y +0*z + 2*w));
  C_Polyhedron ph(gs);
  Variables_Set to_be_removed;
  to_be_removed.insert(y);
  to_be_removed.insert(z);
  ph.remove_space_dimensions(to_be_removed);
  \endcode
  The starting polyhedron is the singleton set
  \f$\bigl\{ (3, 1, 0, 2)^\transpose \bigr\} \sseq \Rset^4\f$, while
  the resulting polyhedron is
  \f$\bigl\{ (3, 2)^\transpose \bigr\} \sseq \Rset^2\f$.
  Be careful when removing space dimensions <EM>incrementally</EM>:
  since dimensions are automatically renamed after each application
  of the <CODE>remove_space_dimensions</CODE> operator, unexpected
  results can be obtained.
  For instance, by using the following code we would obtain
  a different result:
  \code
  set<Variable> to_be_removed1;
  to_be_removed1.insert(y);
  ph.remove_space_dimensions(to_be_removed1);
  set<Variable> to_be_removed2;
  to_be_removed2.insert(z);
  ph.remove_space_dimensions(to_be_removed2);
  \endcode
  In this case, the result is the polyhedron
  \f$\bigl\{(3, 0)^\transpose \bigr\} \sseq \Rset^2\f$:
  when removing the set of dimensions \p to_be_removed2
  we are actually removing variable \f$w\f$ of the original polyhedron.
  For the same reason, the operator \p remove_space_dimensions
  is not idempotent: removing twice the same non-empty set of dimensions
  is never the same as removing them just once.
*/

class Parma_Polyhedra_Library::Polyhedron {
public:
  //! Returns the maximum space dimension all kinds of Polyhedron can handle.
  static dimension_type max_space_dimension();

protected:
  //! Builds a polyhedron having the specified properties.
  /*!
    \param topol
    The topology of the polyhedron;

    \param num_dimensions
    The number of dimensions of the vector space enclosing the polyhedron;

    \param kind
    Specifies whether the universe or the empty polyhedron has to be built.
  */
  Polyhedron(Topology topol,
	     dimension_type num_dimensions,
	     Degenerate_Element kind);

  //! Ordinary copy-constructor.
  Polyhedron(const Polyhedron& y);

  //! Builds a polyhedron from a system of constraints.
  /*!
    The polyhedron inherits the space dimension of the constraint system.

    \param topol
    The topology of the polyhedron;

    \param cs
    The system of constraints defining the polyhedron.

    \exception std::invalid_argument
    Thrown if the topology of \p cs is incompatible with \p topol.
  */
  Polyhedron(Topology topol, const Constraint_System& cs);

  //! Builds a polyhedron recycling a system of constraints.
  /*!
    The polyhedron inherits the space dimension of the constraint system.

    \param topol
    The topology of the polyhedron;

    \param cs
    The system of constraints defining the polyhedron.  It is not
    declared <CODE>const</CODE> because its data-structures will be
    recycled to build the polyhedron.

    \exception std::invalid_argument
    Thrown if the topology of \p cs is incompatible with \p topol.
  */
  Polyhedron(Topology topol, Constraint_System& cs);

  //! Builds a polyhedron from a system of generators.
  /*!
    The polyhedron inherits the space dimension of the generator system.

    \param topol
    The topology of the polyhedron;

    \param gs
    The system of generators defining the polyhedron.

    \exception std::invalid_argument
    Thrown if the topology of \p gs is incompatible with \p topol,
    or if the system of generators is not empty but has no points.
  */
  Polyhedron(Topology topol, const Generator_System& gs);

  //! Builds a polyhedron recycling a system of generators.
  /*!
    The polyhedron inherits the space dimension of the generator system.

    \param topol
    The topology of the polyhedron;

    \param gs
    The system of generators defining the polyhedron.  It is not
    declared <CODE>const</CODE> because its data-structures will be
    recycled to build the polyhedron.

    \exception std::invalid_argument
    Thrown if the topology of \p gs is incompatible with \p topol,
    or if the system of generators is not empty but has no points.
  */
  Polyhedron(Topology topol, Generator_System& gs);

  //! Builds a polyhedron out of a generic, interval-based bounding box.
  /*!
    \param topol
    The topology of the polyhedron;

    \param box
    The bounding box representing the polyhedron to be built.

    \exception std::invalid_argument
    Thrown if \p box has intervals that are incompatible with \p topol.

    The template class Box must provide the following methods.
    \code
      dimension_type space_dimension() const
    \endcode
    returns the dimension of the vector space enclosing the polyhedron
    represented by the bounding box.
    \code
      bool is_empty() const
    \endcode
    returns <CODE>true</CODE> if and only if the bounding box
    describes the empty set.
    The <CODE>is_empty()</CODE> method will always be called before the
    methods below.  However, if <CODE>is_empty()</CODE> returns
    <CODE>true</CODE>, none of the functions below will be called.
    \code
      bool get_lower_bound(dimension_type k, bool closed,
                           Coefficient& n, Coefficient& d) const
    \endcode
    Let \f$I\f$ the interval corresponding to the <CODE>k</CODE>-th
    space dimension.  If \f$I\f$ is not bounded from below, simply return
    <CODE>false</CODE>.  Otherwise, set <CODE>closed</CODE>,
    <CODE>n</CODE> and <CODE>d</CODE> as follows: <CODE>closed</CODE>
    is set to <CODE>true</CODE> if the the lower boundary of \f$I\f$
    is closed and is set to <CODE>false</CODE> otherwise;
    <CODE>n</CODE> and <CODE>d</CODE> are assigned the integers
    \f$n\f$ and \f$d\f$ such that the canonical fraction \f$n/d\f$
    corresponds to the greatest lower bound of \f$I\f$.  The fraction
    \f$n/d\f$ is in canonical form if and only if \f$n\f$ and \f$d\f$
    have no common factors and \f$d\f$ is positive, \f$0/1\f$ being
    the unique representation for zero.
    \code
      bool get_upper_bound(dimension_type k, bool closed,
                           Coefficient& n, Coefficient& d) const
    \endcode
    Let \f$I\f$ the interval corresponding to the <CODE>k</CODE>-th
    space dimension.  If \f$I\f$ is not bounded from above, simply return
    <CODE>false</CODE>.  Otherwise, set <CODE>closed</CODE>,
    <CODE>n</CODE> and <CODE>d</CODE> as follows: <CODE>closed</CODE>
    is set to <CODE>true</CODE> if the the upper boundary of \f$I\f$
    is closed and is set to <CODE>false</CODE> otherwise;
    <CODE>n</CODE> and <CODE>d</CODE> are assigned the integers
    \f$n\f$ and \f$d\f$ such that the canonical fraction \f$n/d\f$
    corresponds to the least upper bound of \f$I\f$.
  */
  template <typename Box>
  Polyhedron(Topology topol, const Box& box);

  /*! \brief
    The assignment operator.
    (\p *this and \p y can be dimension-incompatible.)
  */
  Polyhedron& operator=(const Polyhedron& y);

public:
  //! \name Member Functions that Do Not Modify the Polyhedron
  //@{

  //! Returns the dimension of the vector space enclosing \p *this.
  dimension_type space_dimension() const;

  /*! \brief
    Returns \f$0\f$, if \p *this is empty; otherwise, returns the
    \ref Affine_Independence_and_Affine_Dimension "affine dimension"
    of \p *this.
  */
  dimension_type affine_dimension() const;

  //! Returns the system of constraints.
  const Constraint_System& constraints() const;

  //! Returns the system of constraints, with no redundant constraint.
  const Constraint_System& minimized_constraints() const;

  //! Returns the system of generators.
  const Generator_System& generators() const;

  //! Returns the system of generators, with no redundant generator.
  const Generator_System& minimized_generators() const;

  /*! \brief
    Returns the relations holding between the polyhedron \p *this
    and the constraint \p c.

    \exception std::invalid_argument
    Thrown if \p *this and constraint \p c are dimension-incompatible.
  */
  Poly_Con_Relation relation_with(const Constraint& c) const;

  /*! \brief
    Returns the relations holding between the polyhedron \p *this
    and the generator \p g.

    \exception std::invalid_argument
    Thrown if \p *this and generator \p g are dimension-incompatible.
  */
  Poly_Gen_Relation relation_with(const Generator& g) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is
    an empty polyhedron.
  */
  bool is_empty() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this
    is a universe polyhedron.
  */
  bool is_universe() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this
    is a topologically closed subset of the vector space.
  */
  bool is_topologically_closed() const;

  //! Returns <CODE>true</CODE> if and only if \p *this and \p y are disjoint.
  /*!
    \exception std::invalid_argument
    Thrown if \p x and \p y are topology-incompatible or
    dimension-incompatible.
  */
  bool is_disjoint_from(const Polyhedron& y) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this
    is a bounded polyhedron.
  */
  bool is_bounded() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p expr is
    bounded from above in \p *this.

    \exception std::invalid_argument
    Thrown if \p expr and \p *this are dimension-incompatible.
  */
  bool bounds_from_above(const Linear_Expression& expr) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p expr is
    bounded from below in \p *this.

    \exception std::invalid_argument
    Thrown if \p expr and \p *this are dimension-incompatible.
  */
  bool bounds_from_below(const Linear_Expression& expr) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is not empty
    and \p expr is bounded from above in \p *this, in which case
    the supremum value is computed.

    \param expr
    The linear expression to be maximized subject to \p *this;

    \param sup_n
    The numerator of the supremum value;

    \param sup_d
    The denominator of the supremum value;

    \param maximum
    <CODE>true</CODE> if and only if the supremum is also the maximum value.

    \exception std::invalid_argument
    Thrown if \p expr and \p *this are dimension-incompatible.

    If \p *this is empty or \p expr is not bounded from above,
    <CODE>false</CODE> is returned and \p sup_n, \p sup_d
    and \p maximum are left untouched.
  */
  bool maximize(const Linear_Expression& expr,
		Coefficient& sup_n, Coefficient& sup_d, bool& maximum) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is not empty
    and \p expr is bounded from above in \p *this, in which case
    the supremum value and a point where \p expr reaches it are computed.

    \param expr
    The linear expression to be maximized subject to \p *this;

    \param sup_n
    The numerator of the supremum value;

    \param sup_d
    The denominator of the supremum value;

    \param maximum
    <CODE>true</CODE> if and only if the supremum is also the maximum value;

    \param point
    When maximization succeeds, will be assigned the point or
    closure point where \p expr reaches its supremum value.

    \exception std::invalid_argument
    Thrown if \p expr and \p *this are dimension-incompatible.

    If \p *this is empty or \p expr is not bounded from above,
    <CODE>false</CODE> is returned and \p sup_n, \p sup_d, \p maximum
    and \p point are left untouched.
  */
  bool maximize(const Linear_Expression& expr,
		Coefficient& sup_n, Coefficient& sup_d, bool& maximum,
		Generator& point) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is not empty
    and \p expr is bounded from below in \p *this, in which case
    the infimum value is computed.

    \param expr
    The linear expression to be minimized subject to \p *this;

    \param inf_n
    The numerator of the infimum value;

    \param inf_d
    The denominator of the infimum value;

    \param minimum
    <CODE>true</CODE> if and only if the infimum is also the minimum value.

    \exception std::invalid_argument
    Thrown if \p expr and \p *this are dimension-incompatible.

    If \p *this is empty or \p expr is not bounded from below,
    <CODE>false</CODE> is returned and \p inf_n, \p inf_d
    and \p minimum are left untouched.
  */
  bool minimize(const Linear_Expression& expr,
		Coefficient& inf_n, Coefficient& inf_d, bool& minimum) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is not empty
    and \p expr is bounded from below in \p *this, in which case
    the infimum value and a point where \p expr reaches it are computed.

    \param expr
    The linear expression to be minimized subject to \p *this;

    \param inf_n
    The numerator of the infimum value;

    \param inf_d
    The denominator of the infimum value;

    \param minimum
    <CODE>true</CODE> if and only if the infimum is also the minimum value;

    \param point
    When minimization succeeds, will be assigned a point or
    closure point where \p expr reaches its infimum value.

    \exception std::invalid_argument
    Thrown if \p expr and \p *this are dimension-incompatible.

    If \p *this is empty or \p expr is not bounded from below,
    <CODE>false</CODE> is returned and \p inf_n, \p inf_d, \p minimum
    and \p point are left untouched.
  */
  bool minimize(const Linear_Expression& expr,
		Coefficient& inf_n, Coefficient& inf_d, bool& minimum,
		Generator& point) const;

  //! Returns <CODE>true</CODE> if and only if \p *this contains \p y.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.
  */
  bool contains(const Polyhedron& y) const;

  //! Returns <CODE>true</CODE> if and only if \p *this strictly contains \p y.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.
  */
  bool strictly_contains(const Polyhedron& y) const;

  /*! \brief
    Uses \p *this to shrink a generic, interval-based bounding box.
    Assigns to \p box the intersection of \p box with the smallest
    bounding box containing \p *this.

    \param box
    The bounding box to be shrunk;

    \param complexity
    The complexity class of the algorithm to be used.

    If the polyhedron \p *this or \p box is empty, then the empty box
    is returned.

    If \p *this and \p box are non-empty, then, for
    each space dimension \f$k\f$ with variable \f$\mathrm{var}\f$, let
    \f$u\f$ be the upper and \f$l\f$ the lower bound of the smallest
    interval containing \p *this.

    If \f$l\f$ is infinite, then \p box is unaltered; if \f$l\f$ is
    finite, then the \p box interval for space dimension \f$k\f$ is
    (destructively) intersected with \f$[l, +\mathrm{infty})\f$ if a
    point of \p *this satisfies \f$\mathrm{var} == l\f$ and with
    \f$(l, +\mathrm{infty})\f$ otherwise.

    Similarly, if \f$u\f$ is infinite, then \p box is unaltered; if
    \f$u\f$ is finite, then the \p box interval for space dimension
    \f$k\f$ is (destructively) intersected with \f$(-\mathrm{infty},
    u]\f$ if a point of \p *this satisfies \f$\mathrm{var} == u\f$ and
    with \f$(-\mathrm{infty}, u)\f$ otherwise.

    The template class Box must provide the following methods, whose
    return values, if any, are simply ignored.
    \code
      set_empty()
    \endcode
    causes the box to become empty, i.e., to represent the empty set.
    \code
      raise_lower_bound(dimension_type k, bool closed,
                        Coefficient_traits::const_reference n,
                        Coefficient_traits::const_reference d)
    \endcode
    intersects the interval corresponding to the <CODE>k</CODE>-th
    space dimension
    with \f$[n/d, +\infty)\f$ if <CODE>closed</CODE> is <CODE>true</CODE>,
    with \f$(n/d, +\infty)\f$ if <CODE>closed</CODE> is <CODE>false</CODE>.
    \code
      lower_upper_bound(dimension_type k, bool closed,
                        Coefficient_traits::const_reference n,
                        Coefficient_traits::const_reference d)
    \endcode
    intersects the interval corresponding to the <CODE>k</CODE>-th
    space dimension
    with \f$(-\infty, n/d]\f$ if <CODE>closed</CODE> is <CODE>true</CODE>,
    with \f$(-\infty, n/d)\f$ if <CODE>closed</CODE>
    is <CODE>false</CODE>.

    The function <CODE>raise_lower_bound(k, closed, n, d)</CODE>
    will be called at most once for each possible value for <CODE>k</CODE>
    and for all such calls the fraction \f$n/d\f$ will be in canonical form,
    that is, \f$n\f$ and \f$d\f$ have no common factors and \f$d\f$
    is positive, \f$0/1\f$ being the unique representation for zero.
    The same guarantee is offered for the function
    <CODE>lower_upper_bound(k, closed, n, d)</CODE>.
  */
  template <typename Box>
  void shrink_bounding_box(Box& box,
			   Complexity_Class complexity = ANY_COMPLEXITY) const;

  //! Checks if all the invariants are satisfied.
  /*!
    \return
    <CODE>true</CODE> if and only if \p *this satisfies all the
    invariants and either \p check_not_empty is <CODE>false</CODE> or
    \p *this is not empty.

    \param check_not_empty
    <CODE>true</CODE> if and only if, in addition to checking the
    invariants, \p *this must be checked to be not empty.

    The check is performed so as to intrude as little as possible.  If
    the library has been compiled with run-time assertions enabled,
    error messages are written on <CODE>std::cerr</CODE> in case
    invariants are violated. This is useful for the purpose of
    debugging the library.
  */
  bool OK(bool check_not_empty = false) const;

  //@} // Member Functions that Do Not Modify the Polyhedron

  //! \name Space Dimension Preserving Member Functions that May Modify the Polyhedron
  //@{

  /*! \brief
    Adds a copy of constraint \p c to the system of constraints
    of \p *this (without minimizing the result).

    \exception std::invalid_argument
    Thrown if \p *this and constraint \p c are topology-incompatible
    or dimension-incompatible.
  */
  void add_constraint(const Constraint& c);

  /*! \brief
    Adds a copy of constraint \p c to the system of constraints
    of \p *this, minimizing the result

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \exception std::invalid_argument
    Thrown if \p *this and constraint \p c are topology-incompatible
    or dimension-incompatible.
  */
  bool add_constraint_and_minimize(const Constraint& c);

  /*! \brief
    Adds a copy of generator \p g to the system of generators
    of \p *this (without minimizing the result).

    \exception std::invalid_argument
    Thrown if \p *this and generator \p g are topology-incompatible or
    dimension-incompatible, or if \p *this is an empty polyhedron and
    \p g is not a point.
  */
  void add_generator(const Generator& g);

  /*! \brief
    Adds a copy of generator \p g to the system of generators
    of \p *this, minimizing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \exception std::invalid_argument
    Thrown if \p *this and generator \p g are topology-incompatible or
    dimension-incompatible, or if \p *this is an empty polyhedron and
    \p g is not a point.
  */
  bool add_generator_and_minimize(const Generator& g);

  /*! \brief
    Adds a copy of congruence \p cg to the system of congruences of \p
    *this (without minimizing the result).

    \exception std::invalid_argument
    Thrown if \p *this and congruence \p cg are topology-incompatible
    or dimension-incompatible.
  */
  void add_congruence(const Congruence& cg);

  /*! \brief
    Adds a copy of the constraints in \p cs to the system
    of constraints of \p *this (without minimizing the result).

    \param cs
    Contains the constraints that will be added to the system of
    constraints of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are topology-incompatible or
    dimension-incompatible.
  */
  void add_constraints(const Constraint_System& cs);

  /*! \brief
    Adds the constraints in \p cs to the system of constraints
    of \p *this (without minimizing the result).

    \param cs
    The constraint system that will be recycled, adding its
    constraints to the system of constraints of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are topology-incompatible or
    dimension-incompatible.

    \warning
    The only assumption that can be made on \p cs upon successful or
    exceptional return is that it can be safely destroyed.
  */
  void add_recycled_constraints(Constraint_System& cs);

  /*! \brief
    Adds a copy of the constraints in \p cs to the system
    of constraints of \p *this, minimizing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \param cs
    Contains the constraints that will be added to the system of
    constraints of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are topology-incompatible or
    dimension-incompatible.
  */
  bool add_constraints_and_minimize(const Constraint_System& cs);

  /*! \brief
    Adds the constraints in \p cs to the system of constraints
    of \p *this, minimizing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \param cs
    The constraint system that will be recycled, adding its
    constraints to the system of constraints of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are topology-incompatible or
    dimension-incompatible.

    \warning
    The only assumption that can be made on \p cs upon successful or
    exceptional return is that it can be safely destroyed.
  */
  bool add_recycled_constraints_and_minimize(Constraint_System& cs);

  /*! \brief
    Adds a copy of the generators in \p gs to the system
    of generators of \p *this (without minimizing the result).

    \param gs
    Contains the generators that will be added to the system of
    generators of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p gs are topology-incompatible or
    dimension-incompatible, or if \p *this is empty and the system of
    generators \p gs is not empty, but has no points.
  */
  void add_generators(const Generator_System& gs);

  /*! \brief
    Adds the generators in \p gs to the system of generators
    of \p *this (without minimizing the result).

    \param gs
    The generator system that will be recycled, adding its generators
    to the system of generators of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p gs are topology-incompatible or
    dimension-incompatible, or if \p *this is empty and the system of
    generators \p gs is not empty, but has no points.

    \warning
    The only assumption that can be made on \p gs upon successful or
    exceptional return is that it can be safely destroyed.
  */
  void add_recycled_generators(Generator_System& gs);

  /*! \brief
    Adds a copy of the generators in \p gs to the system
    of generators of \p *this, minimizing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \param gs
    Contains the generators that will be added to the system of
    generators of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p gs are topology-incompatible or
    dimension-incompatible, or if \p *this is empty and the the system
    of generators \p gs is not empty, but has no points.
  */
  bool add_generators_and_minimize(const Generator_System& gs);

  /*! \brief
    Adds the generators in \p gs to the system of generators
    of \p *this, minimizing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \param gs
    The generator system that will be recycled, adding its generators
    to the system of generators of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p gs are topology-incompatible or
    dimension-incompatible, or if \p *this is empty and the the system
    of generators \p gs is not empty, but has no points.

    \warning
    The only assumption that can be made on \p gs upon successful or
    exceptional return is that it can be safely destroyed.
  */
  bool add_recycled_generators_and_minimize(Generator_System& gs);

  /*! \brief
    Adds to \p *this constraints equivalent to the congruences in \p
    cgs (without minimizing the result).

    \param cgs
    Contains the congruences that will be added to the system of
    constraints of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are topology-incompatible or
    dimension-incompatible.
  */
  void add_congruences(const Congruence_System& cgs);

  /*! \brief
    Assigns to \p *this the intersection of \p *this and \p y.
    The result is not guaranteed to be minimized.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.
  */
  void intersection_assign(const Polyhedron& y);

  /*! \brief
    Assigns to \p *this the intersection of \p *this and \p y,
    minimizing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.
  */
  bool intersection_assign_and_minimize(const Polyhedron& y);

  /*! \brief
    Assigns to \p *this the poly-hull of \p *this and \p y.
    The result is not guaranteed to be minimized.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.
  */
  void poly_hull_assign(const Polyhedron& y);

  /*! \brief
    Assigns to \p *this the poly-hull of \p *this and \p y,
    minimizing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.
  */
  bool poly_hull_assign_and_minimize(const Polyhedron& y);

  //! Same as poly_hull_assign(y).
  void upper_bound_assign(const Polyhedron& y);

  /*! \brief
    Assigns to \p *this
    the \ref Convex_Polyhedral_Difference "poly-difference"
    of \p *this and \p y. The result is not guaranteed to be minimized.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.
  */
  void poly_difference_assign(const Polyhedron& y);

  //! Same as poly_difference_assign(y).
  void difference_assign(const Polyhedron& y);

  /*! \brief
    Assigns to \p *this the
    \ref Single_Update_Affine_Functions "affine image"
    of \p *this under the function mapping variable \p var to the
    affine expression specified by \p expr and \p denominator.

    \param var
    The variable to which the affine expression is assigned;

    \param expr
    The numerator of the affine expression;

    \param denominator
    The denominator of the affine expression (optional argument with
    default value 1.)

    \exception std::invalid_argument
    Thrown if \p denominator is zero or if \p expr and \p *this are
    dimension-incompatible or if \p var is not a space dimension of
    \p *this.

    \if Include_Implementation_Details

    When considering the generators of a polyhedron, the
    affine transformation
    \f[
      \frac{\sum_{i=0}^{n-1} a_i x_i + b}{\mathrm{denominator}}
    \f]
    is assigned to \p var where \p expr is
    \f$\sum_{i=0}^{n-1} a_i x_i + b\f$
    (\f$b\f$ is the inhomogeneous term).

    If constraints are up-to-date, it uses the specialized function
    affine_preimage() (for the system of constraints)
    and inverse transformation to reach the same result.
    To obtain the inverse transformation we use the following observation.

    Observation:
    -# The affine transformation is invertible if the coefficient
       of \p var in this transformation (i.e., \f$a_\mathrm{var}\f$)
       is different from zero.
    -# If the transformation is invertible, then we can write
       \f[
  	 \mathrm{denominator} * {x'}_\mathrm{var}
	   = \sum_{i = 0}^{n - 1} a_i x_i + b
	   = a_\mathrm{var} x_\mathrm{var}
	     + \sum_{i \neq var} a_i x_i + b,
       \f]
       so that the inverse transformation is
       \f[
	 a_\mathrm{var} x_\mathrm{var}
           = \mathrm{denominator} * {x'}_\mathrm{var}
             - \sum_{i \neq j} a_i x_i - b.
       \f]

    Then, if the transformation is invertible, all the entities that
    were up-to-date remain up-to-date. Otherwise only generators remain
    up-to-date.

    In other words, if \f$R\f$ is a \f$m_1 \times n\f$ matrix representing
    the rays of the polyhedron, \f$V\f$ is a \f$m_2 \times n\f$
    matrix representing the points of the polyhedron and
    \f[
      P = \bigl\{\,
            \vect{x} = (x_0, \ldots, x_{n-1})^\mathrm{T}
          \bigm|
            \vect{x} = \vect{\lambda} R + \vect{\mu} V,
	    \vect{\lambda} \in \Rset^{m_1}_+,
	    \vect{\mu} \in \Rset^{m_2}_+,
	    \sum_{i = 0}^{m_2 - 1} \mu_i = 1
          \,\bigr\}
    \f]
    and \f$T\f$ is the affine transformation to apply to \f$P\f$, then
    the resulting polyhedron is
    \f[
      P' = \bigl\{\,
             (x_0, \ldots, T(x_0, \ldots, x_{n-1}),
                     \ldots, x_{n-1})^\mathrm{T}
           \bigm|
             (x_0, \ldots, x_{n-1})^\mathrm{T} \in P
           \,\bigr\}.
    \f]

    Affine transformations are, for example:
    - translations
    - rotations
    - symmetries.
    \endif
  */
  void affine_image(Variable var,
		    const Linear_Expression& expr,
		    Coefficient_traits::const_reference denominator
		      = Coefficient_one());

  /*! \brief
    Assigns to \p *this the
    \ref Single_Update_Affine_Functions "affine preimage"
    of \p *this under the function mapping variable \p var to the
    affine expression specified by \p expr and \p denominator.

    \param var
    The variable to which the affine expression is substituted;

    \param expr
    The numerator of the affine expression;

    \param denominator
    The denominator of the affine expression (optional argument with
    default value 1.)

    \exception std::invalid_argument
    Thrown if \p denominator is zero or if \p expr and \p *this are
    dimension-incompatible or if \p var is not a space dimension of \p *this.

    \if Include_Implementation_Details

    When considering constraints of a polyhedron, the affine transformation
    \f[
      \frac{\sum_{i=0}^{n-1} a_i x_i + b}{denominator},
    \f]
    is assigned to \p var where \p expr is
    \f$\sum_{i=0}^{n-1} a_i x_i + b\f$
    (\f$b\f$ is the inhomogeneous term).

    If generators are up-to-date, then the specialized function
    affine_image() is used (for the system of generators)
    and inverse transformation to reach the same result.
    To obtain the inverse transformation, we use the following observation.

    Observation:
    -# The affine transformation is invertible if the coefficient
       of \p var in this transformation (i.e. \f$a_\mathrm{var}\f$)
       is different from zero.
    -# If the transformation is invertible, then we can write
       \f[
  	 \mathrm{denominator} * {x'}_\mathrm{var}
	   = \sum_{i = 0}^{n - 1} a_i x_i + b
           = a_\mathrm{var} x_\mathrm{var}
               + \sum_{i \neq \mathrm{var}} a_i x_i + b,
       \f],
       the inverse transformation is
       \f[
	 a_\mathrm{var} x_\mathrm{var}
           = \mathrm{denominator} * {x'}_\mathrm{var}
               - \sum_{i \neq j} a_i x_i - b.
       \f].

    Then, if the transformation is invertible, all the entities that
    were up-to-date remain up-to-date. Otherwise only constraints remain
    up-to-date.

    In other words, if \f$A\f$ is a \f$m \times n\f$ matrix representing
    the constraints of the polyhedron, \f$T\f$ is the affine transformation
    to apply to \f$P\f$ and
    \f[
      P = \bigl\{\,
            \vect{x} = (x_0, \ldots, x_{n-1})^\mathrm{T}
          \bigm|
            A\vect{x} \geq \vect{0}
          \,\bigr\}.
    \f]
    The resulting polyhedron is
    \f[
      P' = \bigl\{\,
             \vect{x} = (x_0, \ldots, x_{n-1}))^\mathrm{T}
           \bigm|
             A'\vect{x} \geq \vect{0}
           \,\bigr\},
    \f]
    where \f$A'\f$ is defined as follows:
    \f[
      {a'}_{ij}
        = \begin{cases}
            a_{ij} * \mathrm{denominator} + a_{i\mathrm{var}}*\mathrm{expr}[j]
              \quad \mathrm{for } j \neq \mathrm{var}; \\
            \mathrm{expr}[\mathrm{var}] * a_{i\mathrm{var}},
              \quad \text{for } j = \mathrm{var}.
          \end{cases}
    \f]
    \endif
  */
  void affine_preimage(Variable var,
		       const Linear_Expression& expr,
		       Coefficient_traits::const_reference denominator
		         = Coefficient_one());

  /*! \brief
    Assigns to \p *this the image of \p *this with respect to the
    \ref Generalized_Affine_Relations "generalized affine relation"
    \f$\mathrm{var}' \relsym \frac{\mathrm{expr}}{\mathrm{denominator}}\f$,
    where \f$\mathord{\relsym}\f$ is the relation symbol encoded
    by \p relsym.

    \param var
    The left hand side variable of the generalized affine relation;

    \param relsym
    The relation symbol;

    \param expr
    The numerator of the right hand side affine expression;

    \param denominator
    The denominator of the right hand side affine expression (optional
    argument with default value 1.)

    \exception std::invalid_argument
    Thrown if \p denominator is zero or if \p expr and \p *this are
    dimension-incompatible or if \p var is not a space dimension of \p *this
    or if \p *this is a C_Polyhedron and \p relsym is a strict
    relation symbol.
  */
  void generalized_affine_image(Variable var,
				const Relation_Symbol relsym,
				const Linear_Expression& expr,
				Coefficient_traits::const_reference denominator
				  = Coefficient_one());

  /*! \brief
    Assigns to \p *this the preimage of \p *this with respect to the
    \ref Generalized_Affine_Relations "generalized affine relation"
    \f$\mathrm{var}' \relsym \frac{\mathrm{expr}}{\mathrm{denominator}}\f$,
    where \f$\mathord{\relsym}\f$ is the relation symbol encoded
    by \p relsym.

    \param var
    The left hand side variable of the generalized affine relation;

    \param relsym
    The relation symbol;

    \param expr
    The numerator of the right hand side affine expression;

    \param denominator
    The denominator of the right hand side affine expression (optional
    argument with default value 1.)

    \exception std::invalid_argument
    Thrown if \p denominator is zero or if \p expr and \p *this are
    dimension-incompatible or if \p var is not a space dimension of \p *this
    or if \p *this is a C_Polyhedron and \p relsym is a strict
    relation symbol.
  */
  void
  generalized_affine_preimage(Variable var,
			      const Relation_Symbol relsym,
			      const Linear_Expression& expr,
			      Coefficient_traits::const_reference denominator
			      = Coefficient_one());

  /*! \brief
    Assigns to \p *this the image of \p *this with respect to the
    \ref Generalized_Affine_Relations "generalized affine relation"
    \f$\mathrm{lhs}' \relsym \mathrm{rhs}\f$, where
    \f$\mathord{\relsym}\f$ is the relation symbol encoded by \p relsym.

    \param lhs
    The left hand side affine expression;

    \param relsym
    The relation symbol;

    \param rhs
    The right hand side affine expression.

    \exception std::invalid_argument
    Thrown if \p *this is dimension-incompatible with \p lhs or \p rhs
    or if \p *this is a C_Polyhedron and \p relsym is a strict
    relation symbol.
  */
  void generalized_affine_image(const Linear_Expression& lhs,
				const Relation_Symbol relsym,
				const Linear_Expression& rhs);

  /*! \brief
    Assigns to \p *this the preimage of \p *this with respect to the
    \ref Generalized_Affine_Relations "generalized affine relation"
    \f$\mathrm{lhs}' \relsym \mathrm{rhs}\f$, where
    \f$\mathord{\relsym}\f$ is the relation symbol encoded by \p relsym.

    \param lhs
    The left hand side affine expression;

    \param relsym
    The relation symbol;

    \param rhs
    The right hand side affine expression.

    \exception std::invalid_argument
    Thrown if \p *this is dimension-incompatible with \p lhs or \p rhs
    or if \p *this is a C_Polyhedron and \p relsym is a strict
    relation symbol.
  */
  void generalized_affine_preimage(const Linear_Expression& lhs,
				   const Relation_Symbol relsym,
				   const Linear_Expression& rhs);

  /*!
    \brief
    Assigns to \p *this the image of \p *this with respect to the
    \ref Single_Update_Bounded_Affine_Relations "bounded affine relation"
    \f$\frac{\mathrm{lb\_expr}}{\mathrm{denominator}}
         \leq \mathrm{var}'
           \leq \frac{\mathrm{ub\_expr}}{\mathrm{denominator}}\f$.

    \param var
    The variable updated by the affine relation;

    \param lb_expr
    The numerator of the lower bounding affine expression;

    \param ub_expr
    The numerator of the upper bounding affine expression;

    \param denominator
    The (common) denominator for the lower and upper bounding
    affine expressions (optional argument with default value 1.)

    \exception std::invalid_argument
    Thrown if \p denominator is zero or if \p lb_expr (resp., \p ub_expr)
    and \p *this are dimension-incompatible or if \p var is not a space
    dimension of \p *this.
  */
  void bounded_affine_image(Variable var,
			    const Linear_Expression& lb_expr,
			    const Linear_Expression& ub_expr,
			    Coefficient_traits::const_reference denominator
			    = Coefficient_one());

  /*!
    \brief
    Assigns to \p *this the preimage of \p *this with respect to the
    \ref Single_Update_Bounded_Affine_Relations "bounded affine relation"
    \f$\frac{\mathrm{lb\_expr}}{\mathrm{denominator}}
         \leq \mathrm{var}'
           \leq \frac{\mathrm{ub\_expr}}{\mathrm{denominator}}\f$.

    \param var
    The variable updated by the affine relation;

    \param lb_expr
    The numerator of the lower bounding affine expression;

    \param ub_expr
    The numerator of the upper bounding affine expression;

    \param denominator
    The (common) denominator for the lower and upper bounding
    affine expressions (optional argument with default value 1.)

    \exception std::invalid_argument
    Thrown if \p denominator is zero or if \p lb_expr (resp., \p ub_expr)
    and \p *this are dimension-incompatible or if \p var is not a space
    dimension of \p *this.
  */
  void bounded_affine_preimage(Variable var,
			       const Linear_Expression& lb_expr,
			       const Linear_Expression& ub_expr,
			       Coefficient_traits::const_reference denominator
			       = Coefficient_one());

  /*! \brief
    Assigns to \p *this the result of computing the
    \ref Time_Elapse_Operator "time-elapse" between \p *this and \p y.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.
  */
  void time_elapse_assign(const Polyhedron& y);

  //! Assigns to \p *this its topological closure.
  void topological_closure_assign();

  /*! \brief
    Assigns to \p *this the result of computing the
    \ref BHRZ03_widening "BHRZ03-widening" between \p *this and \p y.

    \param y
    A polyhedron that <EM>must</EM> be contained in \p *this;

    \param tp
    An optional pointer to an unsigned variable storing the number of
    available tokens (to be used when applying the
    \ref Widening_with_Tokens "widening with tokens" delay technique).

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.
  */
  void BHRZ03_widening_assign(const Polyhedron& y, unsigned* tp = 0);

  /*! \brief
    Improves the result of the \ref BHRZ03_widening "BHRZ03-widening"
    computation by also enforcing those constraints in \p cs that are
    satisfied by all the points of \p *this.

    \param y
    A polyhedron that <EM>must</EM> be contained in \p *this;

    \param cs
    The system of constraints used to improve the widened polyhedron;

    \param tp
    An optional pointer to an unsigned variable storing the number of
    available tokens (to be used when applying the
    \ref Widening_with_Tokens "widening with tokens" delay technique).

    \exception std::invalid_argument
    Thrown if \p *this, \p y and \p cs are topology-incompatible or
    dimension-incompatible.
  */
  void limited_BHRZ03_extrapolation_assign(const Polyhedron& y,
					   const Constraint_System& cs,
					   unsigned* tp = 0);

  /*! \brief
    Improves the result of the \ref BHRZ03_widening "BHRZ03-widening"
    computation by also enforcing those constraints in \p cs that are
    satisfied by all the points of \p *this, plus all the constraints
    of the form \f$\pm x \leq r\f$ and \f$\pm x < r\f$, with
    \f$r \in \Qset\f$, that are satisfied by all the points of \p *this.

    \param y
    A polyhedron that <EM>must</EM> be contained in \p *this;

    \param cs
    The system of constraints used to improve the widened polyhedron;

    \param tp
    An optional pointer to an unsigned variable storing the number of
    available tokens (to be used when applying the
    \ref Widening_with_Tokens "widening with tokens" delay technique).

    \exception std::invalid_argument
    Thrown if \p *this, \p y and \p cs are topology-incompatible or
    dimension-incompatible.
  */
  void bounded_BHRZ03_extrapolation_assign(const Polyhedron& y,
					   const Constraint_System& cs,
					   unsigned* tp = 0);

  /*! \brief
    Assigns to \p *this the result of computing the
    \ref H79_widening "H79-widening" between \p *this and \p y.

    \param y
    A polyhedron that <EM>must</EM> be contained in \p *this;

    \param tp
    An optional pointer to an unsigned variable storing the number of
    available tokens (to be used when applying the
    \ref Widening_with_Tokens "widening with tokens" delay technique).

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.
  */
  void H79_widening_assign(const Polyhedron& y, unsigned* tp = 0);

  /*! \brief
    Improves the result of the \ref H79_widening "H79-widening"
    computation by also enforcing those constraints in \p cs that are
    satisfied by all the points of \p *this.

    \param y
    A polyhedron that <EM>must</EM> be contained in \p *this;

    \param cs
    The system of constraints used to improve the widened polyhedron;

    \param tp
    An optional pointer to an unsigned variable storing the number of
    available tokens (to be used when applying the
    \ref Widening_with_Tokens "widening with tokens" delay technique).

    \exception std::invalid_argument
    Thrown if \p *this, \p y and \p cs are topology-incompatible or
    dimension-incompatible.
  */
  void limited_H79_extrapolation_assign(const Polyhedron& y,
					const Constraint_System& cs,
					unsigned* tp = 0);

  /*! \brief
    Improves the result of the \ref H79_widening "H79-widening"
    computation by also enforcing those constraints in \p cs that are
    satisfied by all the points of \p *this, plus all the constraints
    of the form \f$\pm x \leq r\f$ and \f$\pm x < r\f$, with
    \f$r \in \Qset\f$, that are satisfied by all the points of \p *this.

    \param y
    A polyhedron that <EM>must</EM> be contained in \p *this;

    \param cs
    The system of constraints used to improve the widened polyhedron;

    \param tp
    An optional pointer to an unsigned variable storing the number of
    available tokens (to be used when applying the
    \ref Widening_with_Tokens "widening with tokens" delay technique).

    \exception std::invalid_argument
    Thrown if \p *this, \p y and \p cs are topology-incompatible or
    dimension-incompatible.
  */
  void bounded_H79_extrapolation_assign(const Polyhedron& y,
					const Constraint_System& cs,
					unsigned* tp = 0);

  //@} // Space Dimension Preserving Member Functions that May Modify [...]

  //! \name Member Functions that May Modify the Dimension of the Vector Space
  //@{

  /*! \brief
    Adds \p m new space dimensions and embeds the old polyhedron
    in the new vector space.

    \param m
    The number of dimensions to add.

    \exception std::length_error
    Thrown if adding \p m new space dimensions would cause the
    vector space to exceed dimension <CODE>max_space_dimension()</CODE>.

    The new space dimensions will be those having the highest indexes
    in the new polyhedron, which is characterized by a system
    of constraints in which the variables running through
    the new dimensions are not constrained.
    For instance, when starting from the polyhedron \f$\cP \sseq \Rset^2\f$
    and adding a third space dimension, the result will be the polyhedron
    \f[
      \bigl\{\,
        (x, y, z)^\transpose \in \Rset^3
      \bigm|
        (x, y)^\transpose \in \cP
      \,\bigr\}.
    \f]
  */
  void add_space_dimensions_and_embed(dimension_type m);

  /*! \brief
    Adds \p m new space dimensions to the polyhedron
    and does not embed it in the new vector space.

    \param m
    The number of space dimensions to add.

    \exception std::length_error
    Thrown if adding \p m new space dimensions would cause the
    vector space to exceed dimension <CODE>max_space_dimension()</CODE>.

    The new space dimensions will be those having the highest indexes
    in the new polyhedron, which is characterized by a system
    of constraints in which the variables running through
    the new dimensions are all constrained to be equal to 0.
    For instance, when starting from the polyhedron \f$\cP \sseq \Rset^2\f$
    and adding a third space dimension, the result will be the polyhedron
    \f[
      \bigl\{\,
        (x, y, 0)^\transpose \in \Rset^3
      \bigm|
        (x, y)^\transpose \in \cP
      \,\bigr\}.
    \f]
  */
  void add_space_dimensions_and_project(dimension_type m);

  /*! \brief
    Assigns to \p *this the \ref Concatenating_Polyhedra "concatenation"
    of \p *this and \p y, taken in this order.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible.

    \exception std::length_error
    Thrown if the concatenation would cause the vector space
    to exceed dimension <CODE>max_space_dimension()</CODE>.
  */
  void concatenate_assign(const Polyhedron& y);

  //! Removes all the specified dimensions from the vector space.
  /*!
    \param to_be_removed
    The set of Variable objects corresponding to the space dimensions
    to be removed.

    \exception std::invalid_argument
    Thrown if \p *this is dimension-incompatible with one of the
    Variable objects contained in \p to_be_removed.
  */
  void remove_space_dimensions(const Variables_Set& to_be_removed);

  /*! \brief
    Removes the higher dimensions of the vector space so that
    the resulting space will have dimension \p new_dimension.

    \exception std::invalid_argument
    Thrown if \p new_dimensions is greater than the space dimension of
    \p *this.
  */
  void remove_higher_space_dimensions(dimension_type new_dimension);

  /*! \brief
    Remaps the dimensions of the vector space according to
    a \ref Mapping_the_Dimensions_of_the_Vector_Space "partial function".

    \param pfunc
    The partial function specifying the destiny of each space dimension.

    The template class Partial_Function must provide the following
    methods.
    \code
      bool has_empty_codomain() const
    \endcode
    returns <CODE>true</CODE> if and only if the represented partial
    function has an empty codomain (i.e., it is always undefined).
    The <CODE>has_empty_codomain()</CODE> method will always be called
    before the methods below.  However, if
    <CODE>has_empty_codomain()</CODE> returns <CODE>true</CODE>, none
    of the functions below will be called.
    \code
      dimension_type max_in_codomain() const
    \endcode
    returns the maximum value that belongs to the codomain
    of the partial function.
    The <CODE>max_in_codomain()</CODE> method is called at most once.
    \code
      bool maps(dimension_type i, dimension_type& j) const
    \endcode
    Let \f$f\f$ be the represented function and \f$k\f$ be the value
    of \p i.  If \f$f\f$ is defined in \f$k\f$, then \f$f(k)\f$ is
    assigned to \p j and <CODE>true</CODE> is returned.
    If \f$f\f$ is undefined in \f$k\f$, then <CODE>false</CODE> is
    returned.
    This method is called at most \f$n\f$ times, where \f$n\f$ is the
    dimension of the vector space enclosing the polyhedron.

    The result is undefined if \p pfunc does not encode a partial
    function with the properties described in the
    \ref Mapping_the_Dimensions_of_the_Vector_Space
    "specification of the mapping operator".
  */
  template <typename Partial_Function>
  void map_space_dimensions(const Partial_Function& pfunc);

  //! Creates \p m copies of the space dimension corresponding to \p var.
  /*!
    \param var
    The variable corresponding to the space dimension to be replicated;

    \param m
    The number of replicas to be created.

    \exception std::invalid_argument
    Thrown if \p var does not correspond to a dimension of the vector space.

    \exception std::length_error
    Thrown if adding \p m new space dimensions would cause the
    vector space to exceed dimension <CODE>max_space_dimension()</CODE>.

    If \p *this has space dimension \f$n\f$, with \f$n > 0\f$,
    and <CODE>var</CODE> has space dimension \f$k \leq n\f$,
    then the \f$k\f$-th space dimension is
    \ref expand_space_dimension "expanded" to \p m new space dimensions
    \f$n\f$, \f$n+1\f$, \f$\dots\f$, \f$n+m-1\f$.
  */
  void expand_space_dimension(Variable var, dimension_type m);

  //! Folds the space dimensions in \p to_be_folded into \p var.
  /*!
    \param to_be_folded
    The set of Variable objects corresponding to the space dimensions
    to be folded;

    \param var
    The variable corresponding to the space dimension that is the
    destination of the folding operation.

    \exception std::invalid_argument
    Thrown if \p *this is dimension-incompatible with \p var or with
    one of the Variable objects contained in \p to_be_folded.
    Also thrown if \p var is contained in \p to_be_folded.

    If \p *this has space dimension \f$n\f$, with \f$n > 0\f$,
    <CODE>var</CODE> has space dimension \f$k \leq n\f$,
    \p to_be_folded is a set of variables whose maximum space dimension
    is also less than or equal to \f$n\f$, and \p var is not a member
    of \p to_be_folded, then the space dimensions corresponding to
    variables in \p to_be_folded are \ref fold_space_dimensions "folded"
    into the \f$k\f$-th space dimension.
  */
  void fold_space_dimensions(const Variables_Set& to_be_folded, Variable var);

  //@} // Member Functions that May Modify the Dimension of the Vector Space

  friend bool Parma_Polyhedra_Library::operator==(const Polyhedron& x,
						  const Polyhedron& y);

  //! \name Miscellaneous Member Functions
  //@{

  //! Destructor.
  ~Polyhedron();

  /*! \brief
    Swaps \p *this with polyhedron \p y.
    (\p *this and \p y can be dimension-incompatible.)

    \exception std::invalid_argument
    Thrown if \p x and \p y are topology-incompatible.
  */
  void swap(Polyhedron& y);

  PPL_OUTPUT_DECLARATIONS;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    \ref ascii_dump) and sets \p *this accordingly.
    Returns <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  bool ascii_load(std::istream& s);

  //! Returns the total size in bytes of the memory occupied by \p *this.
  memory_size_type total_memory_in_bytes() const;

  //! Returns the size in bytes of the memory managed by \p *this.
  memory_size_type external_memory_in_bytes() const;

  //@} // Miscellaneous Member Functions

private:
  //! The system of constraints.
  Constraint_System con_sys;

  //! The system of generators.
  Generator_System gen_sys;

  //! The saturation matrix having constraints on its columns.
  Saturation_Matrix sat_c;

  //! The saturation matrix having generators on its columns.
  Saturation_Matrix sat_g;

#define PPL_IN_Polyhedron_CLASS
// Automatically generated from PPL source file ../src/Ph_Status.idefs.hh line 1
/* Polyhedron::Status class declaration.
*/


#ifndef PPL_IN_Polyhedron_CLASS
#error "Do not include Ph_Status.idefs.hh directly; use Polyhedron.defs.hh instead."
#endif

//! A conjunctive assertion about a polyhedron.
/*! \ingroup PPL_CXX_interface
  The assertions supported are:
  - <EM>zero-dim universe</EM>: the polyhedron is the zero-dimension
    vector space \f$\Rset^0 = \{\cdot\}\f$;
  - <EM>empty</EM>: the polyhedron is the empty set;
  - <EM>constraints pending</EM>: the polyhedron is correctly
    characterized by the attached system of constraints, which is
    split in two non-empty subsets: the already processed constraints,
    which are in minimal form, and the pending constraints, which
    still have to be processed and may thus be inconsistent or
    contain redundancies;
  - <EM>generators pending</EM>: the polyhedron is correctly
    characterized by the attached system of generators, which is
    split in two non-empty subsets: the already processed generators,
    which are in minimal form, and the pending generators, which still
    have to be processed and may thus contain redundancies;
  - <EM>constraints up-to-date</EM>: the polyhedron is correctly
    characterized by the attached system of constraints, modulo the
    processing of pending generators;
  - <EM>generators up-to-date</EM>: the polyhedron is correctly
    characterized by the attached system of generators, modulo the
    processing of pending constraints;
  - <EM>constraints minimized</EM>: the non-pending part of the system
    of constraints attached to the polyhedron is in minimal form;
  - <EM>generators minimized</EM>: the non-pending part of the system
    of generators attached to the polyhedron is in minimal form;
  - <EM>constraints' saturation matrix up-to-date</EM>: the attached
    saturation matrix having rows indexed by non-pending generators and
    columns indexed by non-pending constraints correctly expresses
    the saturation relation between the attached non-pending constraints
    and generators;
  - <EM>generators' saturation matrix up-to-date</EM>: the attached
    saturation matrix having rows indexed by non-pending constraints and
    columns indexed by non-pending generators correctly expresses
    the saturation relation between the attached non-pending constraints
    and generators;

  Not all the conjunctions of these elementary assertions constitute
  a legal Status.  In fact:
  - <EM>zero-dim universe</EM> excludes any other assertion;
  - <EM>empty</EM>: excludes any other assertion;
  - <EM>constraints pending</EM> and <EM>generators pending</EM>
    are mutually exclusive;
  - <EM>constraints pending</EM> implies both <EM>constraints minimized</EM>
    and <EM>generators minimized</EM>;
  - <EM>generators pending</EM> implies both <EM>constraints minimized</EM>
    and <EM>generators minimized</EM>;
  - <EM>constraints minimized</EM> implies <EM>constraints up-to-date</EM>;
  - <EM>generators minimized</EM> implies <EM>generators up-to-date</EM>;
  - <EM>constraints' saturation matrix up-to-date</EM> implies both
    <EM>constraints up-to-date</EM> and <EM>generators up-to-date</EM>;
  - <EM>generators' saturation matrix up-to-date</EM> implies both
    <EM>constraints up-to-date</EM> and <EM>generators up-to-date</EM>.
*/
class Status {
public:
  //! By default Status is the <EM>zero-dim universe</EM> assertion.
  Status();

  //! \name Test, remove or add an individual assertion from the conjunction
  //@{
  bool test_zero_dim_univ() const;
  void reset_zero_dim_univ();
  void set_zero_dim_univ();

  bool test_empty() const;
  void reset_empty();
  void set_empty();

  bool test_c_up_to_date() const;
  void reset_c_up_to_date();
  void set_c_up_to_date();

  bool test_g_up_to_date() const;
  void reset_g_up_to_date();
  void set_g_up_to_date();

  bool test_c_minimized() const;
  void reset_c_minimized();
  void set_c_minimized();

  bool test_g_minimized() const;
  void reset_g_minimized();
  void set_g_minimized();

  bool test_sat_c_up_to_date() const;
  void reset_sat_c_up_to_date();
  void set_sat_c_up_to_date();

  bool test_sat_g_up_to_date() const;
  void reset_sat_g_up_to_date();
  void set_sat_g_up_to_date();

  bool test_c_pending() const;
  void reset_c_pending();
  void set_c_pending();

  bool test_g_pending() const;
  void reset_g_pending();
  void set_g_pending();
  //@} // Test, remove or add an individual assertion from the conjunction

  //! Checks if all the invariants are satisfied.
  bool OK() const;

  PPL_OUTPUT_DECLARATIONS;

  /*! \brief
    Loads from \p s an ASCII representation (as produced by \ref ascii_dump)
    and sets \p *this accordingly.  Returns <CODE>true</CODE> if successful,
    <CODE>false</CODE> otherwise.
  */
  bool ascii_load(std::istream& s);

private:
  //! Status is implemented by means of a finite bitset.
  typedef unsigned int flags_t;

  //! \name Bit-masks for the individual assertions
  //@{
  static const flags_t ZERO_DIM_UNIV    = 0U;
  static const flags_t EMPTY            = 1U << 0;
  static const flags_t C_UP_TO_DATE     = 1U << 1;
  static const flags_t G_UP_TO_DATE     = 1U << 2;
  static const flags_t C_MINIMIZED      = 1U << 3;
  static const flags_t G_MINIMIZED      = 1U << 4;
  static const flags_t SAT_C_UP_TO_DATE = 1U << 5;
  static const flags_t SAT_G_UP_TO_DATE = 1U << 6;
  static const flags_t CS_PENDING       = 1U << 7;
  static const flags_t GS_PENDING       = 1U << 8;
  //@} // Bit-masks for the individual assertions

  //! This holds the current bitset.
  flags_t flags;

  //! Construct from a bit-mask.
  Status(flags_t mask);

  //! Check whether <EM>all</EM> bits in \p mask are set.
  bool test_all(flags_t mask) const;

  //! Check whether <EM>at least one</EM> bit in \p mask is set.
  bool test_any(flags_t mask) const;

  //! Set the bits in \p mask.
  void set(flags_t mask);

  //! Reset the bits in \p mask.
  void reset(flags_t mask);
};

// Automatically generated from PPL source file ../src/Polyhedron.defs.hh line 1856
#undef PPL_IN_Polyhedron_CLASS

  //! The status flags to keep track of the polyhedron's internal state.
  Status status;

  //! The number of dimensions of the enclosing vector space.
  dimension_type space_dim;

  //! Returns the topological kind of the polyhedron.
  Topology topology() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if the polyhedron
    is necessarily closed.
  */
  bool is_necessarily_closed() const;

  //! \name Private Verifiers: Verify if Individual Flags are Set
  //@{

  //! Returns <CODE>true</CODE> if the polyhedron is known to be empty.
  /*!
    The return value <CODE>false</CODE> does not necessarily
    implies that \p *this is non-empty.
  */
  bool marked_empty() const;

  //! Returns <CODE>true</CODE> if the system of constraints is up-to-date.
  bool constraints_are_up_to_date() const;

  //! Returns <CODE>true</CODE> if the system of generators is up-to-date.
  bool generators_are_up_to_date() const;

  //! Returns <CODE>true</CODE> if the system of constraints is minimized.
  /*!
    Note that only \em weak minimization is entailed, so that
    an NNC polyhedron may still have \f$\epsilon\f$-redundant constraints.
  */
  bool constraints_are_minimized() const;

  //! Returns <CODE>true</CODE> if the system of generators is minimized.
  /*!
    Note that only \em weak minimization is entailed, so that
    an NNC polyhedron may still have \f$\epsilon\f$-redundant generators.
  */
  bool generators_are_minimized() const;

  //! Returns <CODE>true</CODE> if there are pending constraints.
  bool has_pending_constraints() const;

  //! Returns <CODE>true</CODE> if there are pending generators.
  bool has_pending_generators() const;

  /*! \brief
    Returns <CODE>true</CODE> if there are
    either pending constraints or pending generators.
  */
  bool has_something_pending() const;

  //! Returns <CODE>true</CODE> if the polyhedron can have something pending.
  bool can_have_something_pending() const;

  /*! \brief
    Returns <CODE>true</CODE> if the saturation matrix \p sat_c
    is up-to-date.
  */
  bool sat_c_is_up_to_date() const;

  /*! \brief
    Returns <CODE>true</CODE> if the saturation matrix \p sat_g
    is up-to-date.
  */
  bool sat_g_is_up_to_date() const;

  //@} // Private Verifiers: Verify if Individual Flags are Set

  //! \name State Flag Setters: Set Only the Specified Flags
  //@{

  /*! \brief
    Sets \p status to express that the polyhedron is the universe
    0-dimension vector space, clearing all corresponding matrices.
  */
  void set_zero_dim_univ();

  /*! \brief
    Sets \p status to express that the polyhedron is empty,
    clearing all corresponding matrices.
  */
  void set_empty();

  //! Sets \p status to express that constraints are up-to-date.
  void set_constraints_up_to_date();

  //! Sets \p status to express that generators are up-to-date.
  void set_generators_up_to_date();

  //! Sets \p status to express that constraints are minimized.
  void set_constraints_minimized();

  //! Sets \p status to express that generators are minimized.
  void set_generators_minimized();

  //! Sets \p status to express that constraints are pending.
  void set_constraints_pending();

  //! Sets \p status to express that generators are pending.
  void set_generators_pending();

  //! Sets \p status to express that \p sat_c is up-to-date.
  void set_sat_c_up_to_date();

  //! Sets \p status to express that \p sat_g is up-to-date.
  void set_sat_g_up_to_date();

  //@} // State Flag Setters: Set Only the Specified Flags

  //! \name State Flag Cleaners: Clear Only the Specified Flag
  //@{

  //! Clears the \p status flag indicating that the polyhedron is empty.
  void clear_empty();

  //! Sets \p status to express that constraints are no longer up-to-date.
  /*!
    This also implies that they are neither minimized
    and both saturation matrices are no longer meaningful.
  */
  void clear_constraints_up_to_date();

  //! Sets \p status to express that generators are no longer up-to-date.
  /*!
    This also implies that they are neither minimized
    and both saturation matrices are no longer meaningful.
  */
  void clear_generators_up_to_date();

  //! Sets \p status to express that constraints are no longer minimized.
  void clear_constraints_minimized();

  //! Sets \p status to express that generators are no longer minimized.
  void clear_generators_minimized();

  //! Sets \p status to express that there are no longer pending constraints.
  void clear_pending_constraints();

  //! Sets \p status to express that there are no longer pending generators.
  void clear_pending_generators();

  //! Sets \p status to express that \p sat_c is no longer up-to-date.
  void clear_sat_c_up_to_date();

  //! Sets \p status to express that \p sat_g is no longer up-to-date.
  void clear_sat_g_up_to_date();

  //@} // State Flag Cleaners: Clear Only the Specified Flag

  //! \name The Handling of Pending Rows
  //@{

  /*! \brief
    Processes the pending rows of either description of the polyhedron
    and obtains a minimized polyhedron.

    \return
    <CODE>false</CODE> if and only if \p *this turns out to be an
    empty polyhedron.

    It is assumed that the polyhedron does have some constraints or
    generators pending.
  */
  bool process_pending() const;

  //! Processes the pending constraints and obtains a minimized polyhedron.
  /*!
    \return
    <CODE>false</CODE> if and only if \p *this turns out to be an
    empty polyhedron.

    It is assumed that the polyhedron does have some pending constraints.
  */
  bool process_pending_constraints() const;

  //! Processes the pending generators and obtains a minimized polyhedron.
  /*!
    It is assumed that the polyhedron does have some pending generators.
  */
  void process_pending_generators() const;

  /*! \brief
    Lazily integrates the pending descriptions of the polyhedron
    to obtain a constraint system without pending rows.

    It is assumed that the polyhedron does have some constraints or
    generators pending.
  */
  void remove_pending_to_obtain_constraints() const;

  /*! \brief
    Lazily integrates the pending descriptions of the polyhedron
    to obtain a generator system without pending rows.

    \return
    <CODE>false</CODE> if and only if \p *this turns out to be an
    empty polyhedron.

    It is assumed that the polyhedron does have some constraints or
    generators pending.
  */
  bool remove_pending_to_obtain_generators() const;

  //@} // The Handling of Pending Rows

  //! \name Updating and Sorting Matrices
  //@{

  //! Updates constraints starting from generators and minimizes them.
  /*!
    The resulting system of constraints is only partially sorted:
    the equalities are in the upper part of the matrix,
    while the inequalities in the lower part.
  */
  void update_constraints() const;

  //! Updates generators starting from constraints and minimizes them.
  /*!
    \return
    <CODE>false</CODE> if and only if \p *this turns out to be an
    empty polyhedron.

    The resulting system of generators is only partially sorted:
    the lines are in the upper part of the matrix,
    while rays and points are in the lower part.
    It is illegal to call this method when the Status field
    already declares the polyhedron to be empty.
  */
  bool update_generators() const;

  //! Updates \p sat_c using the updated constraints and generators.
  /*!
    It is assumed that constraints and generators are up-to-date
    and minimized and that the Status field does not already flag
    \p sat_c to be up-to-date.
    The values of the saturation matrix are computed as follows:
    \f[
      \begin{cases}
        sat\_c[i][j] = 0,
          \quad \text{if } G[i] \cdot C^\mathrm{T}[j] = 0; \\
        sat\_c[i][j] = 1,
          \quad \text{if } G[i] \cdot C^\mathrm{T}[j] > 0.
      \end{cases}
    \f]
  */
  void update_sat_c() const;

  //! Updates \p sat_g using the updated constraints and generators.
  /*!
    It is assumed that constraints and generators are up-to-date
    and minimized and that the Status field does not already flag
    \p sat_g to be up-to-date.
    The values of the saturation matrix are computed as follows:
    \f[
      \begin{cases}
        sat\_g[i][j] = 0,
          \quad \text{if } C[i] \cdot G^\mathrm{T}[j] = 0; \\
        sat\_g[i][j] = 1,
          \quad \text{if } C[i] \cdot G^\mathrm{T}[j] > 0.
      \end{cases}
    \f]
  */
  void update_sat_g() const;

  //! Sorts the matrix of constraints keeping status consistency.
  /*!
    It is assumed that constraints are up-to-date.
    If at least one of the saturation matrices is up-to-date,
    then \p sat_g is kept consistent with the sorted matrix
    of constraints.
    The method is declared \p const because reordering
    the constraints does not modify the polyhedron
    from a \e logical point of view.
  */
  void obtain_sorted_constraints() const;

  //! Sorts the matrix of generators keeping status consistency.
  /*!
    It is assumed that generators are up-to-date.
    If at least one of the saturation matrices is up-to-date,
    then \p sat_c is kept consistent with the sorted matrix
    of generators.
    The method is declared \p const because reordering
    the generators does not modify the polyhedron
    from a \e logical point of view.
  */
  void obtain_sorted_generators() const;

  //! Sorts the matrix of constraints and updates \p sat_c.
  /*!
    It is assumed that both constraints and generators
    are up-to-date and minimized.
    The method is declared \p const because reordering
    the constraints does not modify the polyhedron
    from a \e logical point of view.
  */
  void obtain_sorted_constraints_with_sat_c() const;

  //! Sorts the matrix of generators and updates \p sat_g.
  /*!
    It is assumed that both constraints and generators
    are up-to-date and minimized.
    The method is declared \p const because reordering
    the generators does not modify the polyhedron
    from a \e logical point of view.
  */
  void obtain_sorted_generators_with_sat_g() const;

  //@} // Updating and Sorting Matrices

  //! \name Weak and Strong Minimization of Descriptions
  //@{

  //! Applies (weak) minimization to both the constraints and generators.
  /*!
    \return
    <CODE>false</CODE> if and only if \p *this turns out to be an
    empty polyhedron.

    Minimization is not attempted if the Status field already declares
    both systems to be minimized.
  */
  bool minimize() const;

  //! Applies strong minimization to the constraints of an NNC polyhedron.
  /*!
    \return
    <CODE>false</CODE> if and only if \p *this turns out to be an
    empty polyhedron.
  */
  bool strongly_minimize_constraints() const;

  //! Applies strong minimization to the generators of an NNC polyhedron.
  /*!
    \return
    <CODE>false</CODE> if and only if \p *this turns out to be an
    empty polyhedron.
  */
  bool strongly_minimize_generators() const;

  //@} // Weak and Strong Minimization of Descriptions

  enum Three_Valued_Boolean {
    TVB_TRUE,
    TVB_FALSE,
    TVB_DONT_KNOW
  };

  //! Polynomial but incomplete equivalence test between polyhedra.
  Three_Valued_Boolean quick_equivalence_test(const Polyhedron& y) const;

  //! Returns <CODE>true</CODE> if and only if \p *this is included in \p y.
  bool is_included_in(const Polyhedron& y) const;

  //! Checks if and how \p expr is bounded in \p *this.
  /*!
    Returns <CODE>true</CODE> if and only if \p from_above is
    <CODE>true</CODE> and \p expr is bounded from above in \p *this,
    or \p from_above is <CODE>false</CODE> and \p expr is bounded
    from below in \p *this.

    \param expr
    The linear expression to test;

    \param from_above
    <CODE>true</CODE> if and only if the boundedness of interest is
    "from above".

    \exception std::invalid_argument
    Thrown if \p expr and \p *this are dimension-incompatible.
  */
  bool bounds(const Linear_Expression& expr, bool from_above) const;

  //! Maximizes or minimizes \p expr subject to \p *this.
  /*!
    \param expr
    The linear expression to be maximized or minimized subject to \p
    *this;

    \param maximize
    <CODE>true</CODE> if maximization is what is wanted;

    \param ext_n
    The numerator of the extremum value;

    \param ext_d
    The denominator of the extremum value;

    \param included
    <CODE>true</CODE> if and only if the extremum of \p expr can
    actually be reached in \p * this;

    \param point
    When maximization or minimization succeeds, will be assigned
    a point or closure point where \p expr reaches the
    corresponding extremum value.

    \exception std::invalid_argument
    Thrown if \p expr and \p *this are dimension-incompatible.

    If \p *this is empty or \p expr is not bounded in the appropriate
    direction, <CODE>false</CODE> is returned and \p ext_n, \p ext_d,
    \p included and \p point are left untouched.
  */
  bool max_min(const Linear_Expression& expr,
	       const bool maximize,
	       Coefficient& ext_n, Coefficient& ext_d, bool& included,
	       Generator& point) const;

  //! \name Widening- and Extrapolation-Related Functions
  //@{

  /*! \brief
    Copies to \p cs_selection the constraints of \p y corresponding
    to the definition of the CH78-widening of \p *this and \p y.
  */
  void select_CH78_constraints(const Polyhedron& y,
			       Constraint_System& cs_selected) const;

  /*! \brief
    Splits the constraints of `x' into two subsets, depending on whether
    or not they are selected to compute the \ref H79_widening "H79-widening"
    of \p *this and \p y.
  */
  void select_H79_constraints(const Polyhedron& y,
			      Constraint_System& cs_selected,
			      Constraint_System& cs_not_selected) const;

  bool BHRZ03_combining_constraints(const Polyhedron& y,
				    const BHRZ03_Certificate& y_cert,
 				    const Polyhedron& H79,
				    const Constraint_System& x_minus_H79_con_sys);

  bool BHRZ03_evolving_points(const Polyhedron& y,
			      const BHRZ03_Certificate& y_cert,
			      const Polyhedron& H79);

  bool BHRZ03_evolving_rays(const Polyhedron& y,
			    const BHRZ03_Certificate& y_cert,
			    const Polyhedron& H79);

  //@} // Widening- and Extrapolation-Related Functions

  //! Adds new space dimensions to the given matrices.
  /*!
    \param mat1
    The matrix to which columns are added;

    \param mat2
    The matrix to which rows and columns are added;

    \param sat1
    The saturation matrix whose columns are indexed by the rows of
    matrix \p mat1. On entry it is up-to-date;

    \param sat2
    The saturation matrix whose columns are indexed by the rows of \p
    mat2;

    \param add_dim
    The number of space dimensions to add.

    Adds new space dimensions to the vector space modifying the matrices.
    This function is invoked only by
    <CODE>add_space_dimensions_and_embed()</CODE> and
    <CODE>add_space_dimensions_and_project()</CODE>, passing the matrix of
    constraints and that of generators (and the corresponding saturation
    matrices) in different order (see those methods for details).
  */
  static void add_space_dimensions(Linear_System& mat1,
				   Linear_System& mat2,
				   Saturation_Matrix& sat1,
				   Saturation_Matrix& sat2,
				   dimension_type add_dim);

  //! \name Minimization-Related Static Member Functions
  //@{

  //! Builds and simplifies constraints from generators (or vice versa).
  // Detailed Doxygen comment to be found in file minimize.cc.
  static bool minimize(bool con_to_gen,
		       Linear_System& source,
		       Linear_System& dest,
		       Saturation_Matrix& sat);

  /*! \brief
    Adds given constraints and builds minimized corresponding generators
    or vice versa.
  */
  // Detailed Doxygen comment to be found in file minimize.cc.
  static bool add_and_minimize(bool con_to_gen,
			       Linear_System& source1,
			       Linear_System& dest,
			       Saturation_Matrix& sat,
			       const Linear_System& source2);

  /*! \brief
    Adds given constraints and builds minimized corresponding generators
    or vice versa. The given constraints are in \p source.
  */
  // Detailed Doxygen comment to be found in file minimize.cc.
  static bool add_and_minimize(bool con_to_gen,
			       Linear_System& source,
			       Linear_System& dest,
			       Saturation_Matrix& sat);

  //! Performs the conversion from constraints to generators and vice versa.
  // Detailed Doxygen comment to be found in file conversion.cc.
  static dimension_type conversion(Linear_System& source,
				   dimension_type start,
				   Linear_System& dest,
				   Saturation_Matrix& sat,
				   dimension_type num_lines_or_equalities);

  /*! \brief
    Uses Gauss' elimination method to simplify the result of
    <CODE>conversion()</CODE>.
  */
  // Detailed Doxygen comment to be found in file simplify.cc.
  static int simplify(Linear_System& mat, Saturation_Matrix& sat);

  //@} // Minimization-Related Static Member Functions

  template <typename T> friend class Parma_Polyhedra_Library::BD_Shape;
  friend class Parma_Polyhedra_Library::BHRZ03_Certificate;
  friend class Parma_Polyhedra_Library::H79_Certificate;


  //! \name Exception Throwers
  //@{
protected:
  void throw_runtime_error(const char* method) const;
  void throw_invalid_argument(const char* method, const char* reason) const;

  void throw_topology_incompatible(const char* method,
				   const char* ph_name,
				   const Polyhedron& ph) const;
  void throw_topology_incompatible(const char* method,
				   const char* c_name,
				   const Constraint& c) const;
  void throw_topology_incompatible(const char* method,
				   const char* g_name,
				   const Generator& g) const;
  void throw_topology_incompatible(const char* method,
				   const char* cs_name,
				   const Constraint_System& cs) const;
  void throw_topology_incompatible(const char* method,
				   const char* gs_name,
				   const Generator_System& gs) const;

  void throw_dimension_incompatible(const char* method,
				    const char* other_name,
				    dimension_type other_dim) const;
  void throw_dimension_incompatible(const char* method,
				    const char* ph_name,
				    const Polyhedron& ph) const;
  void throw_dimension_incompatible(const char* method,
				    const char* e_name,
				    const Linear_Expression& e) const;
  void throw_dimension_incompatible(const char* method,
				    const char* c_name,
				    const Constraint& c) const;
  void throw_dimension_incompatible(const char* method,
				    const char* g_name,
				    const Generator& g) const;
  void throw_dimension_incompatible(const char* method,
				    const char* cg_name,
				    const Congruence& cg) const;
  void throw_dimension_incompatible(const char* method,
				    const char* cs_name,
				    const Constraint_System& cs) const;
  void throw_dimension_incompatible(const char* method,
				    const char* gs_name,
				    const Generator_System& gs) const;
  void throw_dimension_incompatible(const char* method,
				    const char* cgs_name,
				    const Congruence_System& cgs) const;
  void throw_dimension_incompatible(const char* method,
				    const char* var_name,
				    const Variable var) const;
  void throw_dimension_incompatible(const char* method,
				    dimension_type required_space_dim) const;

  // Note: it has to be a static method, because it can be called inside
  // constructors (before actually constructing the polyhedron object).
  static void throw_space_dimension_overflow(Topology topol,
					     const char* method,
					     const char* reason);

  void throw_invalid_generator(const char* method,
			       const char* g_name) const;
  void throw_invalid_generators(const char* method,
				const char* gs_name) const;
  //@} // Exception Throwers

};


namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Polyhedron */
void swap(Parma_Polyhedra_Library::Polyhedron& x,
	  Parma_Polyhedra_Library::Polyhedron& y);

} // namespace std

// Automatically generated from PPL source file ../src/Ph_Status.inlines.hh line 1
/* Polyhedron::Status class implementation: inline functions.
*/


namespace Parma_Polyhedra_Library {

inline
Polyhedron::Status::Status(flags_t mask)
  : flags(mask) {
}

inline
Polyhedron::Status::Status()
  : flags(ZERO_DIM_UNIV) {
}

inline bool
Polyhedron::Status::test_all(flags_t mask) const {
  return (flags & mask) == mask;
}

inline bool
Polyhedron::Status::test_any(flags_t mask) const {
  return flags & mask;
}

inline void
Polyhedron::Status::set(flags_t mask) {
  flags |= mask;
}

inline void
Polyhedron::Status::reset(flags_t mask) {
  flags &= ~mask;
}

inline bool
Polyhedron::Status::test_zero_dim_univ() const {
  return flags == ZERO_DIM_UNIV;
}

inline void
Polyhedron::Status::reset_zero_dim_univ() {
  // This is a no-op if the current status is not zero-dim.
  if (flags == ZERO_DIM_UNIV)
    // In the zero-dim space, if it is not the universe it is empty.
    flags = EMPTY;
}

inline void
Polyhedron::Status::set_zero_dim_univ() {
  // Zero-dim universe is incompatible with anything else.
  flags = ZERO_DIM_UNIV;
}

inline bool
Polyhedron::Status::test_empty() const {
  return test_any(EMPTY);
}

inline void
Polyhedron::Status::reset_empty() {
  reset(EMPTY);
}

inline void
Polyhedron::Status::set_empty() {
  flags = EMPTY;
}

inline bool
Polyhedron::Status::test_c_up_to_date() const {
  return test_any(C_UP_TO_DATE);
}

inline void
Polyhedron::Status::reset_c_up_to_date() {
  reset(C_UP_TO_DATE);
}

inline void
Polyhedron::Status::set_c_up_to_date() {
  set(C_UP_TO_DATE);
}

inline bool
Polyhedron::Status::test_g_up_to_date() const {
  return test_any(G_UP_TO_DATE);
}

inline void
Polyhedron::Status::reset_g_up_to_date() {
  reset(G_UP_TO_DATE);
}

inline void
Polyhedron::Status::set_g_up_to_date() {
  set(G_UP_TO_DATE);
}

inline bool
Polyhedron::Status::test_c_minimized() const {
  return test_any(C_MINIMIZED);
}

inline void
Polyhedron::Status::reset_c_minimized() {
  reset(C_MINIMIZED);
}

inline void
Polyhedron::Status::set_c_minimized() {
  set(C_MINIMIZED);
}

inline bool
Polyhedron::Status::test_g_minimized() const {
  return test_any(G_MINIMIZED);
}

inline void
Polyhedron::Status::reset_g_minimized() {
  reset(G_MINIMIZED);
}

inline void
Polyhedron::Status::set_g_minimized() {
  set(G_MINIMIZED);
}


inline bool
Polyhedron::Status::test_c_pending() const {
  return test_any(CS_PENDING);
}

inline void
Polyhedron::Status::reset_c_pending() {
  reset(CS_PENDING);
}

inline void
Polyhedron::Status::set_c_pending() {
  set(CS_PENDING);
}

inline bool
Polyhedron::Status::test_g_pending() const {
  return test_any(GS_PENDING);
}

inline void
Polyhedron::Status::reset_g_pending() {
  reset(GS_PENDING);
}

inline void
Polyhedron::Status::set_g_pending() {
  set(GS_PENDING);
}


inline bool
Polyhedron::Status::test_sat_c_up_to_date() const {
  return test_any(SAT_C_UP_TO_DATE);
}

inline void
Polyhedron::Status::reset_sat_c_up_to_date() {
  reset(SAT_C_UP_TO_DATE);
}

inline void
Polyhedron::Status::set_sat_c_up_to_date() {
  set(SAT_C_UP_TO_DATE);
}

inline bool
Polyhedron::Status::test_sat_g_up_to_date() const {
  return test_any(SAT_G_UP_TO_DATE);
}

inline void
Polyhedron::Status::reset_sat_g_up_to_date() {
  reset(SAT_G_UP_TO_DATE);
}

inline void
Polyhedron::Status::set_sat_g_up_to_date() {
  set(SAT_G_UP_TO_DATE);
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Polyhedron.inlines.hh line 1
/* Polyhedron class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/Polyhedron.inlines.hh line 29
#include <algorithm>
#include <deque>

namespace Parma_Polyhedra_Library {

inline memory_size_type
Polyhedron::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

inline dimension_type
Polyhedron::max_space_dimension() {
  using std::min;
  // One dimension is reserved to have a value of type dimension_type
  // that does not represent a legal dimension.
  return min(std::numeric_limits<dimension_type>::max() - 1,
	     min(Constraint_System::max_space_dimension(),
		 Generator_System::max_space_dimension()
		 )
	     );
}

inline Topology
Polyhedron::topology() const {
  // We can check either one of the two matrices.
  // (`con_sys' is slightly better, since it is placed at offset 0.)
  return con_sys.topology();
}

inline bool
Polyhedron::is_necessarily_closed() const {
  // We can check either one of the two matrices.
  // (`con_sys' is slightly better, since it is placed at offset 0.)
  return con_sys.is_necessarily_closed();
}

inline dimension_type
Polyhedron::space_dimension() const {
  return space_dim;
}

inline void
Polyhedron::upper_bound_assign(const Polyhedron& y) {
  poly_hull_assign(y);
}

inline void
Polyhedron::difference_assign(const Polyhedron& y) {
  poly_difference_assign(y);
}

inline
Polyhedron::~Polyhedron() {
}

inline void
Polyhedron::swap(Polyhedron& y) {
  if (topology() != y.topology())
    throw_topology_incompatible("swap(y)", "y", y);
  std::swap(con_sys, y.con_sys);
  std::swap(gen_sys, y.gen_sys);
  std::swap(sat_c, y.sat_c);
  std::swap(sat_g, y.sat_g);
  std::swap(status, y.status);
  std::swap(space_dim, y.space_dim);
}

} // namespace Parma_Polyhedra_Library

/*! \relates Parma_Polyhedra_Library::Polyhedron */
inline void
std::swap(Parma_Polyhedra_Library::Polyhedron& x,
	  Parma_Polyhedra_Library::Polyhedron& y) {
  x.swap(y);
}

namespace Parma_Polyhedra_Library {

inline bool
Polyhedron::marked_empty() const {
  return status.test_empty();
}

inline bool
Polyhedron::constraints_are_up_to_date() const {
  return status.test_c_up_to_date();
}

inline bool
Polyhedron::generators_are_up_to_date() const {
  return status.test_g_up_to_date();
}

inline bool
Polyhedron::constraints_are_minimized() const {
  return status.test_c_minimized();
}

inline bool
Polyhedron::generators_are_minimized() const {
  return status.test_g_minimized();
}

inline bool
Polyhedron::sat_c_is_up_to_date() const {
  return status.test_sat_c_up_to_date();
}

inline bool
Polyhedron::sat_g_is_up_to_date() const {
  return status.test_sat_g_up_to_date();
}

inline bool
Polyhedron::has_pending_constraints() const {
  return status.test_c_pending();
}

inline bool
Polyhedron::has_pending_generators() const {
  return status.test_g_pending();
}

inline bool
Polyhedron::has_something_pending() const {
  return status.test_c_pending() || status.test_g_pending();
}

inline bool
Polyhedron::can_have_something_pending() const {
  return constraints_are_minimized()
    && generators_are_minimized()
    && (sat_c_is_up_to_date() || sat_g_is_up_to_date());
}

inline void
Polyhedron::set_constraints_up_to_date() {
  status.set_c_up_to_date();
}

inline void
Polyhedron::set_generators_up_to_date() {
  status.set_g_up_to_date();
}

inline void
Polyhedron::set_constraints_minimized() {
  set_constraints_up_to_date();
  status.set_c_minimized();
}

inline void
Polyhedron::set_generators_minimized() {
  set_generators_up_to_date();
  status.set_g_minimized();
}

inline void
Polyhedron::set_constraints_pending() {
  status.set_c_pending();
}

inline void
Polyhedron::set_generators_pending() {
  status.set_g_pending();
}

inline void
Polyhedron::set_sat_c_up_to_date() {
  status.set_sat_c_up_to_date();
}

inline void
Polyhedron::set_sat_g_up_to_date() {
  status.set_sat_g_up_to_date();
}

inline void
Polyhedron::clear_empty() {
  status.reset_empty();
}

inline void
Polyhedron::clear_constraints_minimized() {
  status.reset_c_minimized();
}

inline void
Polyhedron::clear_generators_minimized() {
  status.reset_g_minimized();
}

inline void
Polyhedron::clear_pending_constraints() {
  status.reset_c_pending();
}

inline void
Polyhedron::clear_pending_generators() {
  status.reset_g_pending();
}

inline void
Polyhedron::clear_sat_c_up_to_date() {
  status.reset_sat_c_up_to_date();
  // Can get rid of sat_c here.
}

inline void
Polyhedron::clear_sat_g_up_to_date() {
  status.reset_sat_g_up_to_date();
  // Can get rid of sat_g here.
}

inline void
Polyhedron::clear_constraints_up_to_date() {
  clear_pending_constraints();
  clear_constraints_minimized();
  clear_sat_c_up_to_date();
  clear_sat_g_up_to_date();
  status.reset_c_up_to_date();
  // Can get rid of con_sys here.
}

inline void
Polyhedron::clear_generators_up_to_date() {
  clear_pending_generators();
  clear_generators_minimized();
  clear_sat_c_up_to_date();
  clear_sat_g_up_to_date();
  status.reset_g_up_to_date();
  // Can get rid of gen_sys here.
}

inline bool
Polyhedron::process_pending() const {
  assert(space_dim > 0 && !marked_empty());
  assert(has_something_pending());

  Polyhedron& x = const_cast<Polyhedron&>(*this);

  if (x.has_pending_constraints())
    return x.process_pending_constraints();

  assert(x.has_pending_generators());
  x.process_pending_generators();
  return true;
}

inline bool
Polyhedron::is_empty() const {
  if (marked_empty())
    return true;
  // Try a fast-fail test: if generators are up-to-date and
  // there are no pending constraints, then the generator system
  // (since it is well formed) contains a point.
  if (generators_are_up_to_date() && !has_pending_constraints())
    return false;
  return !minimize();
}

inline bool
Polyhedron::bounds_from_above(const Linear_Expression& expr) const {
  return bounds(expr, true);
}

inline bool
Polyhedron::bounds_from_below(const Linear_Expression& expr) const {
  return bounds(expr, false);
}

inline bool
Polyhedron::maximize(const Linear_Expression& expr,
		     Coefficient& sup_n, Coefficient& sup_d,
		     bool& maximum) const {
  Generator g(point());
  return max_min(expr, true, sup_n, sup_d, maximum, g);
}

inline bool
Polyhedron::maximize(const Linear_Expression& expr,
		     Coefficient& sup_n, Coefficient& sup_d, bool& maximum,
		     Generator& g) const {
  return max_min(expr, true, sup_n, sup_d, maximum, g);
}

inline bool
Polyhedron::minimize(const Linear_Expression& expr,
		     Coefficient& inf_n, Coefficient& inf_d,
		     bool& minimum) const {
  Generator g(point());
  return max_min(expr, false, inf_n, inf_d, minimum, g);
}

inline bool
Polyhedron::minimize(const Linear_Expression& expr,
		     Coefficient& inf_n, Coefficient& inf_d, bool& minimum,
		     Generator& g) const {
  return max_min(expr, false, inf_n, inf_d, minimum, g);
}

/*! \relates Polyhedron */
inline bool
operator!=(const Polyhedron& x, const Polyhedron& y) {
  return !(x == y);
}

inline bool
Polyhedron::strictly_contains(const Polyhedron& y) const {
  const Polyhedron& x = *this;
  return x.contains(y) && !y.contains(x);
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Polyhedron.templates.hh line 1
/* Polyhedron class implementation: non-inline template functions.
*/


// Automatically generated from PPL source file ../src/Polyhedron.templates.hh line 29
#include <algorithm>
#include <deque>

namespace Parma_Polyhedra_Library {

template <typename Box>
Polyhedron::Polyhedron(Topology topol, const Box& box)
  : con_sys(topol),
    gen_sys(topol),
    sat_c(),
    sat_g() {
  // Initialize the space dimension as indicated by the box.
  space_dim = box.space_dimension();

  // Check for emptiness.
  if (box.is_empty()) {
    set_empty();
    return;
  }

  // Zero-dim universe polyhedron.
  if (space_dim == 0) {
    set_zero_dim_univ();
    return;
  }

  // Insert a dummy constraint of the highest dimension to avoid the
  // need of resizing the matrix of constraints later;
  // this constraint will be removed at the end.
  con_sys.insert(Variable(space_dim - 1) >= 0);

  for (dimension_type k = space_dim; k-- > 0; ) {
    // See if we have a valid lower bound.
    bool l_closed = false;
    Coefficient l_n, l_d;
    bool l_bounded = box.get_lower_bound(k, l_closed, l_n, l_d);
    if (l_bounded && topol == NECESSARILY_CLOSED && !l_closed)
      throw_invalid_argument("C_Polyhedron(const Box& box):",
			     " box has an open lower bound");
    // See if we have a valid upper bound.
    bool u_closed = false;
    Coefficient u_n, u_d;
    bool u_bounded = box.get_upper_bound(k, u_closed, u_n, u_d);
    if (u_bounded && topol == NECESSARILY_CLOSED && !u_closed)
      throw_invalid_argument("C_Polyhedron(const Box& box):",
			     " box has an open upper bound");

    // See if we have an implicit equality constraint.
    if (l_bounded && u_bounded
	&& l_closed && u_closed
	&& l_n == u_n && l_d == u_d) {
      // Add the constraint `l_d*v_k == l_n'.
      con_sys.insert(l_d * Variable(k) == l_n);
    }
    else {
      // Check if a lower bound constraint is required.
      if (l_bounded) {
       if (l_closed)
	 // Add the constraint `l_d*v_k >= l_n'.
	 con_sys.insert(l_d * Variable(k) >= l_n);
       else
	 // Add the constraint `l_d*v_k > l_n'.
	 con_sys.insert(l_d * Variable(k) > l_n);
      }
      // Check if an upper bound constraint is required.
      if (u_bounded) {
       if (u_closed)
	 // Add the constraint `u_d*v_k <= u_n'.
	 con_sys.insert(u_d * Variable(k) <= u_n);
       else
	 // Add the constraint `u_d*v_k < u_n'.
	 con_sys.insert(u_d * Variable(k) < u_n);
      }
    }
  }

  // Adding the low-level constraints.
  con_sys.add_low_level_constraints();
  // Now removing the dummy constraint inserted before.
  dimension_type n_rows = con_sys.num_rows() - 1;
  con_sys[0].swap(con_sys[n_rows]);
  con_sys.set_sorted(false);
  // NOTE: here there are no pending constraints.
  con_sys.set_index_first_pending_row(n_rows);
  con_sys.erase_to_end(n_rows);

  // Constraints are up-to-date.
  set_constraints_up_to_date();
  assert(OK());
}

template <typename Box>
void
Polyhedron::shrink_bounding_box(Box& box, Complexity_Class complexity) const {
  bool reduce_complexity = (complexity != ANY_COMPLEXITY);
  if (!reduce_complexity
      || (!has_something_pending() && constraints_are_minimized())) {
    // If the constraint system is minimized, the test `is_universe()'
    // is not exponential.
    if (is_universe())
      return;
  }
  if (reduce_complexity) {
    if (marked_empty()
	|| (generators_are_up_to_date() && gen_sys.num_rows() == 0)) {
      box.set_empty();
      return;
    }
    else if (constraints_are_up_to_date()) {
      // See if there is at least one inconsistent constraint in `con_sys'.
      for (Constraint_System::const_iterator i = con_sys.begin(),
	     cs_end = con_sys.end(); i != cs_end; ++i)
	if (i->is_inconsistent()) {
	  box.set_empty();
	  return;
	}
      // If `complexity' allows it, use the LP_Problem solver to determine
      // whether or not the polyhedron is empty.
      if (complexity == SIMPLEX_COMPLEXITY
	  // TODO: find a workaround for NNC polyhedra.
	  && is_necessarily_closed()) {
	LP_Problem lp(con_sys);
	if (!lp.is_satisfiable()) {
	  box.set_empty();
	  return;
	}
      }
    }
  }
  else
    // The flag `reduce_complexity' is `false'.
    // Note that the test `is_empty()' is exponential in the worst case.
    if (is_empty()) {
      box.set_empty();
      return;
    }

  if (space_dim == 0)
    return;

  // The following vectors will store the lower and upper bound
  // for each dimension.
  // Lower bounds are initialized to open plus infinity.
  std::vector<LBoundary>
    lower_bound(space_dim,
		LBoundary(ERational(PLUS_INFINITY), LBoundary::OPEN));
  // Upper bounds are initialized to open minus infinity.
  std::vector<UBoundary>
    upper_bound(space_dim,
		UBoundary(ERational(MINUS_INFINITY), UBoundary::OPEN));

  if (!reduce_complexity && has_something_pending())
    process_pending();

  // TODO: use simplex to derive variable bounds, if the complexity
  // is SIMPLEX_COMPLEXITY.

  if (reduce_complexity &&
       (!generators_are_up_to_date() || has_pending_constraints())) {
    // Extract easy-to-find bounds from constraints.
    assert(constraints_are_up_to_date());

    // We must copy `con_sys' to a temporary matrix,
    // as we need to simplify all of the matrix
    // (not just the non-pending part of it).
    Constraint_System cs(con_sys);
    if (cs.num_pending_rows() > 0)
      cs.unset_pending_rows();
    if (has_pending_constraints() || !constraints_are_minimized())
      cs.simplify();

    const Constraint_System::const_iterator cs_begin = cs.begin();
    const Constraint_System::const_iterator cs_end = cs.end();

    for (Constraint_System::const_iterator i = cs_begin; i != cs_end; ++i) {
      dimension_type varid = space_dim;
      const Constraint& c = *i;
      // After `simplify()' some constraints may have become inconsistent.
      if (c.is_inconsistent()) {
	box.set_empty();
	return;
      }
      for (dimension_type j = space_dim; j-- > 0; ) {
	// We look for constraints of the form `Variable(j) == k',
	// `Variable(j) >= k', and `Variable(j) > k'.
	if (c.coefficient(Variable(j)) != 0)
	  if (varid != space_dim) {
	    varid = space_dim;
	    break;
	  }
	  else
	    varid = j;
      }
      if (varid != space_dim) {
	Coefficient_traits::const_reference d = c.coefficient(Variable(varid));
	Coefficient_traits::const_reference n = c.inhomogeneous_term();
	// The constraint `c' is of the form
	// `Variable(varid) + n / d rel 0', where
	// `rel' is either the relation `==', `>=', or `>'.
	// For the purpose of shrinking intervals, this is
	// (morally) turned into `Variable(varid) rel -n/d'.
	mpq_class q;
	assign_r(q.get_num(), n, ROUND_NOT_NEEDED);
	assign_r(q.get_den(), d, ROUND_NOT_NEEDED);
	q.canonicalize();
	// Turn `n/d' into `-n/d'.
	q = -q;
	const ERational r(q, ROUND_NOT_NEEDED);
	const Constraint::Type c_type = c.type();
	switch (c_type) {
	case Constraint::EQUALITY:
	  lower_bound[varid] = LBoundary(r, LBoundary::CLOSED);
	  upper_bound[varid] = UBoundary(r, UBoundary::CLOSED);
	  break;
	case Constraint::NONSTRICT_INEQUALITY:
	case Constraint::STRICT_INEQUALITY:
	  if (d > 0)
	  // If `d' is strictly positive, we have a constraint of the
	  // form `Variable(varid) >= k' or `Variable(varid) > k'.
	    lower_bound[varid]
	      = LBoundary(r, (c_type == Constraint::NONSTRICT_INEQUALITY
			      ? LBoundary::CLOSED
			      : LBoundary::OPEN));
	  else {
	    // Otherwise, we are sure that `d' is strictly negative
	    // and, in this case, we have a constraint of the form
	    // `Variable(varid) <= k' or `Variable(varid) < k'.
	    assert(d < 0);
	    upper_bound[varid]
	      = UBoundary(r, (c_type == Constraint::NONSTRICT_INEQUALITY
			      ? UBoundary::CLOSED
			      : UBoundary::OPEN));
	  }
	  break;
	}
      }
    }
  }
  else {
    // We are in the case where either the generators are up-to-date
    // or reduced complexity is not required.
    // Get the generators for *this.

    // We have not to copy `gen_sys', because in this case
    // we only read the generators.
    const Generator_System& gs = gen_sys;

    // We first need to identify those axes that are unbounded below
    // and/or above.
    for (Generator_System::const_iterator i = gs.begin(),
	   gs_end = gs.end(); i != gs_end; ++i) {
      // Note: using an iterator, we read also the pending part of the matrix.
      const Generator& g = *i;
      Generator::Type g_type = g.type();
      switch (g_type) {
      case Generator::LINE:
	// Any axes `j' in which the coefficient is non-zero is unbounded
	// both below and above.
	for (dimension_type j = space_dim; j-- > 0; )
	  if (g.coefficient(Variable(j)) != 0) {
	    lower_bound[j] = LBoundary(ERational(MINUS_INFINITY),
				       LBoundary::OPEN);
	    upper_bound[j] = UBoundary(ERational(PLUS_INFINITY),
				       UBoundary::OPEN);
	  }
	break;
      case Generator::RAY:
	// Axes in which the coefficient is negative are unbounded below.
	// Axes in which the coefficient is positive are unbounded above.
	for (dimension_type j = space_dim; j-- > 0; ) {
	  int sign = sgn(g.coefficient(Variable(j)));
	  if (sign < 0)
	    lower_bound[j] = LBoundary(ERational(MINUS_INFINITY),
				       LBoundary::OPEN);
	  else if (sign > 0)
	    upper_bound[j] = UBoundary(ERational(PLUS_INFINITY),
				       UBoundary::OPEN);
	}
	break;
      case Generator::POINT:
      case Generator::CLOSURE_POINT:
	{
	  Coefficient_traits::const_reference d = g.divisor();
	  for (dimension_type j = space_dim; j-- > 0; ) {
	    Coefficient_traits::const_reference n = g.coefficient(Variable(j));
	    mpq_class q;
	    assign_r(q.get_num(), n, ROUND_NOT_NEEDED);
	    assign_r(q.get_den(), d, ROUND_NOT_NEEDED);
	    q.canonicalize();
	    const ERational r(q, ROUND_NOT_NEEDED);
	    LBoundary lb(r,(g_type == Generator::CLOSURE_POINT
			    ? LBoundary::OPEN
			    : LBoundary::CLOSED));
	    if (lb < lower_bound[j])
	      lower_bound[j] = lb;
	    UBoundary ub(r, (g_type == Generator::CLOSURE_POINT
			     ? UBoundary::OPEN
			     : UBoundary::CLOSED));
	    if (ub > upper_bound[j])
	      upper_bound[j] = ub;
	  }
	}
	break;
      }
    }
  }

  TEMP_INTEGER(n);
  TEMP_INTEGER(d);

  // Now shrink the bounded axes.
  for (dimension_type j = space_dim; j-- > 0; ) {
    // Lower bound.
    const LBoundary& lb = lower_bound[j];
    const ERational& lr = lb.bound();
    if (!is_plus_infinity(lr) && !is_minus_infinity(lr)) {
      n = raw_value(lr).get_num();
      d = raw_value(lr).get_den();
      box.raise_lower_bound(j, lb.is_closed(), n, d);
    }

    // Upper bound.
    const UBoundary& ub = upper_bound[j];
    const ERational& ur = ub.bound();
    if (!is_plus_infinity(ur) && !is_minus_infinity(ur)) {
      n = raw_value(ur).get_num();
      d = raw_value(ur).get_den();
      box.lower_upper_bound(j, ub.is_closed(), n, d);
    }
  }
}

template <typename Partial_Function>
void
Polyhedron::map_space_dimensions(const Partial_Function& pfunc) {
  if (space_dim == 0)
    return;

  if (pfunc.has_empty_codomain()) {
    // All dimensions vanish: the polyhedron becomes zero_dimensional.
    if (marked_empty()
	|| (has_pending_constraints()
	    && !remove_pending_to_obtain_generators())
	|| (!generators_are_up_to_date() && !update_generators())) {
      // Removing all dimensions from the empty polyhedron.
      space_dim = 0;
      con_sys.clear();
    }
    else
      // Removing all dimensions from a non-empty polyhedron.
      set_zero_dim_univ();

    assert(OK());
    return;
  }

  const dimension_type new_space_dimension = pfunc.max_in_codomain() + 1;

  if (new_space_dimension == space_dim) {
    // The partial function `pfunc' is indeed total and thus specifies
    // a permutation, that is, a renaming of the dimensions.  For
    // maximum efficiency, we will simply permute the columns of the
    // constraint system and/or the generator system.

    // We first compute suitable permutation cycles for the columns of
    // the `con_sys' and `gen_sys' matrices.  We will represent them
    // with a linear array, using 0 as a terminator for each cycle
    // (notice that the columns with index 0 of `con_sys' and
    // `gen_sys' represent the inhomogeneous terms, and thus are
    // unaffected by the permutation of dimensions).
    // Cycles of length 1 will be omitted so that, in the worst case,
    // we will have `space_dim' elements organized in `space_dim/2'
    // cycles, which means we will have at most `space_dim/2'
    // terminators.
    std::vector<dimension_type> cycles;
    cycles.reserve(space_dim + space_dim/2);

    // Used to mark elements as soon as they are inserted in a cycle.
    std::deque<bool> visited(space_dim);

    for (dimension_type i = space_dim; i-- > 0; ) {
      if (!visited[i]) {
	dimension_type j = i;
	do {
	  visited[j] = true;
	  // The following initialization is only to make the compiler happy.
	  dimension_type k = 0;
	  if (!pfunc.maps(j, k))
	    throw_invalid_argument("map_space_dimensions(pfunc)",
				   " pfunc is inconsistent");
	  if (k == j)
	    // Cycle of length 1: skip it.
	    goto skip;

	  cycles.push_back(j+1);
	  // Go along the cycle.
	  j = k;
	} while (!visited[j]);
	// End of cycle: mark it.
	cycles.push_back(0);
      skip:
	;
      }
    }

    // If `cycles' is empty then `pfunc' is the identity.
    if (cycles.empty())
      return;

    // Permute all that is up-to-date.  Notice that the contents of
    // the saturation matrices is unaffected by the permutation of
    // columns: they remain valid, if they were so.
    if (constraints_are_up_to_date())
      con_sys.permute_columns(cycles);

    if (generators_are_up_to_date())
      gen_sys.permute_columns(cycles);

    assert(OK());
    return;
  }

  // If control gets here, then `pfunc' is not a permutation and some
  // dimensions must be projected away.

  // If there are pending constraints, using `generators()' we process them.
  const Generator_System& old_gensys = generators();

  if (old_gensys.num_rows() == 0) {
    // The polyhedron is empty.
    Polyhedron new_polyhedron(topology(), new_space_dimension, EMPTY);
    std::swap(*this, new_polyhedron);
    assert(OK());
    return;
  }

  // Make a local copy of the partial function.
  std::vector<dimension_type> pfunc_maps(space_dim, not_a_dimension());
  for (dimension_type j = space_dim; j-- > 0; ) {
    dimension_type pfunc_j;
    if (pfunc.maps(j, pfunc_j))
      pfunc_maps[j] = pfunc_j;
  }

  Generator_System new_gensys;
  for (Generator_System::const_iterator i = old_gensys.begin(),
	 old_gensys_end = old_gensys.end(); i != old_gensys_end; ++i) {
    const Generator& old_g = *i;
    Linear_Expression e(0 * Variable(new_space_dimension-1));
    bool all_zeroes = true;
    for (dimension_type j = space_dim; j-- > 0; ) {
      if (old_g.coefficient(Variable(j)) != 0
	  && pfunc_maps[j] != not_a_dimension()) {
	e += Variable(pfunc_maps[j]) * old_g.coefficient(Variable(j));
	all_zeroes = false;
      }
    }
    switch (old_g.type()) {
    case Generator::LINE:
      if (!all_zeroes)
	new_gensys.insert(line(e));
      break;
    case Generator::RAY:
      if (!all_zeroes)
	new_gensys.insert(ray(e));
      break;
    case Generator::POINT:
      // A point in the origin has all zero homogeneous coefficients.
      new_gensys.insert(point(e, old_g.divisor()));
      break;
    case Generator::CLOSURE_POINT:
      // A closure point in the origin has all zero homogeneous coefficients.
      new_gensys.insert(closure_point(e, old_g.divisor()));
      break;
    }
  }
  Polyhedron new_polyhedron(topology(), new_gensys);
  std::swap(*this, new_polyhedron);
  assert(OK(true));
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Polyhedron.defs.hh line 2474

// Automatically generated from PPL source file ../src/H79_Certificate.inlines.hh line 27

namespace Parma_Polyhedra_Library {

inline
H79_Certificate::H79_Certificate()
  : affine_dim(0), num_constraints(0) {
  // This is the certificate for a zero-dim universe polyhedron.
}

inline
H79_Certificate::H79_Certificate(const H79_Certificate& y)
  : affine_dim(y.affine_dim), num_constraints(y.num_constraints) {
}

inline
H79_Certificate::~H79_Certificate() {
}

inline bool
H79_Certificate::Compare::operator()(const H79_Certificate& x,
				     const H79_Certificate& y) const {
  // For an efficient evaluation of the multiset ordering based
  // on this lgo relation, we want larger elements to come first.
  return x.compare(y) == 1;
}

template <typename PH>
inline
H79_Certificate::H79_Certificate(const PH& ph)
  : affine_dim(0), num_constraints(0) {
  H79_Certificate cert(Polyhedron(NECESSARILY_CLOSED, ph.constraints()));
  affine_dim = cert.affine_dim;
  num_constraints = cert.num_constraints;
}

template <typename PH>
inline int
H79_Certificate::compare(const PH& ph) const {
  return this->compare(Polyhedron(NECESSARILY_CLOSED, ph.constraints()));
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/H79_Certificate.defs.hh line 96

// Automatically generated from PPL source file ../src/Grid_Certificate.defs.hh line 1
/* Grid_Certificate class declaration.
*/


// Automatically generated from PPL source file ../src/Grid_Certificate.defs.hh line 27

// Automatically generated from PPL source file ../src/Grid_Certificate.defs.hh line 30
#include <cassert>
#include <vector>

//! The convergence certificate for the Grid widening operator.
/*! \ingroup PPL_CXX_interface
  Convergence certificates are used to instantiate the BHZ03 framework
  so as to define widening operators for the finite powerset domain.

  \note
  Each convergence certificate has to be used together with a
  compatible widening operator. In particular, Grid_Certificate can
  certify the Grid widening.
*/
class Parma_Polyhedra_Library::Grid_Certificate {
public:
  //! Default constructor.
  Grid_Certificate();

  //! Constructor: computes the certificate for \p gr.
  Grid_Certificate(const Grid& gr);

  //! Copy constructor.
  Grid_Certificate(const Grid_Certificate& y);

  //! Destructor.
  ~Grid_Certificate();

  //! The comparison function for certificates.
  /*!
    \return
    \f$-1\f$, \f$0\f$ or \f$1\f$ depending on whether \p *this
    is smaller than, equal to, or greater than \p y, respectively.
  */
  int compare(const Grid_Certificate& y) const;

  //! Compares \p *this with the certificate for grid \p gr.
  int compare(const Grid& gr) const;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Returns <CODE>true</CODE> if and only if the certificate for grid
    \p gr is strictly smaller than \p *this.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  bool is_stabilizing(const Grid& gr) const;

  //! A total ordering on Grid certificates.
  /*!
    This binary predicate defines a total ordering on Grid certificates
    which is used when storing information about sets of grids.
  */
  struct Compare {
    //! Returns <CODE>true</CODE> if and only if \p x comes before \p y.
    bool operator()(const Grid_Certificate& x,
		    const Grid_Certificate& y) const;
  };

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  //! Check if gathered information is meaningful.
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  bool OK() const;

private:
  //! Number of a equalities in a minimized congruence system for the
  //! grid.
  dimension_type num_equalities;
  //! Number of a proper congruences in a minimized congruence system
  //! for the grid.
  dimension_type num_proper_congruences;
};

// Automatically generated from PPL source file ../src/Grid_Certificate.inlines.hh line 1
/* Grid_Certificate class implementation: inline functions.
*/


namespace Parma_Polyhedra_Library {

inline
Grid_Certificate::Grid_Certificate()
  : num_equalities(0), num_proper_congruences(0) {
  // This is the certificate for a zero-dim universe grid.
  assert(OK());
}

inline
Grid_Certificate::Grid_Certificate(const Grid_Certificate& y)
  : num_equalities(y.num_equalities),
    num_proper_congruences(y.num_proper_congruences) {
}

inline
Grid_Certificate::~Grid_Certificate() {
}

inline bool
Grid_Certificate::is_stabilizing(const Grid& gr) const {
  return compare(gr) == 1;
}

inline bool
Grid_Certificate::Compare::operator()(const Grid_Certificate& x,
				      const Grid_Certificate& y) const {
  // For an efficient evaluation of the multiset ordering based
  // on this lgo relation, we want larger elements to come first.
  return x.compare(y) == 1;
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Grid_Certificate.defs.hh line 102

// Automatically generated from PPL source file ../src/Grid.defs.hh line 1
/* Grid class declaration.
*/


#define STRONG_REDUCTION

// Automatically generated from PPL source file ../src/Grid.defs.hh line 43
#include <vector>
#include <iosfwd>

// Dimension kind vector tracing
#define print_dim_kinds(msg, dim_kinds)					\
  std::cout << msg << "dim_kinds:";					\
  for (Dimension_Kinds::iterator i = dim_kinds.begin(); i != dim_kinds.end(); ++i) \
    std::cout << " " << *i;						\
  std::cout << std::endl;
#if 0
#define trace_dim_kinds(msg, dim_kinds) print_dim_kinds(msg, dim_kinds)
#else
#define trace_dim_kinds(msg, dim_kinds)
#endif

namespace Parma_Polyhedra_Library {

namespace IO_Operators {

//! Output operator.
/*!
  \relates Parma_Polyhedra_Library::Grid
  Writes a textual representation of \p gr on \p s: <CODE>false</CODE>
  is written if \p gr is an empty grid; <CODE>true</CODE> is written
  if \p gr is a universe grid; a minimized system of congruences
  defining \p gr is written otherwise, all congruences in one row
  separated by ", "s.
*/
std::ostream&
operator<<(std::ostream& s, const Grid& gr);

} // namespace IO_Operators

/*! \brief
  Returns <CODE>true</CODE> if and only if \p x and \p y are the same
  grid.

  \relates Grid
  Note that \p x and \p y may be dimension-incompatible grids: in
  those cases, the value <CODE>false</CODE> is returned.
*/
bool operator==(const Grid& x, const Grid& y);

/*! \brief
  Returns <CODE>true</CODE> if and only if \p x and \p y are different
  grids.

  \relates Grid
  Note that \p x and \p y may be dimension-incompatible grids: in
  those cases, the value <CODE>true</CODE> is returned.
*/
bool operator!=(const Grid& x, const Grid& y);

} // namespace Parma_Polyhedra_Library


//! A grid.
/*! \ingroup PPL_CXX_interface
  An object of the class Grid represents a rational grid.

  A grid can be specified as either a finite system of congruences
  or a finite system of generators (see Section \ref
  sect_rational_grids) and it is always possible to obtain either
  representation.
  That is, if we know the system of congruences, we can obtain
  from this the system of generators that define the same grid
  and vice versa.
  These systems can contain redundant members, or they can be in the
  minimal form.
  Most operators on grids are provided with two implementations:
  one of these, denoted <CODE>\<operator-name\>_and_minimize</CODE>,
  also enforces the minimization of the representations,
  and returns the boolean value <CODE>false</CODE> whenever
  the resulting grid turns out to be empty.

  A key attributes of any grid is its space dimension (the dimension
  \f$n \in \Nset\f$ of the enclosing vector space):

  - all grids, the empty ones included, are endowed with a space
    dimension;
  - most operations working on a grid and another object (another
    grid, a congruence, a generator, a set of variables, etc.) will
    throw an exception if the grid and the object are not
    dimension-compatible (see Section \ref Grid_Space_Dimensions);
  - the only ways in which the space dimension of a grid can be
    changed are with <EM>explicit</EM> calls to operators provided for
    that purpose, and with standard copy, assignment and swap
    operators.

  Note that two different grids can be defined on the zero-dimension
  space: the empty grid and the universe grid \f$R^0\f$.

  \par
  In all the examples it is assumed that variables
  <CODE>x</CODE> and <CODE>y</CODE> are defined (where they are
  used) as follows:
  \code
  Variable x(0);
  Variable y(1);
  \endcode

  \par Example 1
  The following code builds a grid corresponding to the even integer
  pairs in \f$\Rset^2\f$, given as a system of congruences:
  \code
  Congruence_System cgs;
  cgs.insert((x %= 0) / 2);
  cgs.insert((y %= 0) / 2);
  Grid gr(cgs);
  \endcode
  The following code builds the same grid as above, but starting
  from a system of generators specifying three of the points:
  \code
  Grid_Generator_System gs;
  gs.insert(grid_point(0*x + 0*y));
  gs.insert(grid_point(0*x + 2*y));
  gs.insert(grid_point(2*x + 0*y));
  Grid gr(gs);
  \endcode

  \par Example 2
  The following code builds a grid corresponding to a line in
  \f$\Rset^2\f$ by adding a single congruence to the universe grid:
  \code
  Congruence_System cgs;
  cgs.insert(x - y == 0);
  Grid gr(cgs);
  \endcode
  The following code builds the same grid as above, but starting
  from a system of generators specifying a point and a line:
  \code
  Grid_Generator_System gs;
  gs.insert(grid_point(0*x + 0*y));
  gs.insert(grid_line(x + y));
  Grid gr(gs);
  \endcode

  \par Example 3
  The following code builds a grid corresponding to the integral
  points on the line \f$x = y\f$ in \f$\Rset^2\f$ constructed
  by adding an equality and congruence to the universe grid:
  \code
  Congruence_System cgs;
  cgs.insert(x - y == 0);
  cgs.insert(x %= 0);
  Grid gr(cgs);
  \endcode
  The following code builds the same grid as above, but starting
  from a system of generators specifying a point and a parameter:
  \code
  Grid_Generator_System gs;
  gs.insert(grid_point(0*x + 0*y));
  gs.insert(parameter(x + y));
  Grid gr(gs);
  \endcode

  \par Example 4
  The following code builds the grid corresponding to a plane by
  creating the universe grid in \f$\Rset^2\f$:
  \code
  Grid gr(2);
  \endcode
  The following code builds the same grid as above, but starting
  from the empty grid in \f$\Rset^2\f$ and inserting the appropriate
  generators (a point, and two lines).
  \code
  Grid gr(2, EMPTY);
  gr.add_generator(grid_point(0*x + 0*y));
  gr.add_generator(grid_line(x));
  gr.add_generator(grid_line(y));
  \endcode
  Note that a generator system must contain a point when describing
  a grid.  To ensure that this is always the case it is required
  that the first generator inserted in an empty grid is a point
  (otherwise, an exception is thrown).

  \par Example 5
  The following code shows the use of the function
  <CODE>add_space_dimensions_and_embed</CODE>:
  \code
  Grid gr(1);
  gr.add_congruence(x == 2);
  gr.add_space_dimensions_and_embed(1);
  \endcode
  We build the universe grid in the 1-dimension space \f$\Rset\f$.
  Then we add a single equality congruence,
  thus obtaining the grid corresponding to the singleton set
  \f$\{ 2 \} \sseq \Rset\f$.
  After the last line of code, the resulting grid is
  \f[
  \bigl\{\,
  (2, y)^\transpose \in \Rset^2
  \bigm|
  y \in \Rset
  \,\bigr\}.
  \f]

  \par Example 6
  The following code shows the use of the function
  <CODE>add_space_dimensions_and_project</CODE>:
  \code
  Grid gr(1);
  gr.add_congruence(x == 2);
  gr.add_space_dimensions_and_project(1);
  \endcode
  The first two lines of code are the same as in Example 4 for
  <CODE>add_space_dimensions_and_embed</CODE>.
  After the last line of code, the resulting grid is
  the singleton set
  \f$\bigl\{ (2, 0)^\transpose \bigr\} \sseq \Rset^2\f$.

  \par Example 7
  The following code shows the use of the function
  <CODE>affine_image</CODE>:
  \code
  Grid gr(2, EMPTY);
  gr.add_generator(grid_point(0*x + 0*y));
  gr.add_generator(grid_point(4*x + 0*y));
  gr.add_generator(grid_point(0*x + 2*y));
  Linear_Expression expr = x + 3;
  gr.affine_image(x, expr);
  \endcode
  In this example the starting grid is all the pairs of \f$x\f$ and
  \f$y\f$ in \f$\Rset^2\f$ where \f$x\f$ is an integer multiple of 4
  and \f$y\f$ is an integer multiple of 2.  The considered variable
  is \f$x\f$ and the affine expression is \f$x+3\f$.  The resulting
  grid is the given grid translated 3 integers to the right (all the
  pairs \f$(x, y)\f$ where \f$x\f$ is -1 plus an integer multiple of 4
  and \f$y\f$ is an integer multiple of 2).
  Moreover, if the affine transformation for the same variable \p x
  is instead \f$x+y\f$:
  \code
  Linear_Expression expr = x + y;
  \endcode
  the resulting grid is every second integral point along the \f$x=y\f$
  line, with this line of points repeated at every fourth integral value
  along the \f$x\f$ axis.
  Instead, if we do not use an invertible transformation for the
  same variable; for example, the affine expression \f$y\f$:
  \code
  Linear_Expression expr = y;
  \endcode
  the resulting grid is every second point along the \f$x=y\f$ line.

  \par Example 8
  The following code shows the use of the function
  <CODE>affine_preimage</CODE>:
  \code
  Grid gr(2, EMPTY);
  gr.add_generator(grid_point(0*x + 0*y));
  gr.add_generator(grid_point(4*x + 0*y));
  gr.add_generator(grid_point(0*x + 2*y));
  Linear_Expression expr = x + 3;
  gr.affine_preimage(x, expr);
  \endcode
  In this example the starting grid, \p var and the affine
  expression and the denominator are the same as in Example 6, while
  the resulting grid is similar but translated 3 integers to the
  left (all the pairs \f$(x, y)\f$
  where \f$x\f$ is -3 plus an integer multiple of 4 and
  \f$y\f$ is an integer multiple of 2)..
  Moreover, if the affine transformation for \p x is \f$x+y\f$
  \code
  Linear_Expression expr = x + y;
  \endcode
  the resulting grid is a similar grid to the result in Example 6,
  only the grid is slanted along \f$x=-y\f$.
  Instead, if we do not use an invertible transformation for the same
  variable \p x, for example, the affine expression \f$y\f$:
  \code
  Linear_Expression expr = y;
  \endcode
  the resulting grid is every fourth line parallel to the \f$x\f$
  axis.

  \par Example 9
  For this example we also use the variables:
  \code
  Variable z(2);
  Variable w(3);
  \endcode
  The following code shows the use of the function
  <CODE>remove_space_dimensions</CODE>:
  \code
  Grid_Generator_System gs;
  gs.insert(grid_point(3*x + y +0*z + 2*w));
  Grid gr(gs);
  Variables_Set to_be_removed;
  to_be_removed.insert(y);
  to_be_removed.insert(z);
  gr.remove_space_dimensions(to_be_removed);
  \endcode
  The starting grid is the singleton set
  \f$\bigl\{ (3, 1, 0, 2)^\transpose \bigr\} \sseq \Rset^4\f$, while
  the resulting grid is
  \f$\bigl\{ (3, 2)^\transpose \bigr\} \sseq \Rset^2\f$.
  Be careful when removing space dimensions <EM>incrementally</EM>:
  since dimensions are automatically renamed after each application
  of the <CODE>remove_space_dimensions</CODE> operator, unexpected
  results can be obtained.
  For instance, by using the following code we would obtain
  a different result:
  \code
  set<Variable> to_be_removed1;
  to_be_removed1.insert(y);
  gr.remove_space_dimensions(to_be_removed1);
  set<Variable> to_be_removed2;
  to_be_removed2.insert(z);
  gr.remove_space_dimensions(to_be_removed2);
  \endcode
  In this case, the result is the grid
  \f$\bigl\{(3, 0)^\transpose \bigr\} \sseq \Rset^2\f$:
  when removing the set of dimensions \p to_be_removed2
  we are actually removing variable \f$w\f$ of the original grid.
  For the same reason, the operator \p remove_space_dimensions
  is not idempotent: removing twice the same non-empty set of dimensions
  is never the same as removing them just once.
*/

class Parma_Polyhedra_Library::Grid {
public:
  //! Returns the maximum space dimension all kinds of Grid can handle.
  static dimension_type max_space_dimension();

  //! Builds a grid having the specified properties.
  /*!
    \param num_dimensions
    The number of dimensions of the vector space enclosing the grid;

    \param kind
    Specifies whether the universe or the empty grid has to be built.

    \exception std::length_error
    Thrown if \p num_dimensions exceeds the maximum allowed space
    dimension.
  */
  explicit Grid(dimension_type num_dimensions = 0,
		const Degenerate_Element kind = UNIVERSE);

  //! Builds a grid, copying a system of congruences.
  /*!
    The grid inherits the space dimension of the congruence system.

    \param cgs
    The system of congruences defining the grid.

    \exception std::length_error
    Thrown if \p num_dimensions exceeds the maximum allowed space
    dimension.
  */
  explicit Grid(const Congruence_System& cgs);

  //! Builds a grid, recycling a system of congruences.
  /*!
    The grid inherits the space dimension of the congruence system.

    \param cgs
    The system of congruences defining the grid.  Its data-structures
    will be recycled to build the grid.

    \exception std::length_error
    Thrown if \p num_dimensions exceeds the maximum allowed space
    dimension.
  */
  explicit Grid(Congruence_System& cgs);

  //! Builds a grid, copying a system of constraints.
  /*!
    The grid inherits the space dimension of the constraint system.

    \param cs
    The system of constraints defining the grid.

    \exception std::length_error
    Thrown if \p num_dimensions exceeds the maximum allowed space
    dimension.
  */
  explicit Grid(const Constraint_System& cs);

  //! Builds a grid, recycling a system of constraints.
  /*!
    The grid inherits the space dimension of the constraint system.

    \param cs
    The system of constraints defining the grid.

    \exception std::length_error
    Thrown if \p num_dimensions exceeds the maximum allowed space
    dimension.
  */
  explicit Grid(Constraint_System& cs);

  //! Builds a grid, copying a system of generators.
  /*!
    The grid inherits the space dimension of the generator system.

    \param const_gs
    The system of generators defining the grid.

    \exception std::invalid_argument
    Thrown if the system of generators is not empty but has no points.

    \exception std::length_error
    Thrown if \p num_dimensions exceeds the maximum allowed space
    dimension.
  */
  explicit Grid(const Grid_Generator_System& const_gs);

  //! Builds a grid, recycling a system of generators.
  /*!
    The grid inherits the space dimension of the generator system.

    \param gs
    The system of generators defining the grid.  Its data-structures
    will be recycled to build the grid.

    \exception std::invalid_argument
    Thrown if the system of generators is not empty but has no points.

    \exception std::length_error
    Thrown if \p num_dimensions exceeds the maximum allowed space dimension.
  */
  explicit Grid(Grid_Generator_System& gs);

  //! Builds a grid out of a generic, interval-based bounding box.
  /*!
    \param box
    The bounding box representing the grid to be built.  The box can
    contain only point and universe intervals;

    \param dummy
    A dummy tag to make this constructor syntactically unique.

    \exception std::length_error
    Thrown if the space dimension of \p box exceeds the maximum
    allowed space dimension.

    \exception std::invalid_argument
    Thrown if \p box contains at least one interval with: a
    topologically open bound, a single bound, or two bounds which have
    space between them.

    The template class Box must provide the following methods.
    \code
      dimension_type space_dimension() const
    \endcode
    returns the dimension of the vector space enclosing the grid
    represented by the bounding box.
    \code
      bool is_empty() const
    \endcode
    returns <CODE>true</CODE> if and only if the bounding box
    describes the empty set.
    \code
      bool get_lower_bound(dimension_type k, bool closed,
                           Coefficient& n, Coefficient& d) const
    \endcode
    Let \f$I\f$ be the interval corresponding to the <CODE>k</CODE>-th
    space dimension.  If \f$I\f$ is not bounded from below, simply return
    <CODE>false</CODE>.  Otherwise, set <CODE>closed</CODE>,
    <CODE>n</CODE> and <CODE>d</CODE> as follows: <CODE>closed</CODE>
    is set to <CODE>true</CODE> if the lower boundary of \f$I\f$
    is closed and is set to <CODE>false</CODE> otherwise;
    <CODE>n</CODE> and <CODE>d</CODE> are assigned the integers
    \f$n\f$ and \f$d\f$ such that the canonical fraction \f$n/d\f$
    corresponds to the greatest lower bound of \f$I\f$.  The fraction
    \f$n/d\f$ is in canonical form if and only if \f$n\f$ and \f$d\f$
    have no common factors and \f$d\f$ is positive, \f$0/1\f$ being
    the unique representation for zero.
    \code
      bool get_upper_bound(dimension_type k, bool closed,
                           Coefficient& n, Coefficient& d) const
    \endcode
    Let \f$I\f$ be the interval corresponding to the <CODE>k</CODE>-th
    space dimension.  If \f$I\f$ is not bounded from above, simply return
    <CODE>false</CODE>.  Otherwise, set <CODE>closed</CODE>,
    <CODE>n</CODE> and <CODE>d</CODE> as follows: <CODE>closed</CODE>
    is set to <CODE>true</CODE> if the upper boundary of \f$I\f$
    is closed and is set to <CODE>false</CODE> otherwise;
    <CODE>n</CODE> and <CODE>d</CODE> are assigned the integers
    \f$n\f$ and \f$d\f$ such that the canonical fraction \f$n/d\f$
    corresponds to the least upper bound of \f$I\f$.
  */
  template <typename Box>
  Grid(const Box& box, From_Bounding_Box dummy);

  //! Builds a grid out of a generic, interval-based covering box.
  /*!
    The covering box is a set of upper and lower values for each
    dimension.  When a covering box is tiled onto empty space the
    corners of the tiles form a rectilinear grid.

    A box interval with only one bound fixes the values of all grid
    points in the dimension associated with the box to the value of
    the bound.  A box interval which has upper and lower bounds of
    equal value allows all grid points with any value in the dimension
    associated with the interval.  The presence of a universe interval
    results in the empty grid.  The empty box produces the empty grid
    of the same dimension as the box.

    \param box
    The covering box representing the grid to be built;

    \param dummy
    A dummy tag to make this constructor syntactically unique.

    \exception std::length_error
    Thrown if the space dimension of \p box exceeds the maximum
    allowed space dimension.

    \exception std::invalid_argument
    Thrown if \p box contains any topologically open bounds.

    The template class Box must provide the following methods.
    \code
      dimension_type space_dimension() const
    \endcode
    returns the dimension of the vector space enclosing the grid
    represented by the covering box.
    \code
      bool is_empty() const
    \endcode
    returns <CODE>true</CODE> if and only if the covering box
    describes the empty set.
    \code
      bool get_lower_bound(dimension_type k, bool closed,
                           Coefficient& n, Coefficient& d) const
    \endcode
    Let \f$I\f$ be the interval corresponding to the <CODE>k</CODE>-th
    space dimension.  If \f$I\f$ is not bounded from below, simply return
    <CODE>false</CODE>.  Otherwise, set <CODE>closed</CODE>,
    <CODE>n</CODE> and <CODE>d</CODE> as follows: <CODE>closed</CODE>
    is set to <CODE>true</CODE> if the lower boundary of \f$I\f$
    is closed and is set to <CODE>false</CODE> otherwise;
    <CODE>n</CODE> and <CODE>d</CODE> are assigned the integers
    \f$n\f$ and \f$d\f$ such that the canonical fraction \f$n/d\f$
    corresponds to the greatest lower bound of \f$I\f$.  The fraction
    \f$n/d\f$ is in canonical form if and only if \f$n\f$ and \f$d\f$
    have no common factors and \f$d\f$ is positive, \f$0/1\f$ being
    the unique representation for zero.
    \code
      bool get_upper_bound(dimension_type k, bool closed,
                           Coefficient& n, Coefficient& d) const
    \endcode
    Let \f$I\f$ be the interval corresponding to the <CODE>k</CODE>-th
    space dimension.  If \f$I\f$ is not bounded from above, simply return
    <CODE>false</CODE>.  Otherwise, set <CODE>closed</CODE>,
    <CODE>n</CODE> and <CODE>d</CODE> as follows: <CODE>closed</CODE>
    is set to <CODE>true</CODE> if the upper boundary of \f$I\f$
    is closed and is set to <CODE>false</CODE> otherwise;
    <CODE>n</CODE> and <CODE>d</CODE> are assigned the integers
    \f$n\f$ and \f$d\f$ such that the canonical fraction \f$n/d\f$
    corresponds to the least upper bound of \f$I\f$.
  */
  template <typename Box>
  Grid(const Box& box, From_Covering_Box dummy);

  //! Ordinary copy-constructor.
  Grid(const Grid& y);

  /*! \brief
    The assignment operator.  (\p *this and \p y can be
    dimension-incompatible.)
  */
  Grid& operator=(const Grid& y);

  //! \name Member Functions that Do Not Modify the Grid
  //@{

  //! Returns the dimension of the vector space enclosing \p *this.
  dimension_type space_dimension() const;

  /*! \brief
    Returns \f$0\f$, if \p *this is empty; otherwise, returns
    the \ref Grid_Affine_Dimension "affine dimension" of \p *this.
  */
  dimension_type affine_dimension() const;

  //! Returns the system of congruences.
  const Congruence_System& congruences() const;

  //! Returns the system of congruences in reduced form.
  const Congruence_System& minimized_congruences() const;

  //! Returns the system of generators.
  const Grid_Generator_System& generators() const;

  //! Returns the minimized system of generators.
  const Grid_Generator_System& minimized_generators() const;

  //! Returns the relations holding between \p *this and \p cg.
  /*
    \exception std::invalid_argument
    Thrown if \p *this and congruence \p cg are dimension-incompatible.
  */
  // FIXME: Poly_Con_Relation seems to encode exactly what we want
  // here.  We must find a new name for that class.  Temporarily,
  // we keep using it without changing the name.
  Poly_Con_Relation relation_with(const Congruence& cg) const;

  //! Returns the relations holding between \p *this and \p g.
  /*
    \exception std::invalid_argument
    Thrown if \p *this and generator \p g are dimension-incompatible.
  */
  // FIXME: see the comment for Poly_Con_Relation above.
  Poly_Gen_Relation
  relation_with(const Grid_Generator& g) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is an empty
    grid.
  */
  bool is_empty() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is a universe
    grid.
  */
  bool is_universe() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is a
    topologically closed subset of the vector space.
  */
  bool is_topologically_closed() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this and \p y are
    disjoint.

    \exception std::invalid_argument
    Thrown if \p x and \p y are dimension-incompatible.
  */
  bool is_disjoint_from(const Grid& y) const;

  //! Returns <CODE>true</CODE> if and only if \p *this is discrete.
  /*!
    A grid is discrete if it can be defined by a generator system which
    contains only points and parameters.  This includes the empty grid
    and any grid in dimension zero.
  */
  bool is_discrete() const;

  //! Returns <CODE>true</CODE> if and only if \p *this is bounded.
  bool is_bounded() const;

  //! Returns <CODE>true</CODE> if and only if \p expr is bounded in \p *this.
  /*!
    This method is the same as bounds_from_below.

    \exception std::invalid_argument
    Thrown if \p expr and \p *this are dimension-incompatible.
  */
  bool bounds_from_above(const Linear_Expression& expr) const;

  //! Returns <CODE>true</CODE> if and only if \p expr is bounded in \p *this.
  /*!
    This method is the same as bounds_from_above.

    \exception std::invalid_argument
    Thrown if \p expr and \p *this are dimension-incompatible.
  */
  bool bounds_from_below(const Linear_Expression& expr) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is not empty and
    \p expr is bounded from above in \p *this, in which case the
    supremum value is computed.

    \param expr
    The linear expression to be maximized subject to \p *this;

    \param sup_n
    The numerator of the supremum value;

    \param sup_d
    The denominator of the supremum value;

    \param maximum
    <CODE>true</CODE> if the supremum value can be reached in \p this.
    Always <CODE>true</CODE> when \p this bounds \p expr.  Present for
    interface compatibility with class Polyhedron, where closure
    points can result in a value of false.

    \exception std::invalid_argument
    Thrown if \p expr and \p *this are dimension-incompatible.

    If \p *this is empty or \p expr is not bounded by \p *this,
    <CODE>false</CODE> is returned and \p sup_n, \p sup_d and \p
    maximum are left untouched.
  */
  bool maximize(const Linear_Expression& expr,
		Coefficient& sup_n, Coefficient& sup_d, bool& maximum) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is not empty and
    \p expr is bounded from above in \p *this, in which case the
    supremum value and a point where \p expr reaches it are computed.

    \param expr
    The linear expression to be maximized subject to \p *this;

    \param sup_n
    The numerator of the supremum value;

    \param sup_d
    The denominator of the supremum value;

    \param maximum
    <CODE>true</CODE> if the supremum value can be reached in \p this.
    Always <CODE>true</CODE> when \p this bounds \p expr.  Present for
    interface compatibility with class Polyhedron, where closure
    points can result in a value of false;

    \param point
    When maximization succeeds, will be assigned a point where \p expr
    reaches its supremum value.

    \exception std::invalid_argument
    Thrown if \p expr and \p *this are dimension-incompatible.

    If \p *this is empty or \p expr is not bounded by \p *this,
    <CODE>false</CODE> is returned and \p sup_n, \p sup_d, \p maximum
    and \p point are left untouched.
  */
  bool maximize(const Linear_Expression& expr,
		Coefficient& sup_n, Coefficient& sup_d, bool& maximum,
		Grid_Generator& point) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is not empty and
    \p expr is bounded from below in \p *this, in which case the
    infimum value is computed.

    \param expr
    The linear expression to be minimized subject to \p *this;

    \param inf_n
    The numerator of the infimum value;

    \param inf_d
    The denominator of the infimum value;

    \param minimum
    <CODE>true</CODE> if the is the infimum value can be reached in \p
    this.  Always <CODE>true</CODE> when \p this bounds \p expr.
    Present for interface compatibility with class Polyhedron, where
    closure points can result in a value of false.

    \exception std::invalid_argument
    Thrown if \p expr and \p *this are dimension-incompatible.

    If \p *this is empty or \p expr is not bounded from below,
    <CODE>false</CODE> is returned and \p inf_n, \p inf_d
    and \p minimum are left untouched.
  */
  bool minimize(const Linear_Expression& expr,
		Coefficient& inf_n, Coefficient& inf_d, bool& minimum) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is not empty and
    \p expr is bounded from below in \p *this, in which case the
    infimum value and a point where \p expr reaches it are computed.

    \param expr
    The linear expression to be minimized subject to \p *this;

    \param inf_n
    The numerator of the infimum value;

    \param inf_d
    The denominator of the infimum value;

    \param minimum
    <CODE>true</CODE> if the is the infimum value can be reached in \p
    this.  Always <CODE>true</CODE> when \p this bounds \p expr.
    Present for interface compatibility with class Polyhedron, where
    closure points can result in a value of false;

    \param point
    When minimization succeeds, will be assigned a point where \p expr
    reaches its infimum value.

    \exception std::invalid_argument
    Thrown if \p expr and \p *this are dimension-incompatible.

    If \p *this is empty or \p expr is not bounded from below,
    <CODE>false</CODE> is returned and \p inf_n, \p inf_d, \p minimum
    and \p point are left untouched.
  */
  bool minimize(const Linear_Expression& expr,
		Coefficient& inf_n, Coefficient& inf_d, bool& minimum,
		Grid_Generator& point) const;

  //! Returns <CODE>true</CODE> if and only if \p *this contains \p y.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  bool contains(const Grid& y) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this strictly
    contains \p y.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  bool strictly_contains(const Grid& y) const;

  //! Uses \p *this to shrink a generic, interval-based bounding box.
  /*!
    \param box
    The bounding box to be shrunk.

    \exception std::invalid_argument
    Thrown if \p *this and \p box are dimension-incompatible, or if \p
    box contains any topologically open bounds.

    The template class Box must provide the following methods
    \code
      dimension_type space_dimension() const
    \endcode
    returns the dimension of the vector space enclosing the grid
    represented by the bounding box.
    \code
      bool get_lower_bound(dimension_type k, bool closed,
                           Coefficient& n, Coefficient& d) const
    \endcode
    Let \f$I\f$ be the interval corresponding to the <CODE>k</CODE>-th
    space dimension.  If \f$I\f$ is not bounded from below, simply return
    <CODE>false</CODE>.  Otherwise, set <CODE>closed</CODE>,
    <CODE>n</CODE> and <CODE>d</CODE> as follows: <CODE>closed</CODE>
    is set to <CODE>true</CODE> if the lower boundary of \f$I\f$
    is closed and is set to <CODE>false</CODE> otherwise;
    <CODE>n</CODE> and <CODE>d</CODE> are assigned the integers
    \f$n\f$ and \f$d\f$ such that the canonical fraction \f$n/d\f$
    corresponds to the greatest lower bound of \f$I\f$.  The fraction
    \f$n/d\f$ is in canonical form if and only if \f$n\f$ and \f$d\f$
    have no common factors and \f$d\f$ is positive, \f$0/1\f$ being
    the unique representation for zero.
    \code
      bool get_upper_bound(dimension_type k, bool closed,
                           Coefficient& n, Coefficient& d) const
    \endcode
    Let \f$I\f$ be the interval corresponding to the <CODE>k</CODE>-th
    space dimension.  If \f$I\f$ is not bounded from above, simply return
    <CODE>false</CODE>.  Otherwise, set <CODE>closed</CODE>,
    <CODE>n</CODE> and <CODE>d</CODE> as follows: <CODE>closed</CODE>
    is set to <CODE>true</CODE> if the upper boundary of \f$I\f$
    is closed and is set to <CODE>false</CODE> otherwise;
    <CODE>n</CODE> and <CODE>d</CODE> are assigned the integers
    \f$n\f$ and \f$d\f$ such that the canonical fraction \f$n/d\f$
    corresponds to the least upper bound of \f$I\f$.
    \code
      set_empty()
    \endcode
    Causes the box to become empty, i.e., to represent the empty set.
    \code
      raise_lower_bound(dimension_type k, bool closed,
                        Coefficient_traits::const_reference n,
                        Coefficient_traits::const_reference d)
    \endcode
    intersects the interval corresponding to the <CODE>k</CODE>-th
    space dimension with \f$[n/d, +\infty)\f$.  <CODE>closed</CODE> is
    always passed as <CODE>true</CODE>.
    \code
      lower_upper_bound(dimension_type k, bool closed,
                        Coefficient_traits::const_reference n,
                        Coefficient_traits::const_reference d)
    \endcode
    intersects the interval corresponding to the <CODE>k</CODE>-th
    space dimension with \f$(-\infty, n/d]\f$.  <CODE>closed</CODE> is
    always passed as <CODE>true</CODE>.

    The function <CODE>raise_lower_bound(k, closed, n, d)</CODE>
    will be called at most once for each possible value for <CODE>k</CODE>
    and for all such calls the fraction \f$n/d\f$ will be in canonical form,
    that is, \f$n\f$ and \f$d\f$ have no common factors and \f$d\f$
    is positive, \f$0/1\f$ being the unique representation for zero.
    The same guarantee is offered for the function
    <CODE>lower_upper_bound(k, closed, n, d)</CODE>.
  */
  template <typename Box>
  void shrink_bounding_box(Box& box) const;

  //! Writes the covering box for \p *this into \p box.
  /*!
    The covering box is a set of upper and lower values for each
    dimension.  When the covering box written into \p box is tiled
    onto empty space the corners of the tiles form the sparsest
    rectilinear grid that includes \p *this.

    The value of the lower bound of each interval of the resulting \p
    box are as close as possible to the origin, with positive values
    taking preference when the lowest positive value equals the lowest
    negative value.

    If all the points have a single value in a particular dimension of
    the grid then there is only a lower bound on the interval produced
    in \p box, and the lower bound denotes the single value for the
    dimension.  If the coordinates of the points in a particular
    dimension include every value then the upper and lower bounds of
    the associated interval in \p box are set equal.  The empty grid
    produces the empty \p box.  The zero dimension universe grid
    produces the zero dimension universe box.

    \param box
    The Box into which the covering box is written.

    \exception std::invalid_argument
    Thrown if \p *this and \p box are dimension-incompatible.

    The template class Box must provide the following methods
    \code
      Box(dimension_type space_dimension)
    \endcode
    Creates a universe box of space_dimension dimensions.
    \code
      dimension_type space_dimension() const
    \endcode
    returns the dimension of the vector space enclosing the grid
    represented by the covering box.
    \code
      set_empty()
    \endcode
    Causes the box to become empty, i.e., to represent the empty set.
    \code
      raise_lower_bound(dimension_type k, bool closed,
                        Coefficient_traits::const_reference n,
                        Coefficient_traits::const_reference d)
    \endcode
    intersects the interval corresponding to the <CODE>k</CODE>-th
    space dimension with \f$[n/d, +\infty)\f$.  <CODE>closed</CODE> is
    always passed as <CODE>true</CODE>.
    \code
      lower_upper_bound(dimension_type k, bool closed,
                        Coefficient_traits::const_reference n,
                        Coefficient_traits::const_reference d)
    \endcode
    intersects the interval corresponding to the <CODE>k</CODE>-th
    space dimension with \f$(-\infty, n/d]\f$.  <CODE>closed</CODE> is
    always passed as <CODE>true</CODE>.

    The function <CODE>raise_lower_bound(k, closed, n, d)</CODE>
    will be called at most once for each possible value for <CODE>k</CODE>
    and for all such calls the fraction \f$n/d\f$ will be in canonical form,
    that is, \f$n\f$ and \f$d\f$ have no common factors and \f$d\f$
    is positive, \f$0/1\f$ being the unique representation for zero.
    The same guarantee is offered for the function
    <CODE>lower_upper_bound(k, closed, n, d)</CODE>.
  */
  template <typename Box>
  void get_covering_box(Box& box) const;

  //! Checks if all the invariants are satisfied.
  /*!
    \return
    <CODE>true</CODE> if and only if \p *this satisfies all the
    invariants and either \p check_not_empty is <CODE>false</CODE> or
    \p *this is not empty.

    \param check_not_empty
    <CODE>true</CODE> if and only if, in addition to checking the
    invariants, \p *this must be checked to be not empty.

    The check is performed so as to intrude as little as possible.  If
    the library has been compiled with run-time assertions enabled,
    error messages are written on <CODE>std::cerr</CODE> in case
    invariants are violated. This is useful for the purpose of
    debugging the library.
  */
  bool OK(bool check_not_empty = false) const;

  //@} // Member Functions that Do Not Modify the Grid

  //! \name Space Dimension Preserving Member Functions that May Modify the Grid
  //@{

  //! Adds a copy of congruence \p cg to \p *this.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this and congruence \p cg are
    dimension-incompatible.
  */
  void add_congruence(const Congruence& cg);

  //! Adds constraint \p c to \p *this.
  /*!
    The addition can only affect \p *this if \p c is an equality.

    \exception std::invalid_argument
    Thrown if \p *this and constraint \p c are dimension-incompatible.
  */
  void add_congruence(const Constraint& c);

  /*! \brief
    Adds a copy of congruence \p cg to the system of congruences of \p
    *this, reducing the result

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \exception std::invalid_argument
    Thrown if \p *this and congruence \p cg are dimension-incompatible.
  */
  bool add_congruence_and_minimize(const Congruence& c);

  //! Adds a copy of constraint \p c to \p *this, reducing the result.
  /*!
    The addition can only affect \p *this if \p c is an equality.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \exception std::invalid_argument
    Thrown if \p *this and constraint \p c are dimension-incompatible.
  */
  bool add_congruence_and_minimize(const Constraint& c);

  /*! \brief
    Adds a copy of generator \p g to the system of generators of \p
    *this.

    \exception std::invalid_argument
    Thrown if \p *this and generator \p g are dimension-incompatible,
    or if \p *this is an empty grid and \p g is not a point.
  */
  void add_generator(const Grid_Generator& g);

  /*! \brief
    Adds a copy of generator \p g to the system of generators of \p
    *this, reducing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \exception std::invalid_argument
    Thrown if \p *this and generator \p g are dimension-incompatible,
    or if \p *this is an empty grid and \p g is not a point.
  */
  bool add_generator_and_minimize(const Grid_Generator& g);

  //! Adds a copy of each congruence in \p cgs to \p *this.
  /*!
    \param cgs
    Contains the congruences that will be added to the system of
    congruences of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible.
  */
  void add_congruences(const Congruence_System& cgs);

  //! Adds a copy of each equality constraint in \p cs to \p *this.
  /*!
    \param cs
    The congruences that will be considered for addition to the system
    of congruences of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible.
  */
  void add_congruences(const Constraint_System& cs);

  //! Adds the congruences in \p cgs to *this.
  /*!
    \param cgs
    The congruence system that will be recycled, adding its
    congruences to the system of congruences of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible.

    \warning
    The only assumption that can be made about \p cgs upon successful
    or exceptional return is that it can be safely destroyed.
  */
  void add_recycled_congruences(Congruence_System& cgs);

  //! Adds the equality constraints in \p cs to \p *this.
  /*!
    \param cs
    The constraint system from which constraints will be considered
    for addition to the system of congruences of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible.

    \warning

    The only assumption that can be made about \p cs upon successful
    or exceptional return is that it can be safely destroyed.
  */
  void add_recycled_congruences(Constraint_System& cs);

  /*! \brief
    Adds a copy of the congruences in \p cgs to the system of
    congruences of \p *this, reducing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \param cgs
    Contains the congruences that will be added to the system of
    congruences of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible.
  */
  bool add_congruences_and_minimize(const Congruence_System& cgs);

  /*! \brief
    Adds a copy of each equality constraint in \p cs to \p *this,
    reducing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \param cs
    Contains the constraints that will be added to the system of
    congruences of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible.
  */
  bool add_congruences_and_minimize(const Constraint_System& cs);

  /*! \brief
    Adds the congruences in \p cgs to the system of congruences of \p
    *this, reducing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \param cgs
    The congruence system that will be recycled, adding its
    congruences to the system of congruences of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p cgs are dimension-incompatible.

    \warning
    The only assumption that can be made about \p cgs upon successful
    or exceptional return is that it can be safely destroyed.
  */
  bool add_recycled_congruences_and_minimize(Congruence_System& cgs);

  //! Adds the equalities in \p cs to \p *this, reducing the result.
  /*!
    \return
    <CODE>false</CODE> if and only if the result is empty.

    \param cs
    The constraint system that will be recycled, adding its
    equalities to the system of congruences of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible.

    \warning
    The only assumption that can be made about \p cs upon successful
    or exceptional return is that it can be safely destroyed.
  */
  bool add_recycled_congruences_and_minimize(Constraint_System& cs);

  //! Adds constraint \p c to \p *this.
  /*!
    The addition can only affect \p *this if \p c is an equality.

    \exception std::invalid_argument
    Thrown if \p *this and \p c are dimension-incompatible.
  */
  void add_constraint(const Constraint& c);

  //! Adds constraint \p c to \p *this, reducing the result.
  /*!
    The addition can only affect \p *this if \p c is an equality.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \exception std::invalid_argument
    Thrown if \p *this and \p c are dimension-incompatible.
  */
  bool add_constraint_and_minimize(const Constraint& c);

  //! Adds copies of the equality constraints in \p cs to \p *this.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible.
  */
  void add_constraints(const Constraint_System& cs);

  /*! \brief
    Adds copies of the equality constraints in \p cs to \p *this,
    reducing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible.
  */
  bool add_constraints_and_minimize(const Constraint_System& cs);

  //! Adds the equality constraints in \p cs to \p *this.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible.

    \warning
    The only assumption that can be made about \p cs upon successful
    or exceptional return is that it can be safely destroyed.
  */
  void add_recycled_constraints(Constraint_System& cs);

  /*! \brief

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible.

    \warning
    The only assumption that can be made about \p cs upon successful
    or exceptional return is that it can be safely destroyed.
  */
  bool add_recycled_constraints_and_minimize(Constraint_System& cs);

  /*! \brief
    Adds a copy of the generators in \p gs to the system of generators
    of \p *this.

    \param gs
    Contains the generators that will be added to the system of
    generators of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p gs are dimension-incompatible, or if
    \p *this is empty and the system of generators \p gs is not empty,
    but has no points.
  */
  void add_generators(const Grid_Generator_System& gs);

  /*! \brief
    Adds the generators in \p gs to the system of generators of \p
    *this.

    \param gs
    The generator system that will be recycled, adding its generators
    to the system of generators of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p gs are dimension-incompatible, or if
    \p *this is empty and the system of generators \p gs is not empty,
    but has no points.

    \warning
    The only assumption that can be made about \p gs upon successful
    or exceptional return is that it can be safely destroyed.
  */
  void add_recycled_generators(Grid_Generator_System& gs);

  /*! \brief
    Adds a copy of the generators in \p gs to the system of generators
    of \p *this, reducing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \param gs
    Contains the generators that will be added to the system of
    generators of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p gs are dimension-incompatible, or if \p
    *this is empty and the system of generators \p gs is not empty,
    but has no points.
  */
  bool add_generators_and_minimize(const Grid_Generator_System& gs);

  /*! \brief
    Adds the generators in \p gs to the system of generators of \p
    *this, reducing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \param gs
    The generator system that will be recycled, adding its generators
    to the system of generators of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p gs are dimension-incompatible, or if \p
    *this is empty and the system of generators \p gs is not empty,
    but has no points.

    \warning
    The only assumption that can be made about \p gs upon successful
    or exceptional return is that it can be safely destroyed.
  */
  bool add_recycled_generators_and_minimize(Grid_Generator_System& gs);

  /*! \brief
    Assigns to \p *this the intersection of \p *this and \p y.  The
    result is not guaranteed to be reduced.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void intersection_assign(const Grid& y);

  /*! \brief
    Assigns to \p *this the intersection of \p *this and \p y,
    reducing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  bool intersection_assign_and_minimize(const Grid& y);

  /*! \brief
    Assigns to \p *this the join of \p *this and \p y.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void join_assign(const Grid& y);

  /*! \brief
    Assigns to \p *this the join of \p *this and \p y, reducing the
    result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  bool join_assign_and_minimize(const Grid& y);

  //! Same as join_assign(y).
  void upper_bound_assign(const Grid& y);

  /*! \brief
    If the join of \p *this and \p y is exact it is assigned to \p
    *this and <CODE>true</CODE> is returned, otherwise
    <CODE>false</CODE> is returned.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  bool join_assign_if_exact(const Grid& y);

  //! Same as join_assign_if_exact(y).
  bool upper_bound_assign_if_exact(const Grid& y);

  /*! \brief
    Assigns to \p *this the \ref Grid_Difference "grid-difference" of
    \p *this and \p y.

    The grid difference between grids x and y is the smallest grid
    containing all the points from x and y that are only in x.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void grid_difference_assign(const Grid& y);

  //! Same as grid_difference_assign(y).
  void difference_assign(const Grid& y);

  /*! \brief
    Assigns to \p *this the \ref Grid_Affine_Transformation
    "affine image" of \p
    *this under the function mapping variable \p var to the affine
    expression specified by \p expr and \p denominator.

    \param var
    The variable to which the affine expression is assigned;

    \param expr
    The numerator of the affine expression;

    \param denominator
    The denominator of the affine expression (optional argument with
    default value 1).

    \exception std::invalid_argument
    Thrown if \p denominator is zero or if \p expr and \p *this are
    dimension-incompatible or if \p var is not a space dimension of
    \p *this.

    \if Include_Implementation_Details

    When considering the generators of a grid, the
    affine transformation
    \f[
      \frac{\sum_{i=0}^{n-1} a_i x_i + b}{\mathrm{denominator}}
    \f]
    is assigned to \p var where \p expr is
    \f$\sum_{i=0}^{n-1} a_i x_i + b\f$
    (\f$b\f$ is the inhomogeneous term).

    If congruences are up-to-date, it uses the specialized function
    affine_preimage() (for the system of congruences)
    and inverse transformation to reach the same result.
    To obtain the inverse transformation we use the following observation.

    Observation:
    -# The affine transformation is invertible if the coefficient
       of \p var in this transformation (i.e., \f$a_\mathrm{var}\f$)
       is different from zero.
    -# If the transformation is invertible, then we can write
       \f[
  	 \mathrm{denominator} * {x'}_\mathrm{var}
	   = \sum_{i = 0}^{n - 1} a_i x_i + b
	   = a_\mathrm{var} x_\mathrm{var}
	     + \sum_{i \neq var} a_i x_i + b,
       \f]
       so that the inverse transformation is
       \f[
	 a_\mathrm{var} x_\mathrm{var}
           = \mathrm{denominator} * {x'}_\mathrm{var}
             - \sum_{i \neq j} a_i x_i - b.
       \f]

    Then, if the transformation is invertible, all the entities that
    were up-to-date remain up-to-date. Otherwise only generators remain
    up-to-date.

    \endif
  */
  void affine_image(Variable var,
		    const Linear_Expression& expr,
		    Coefficient_traits::const_reference denominator
		    = Coefficient_one());

  /*! \brief
    Assigns to \p *this the \ref Grid_Affine_Transformation
    "affine preimage" of
    \p *this under the function mapping variable \p var to the affine
    expression specified by \p expr and \p denominator.

    \param var
    The variable to which the affine expression is substituted;

    \param expr
    The numerator of the affine expression;

    \param denominator
    The denominator of the affine expression (optional argument with
    default value 1).

    \exception std::invalid_argument
    Thrown if \p denominator is zero or if \p expr and \p *this are
    dimension-incompatible or if \p var is not a space dimension of \p *this.

    \if Include_Implementation_Details

    When considering congruences of a grid, the affine transformation
    \f[
      \frac{\sum_{i=0}^{n-1} a_i x_i + b}{denominator},
    \f]
    is assigned to \p var where \p expr is
    \f$\sum_{i=0}^{n-1} a_i x_i + b\f$
    (\f$b\f$ is the inhomogeneous term).

    If generators are up-to-date, then the specialized function
    affine_image() is used (for the system of generators)
    and inverse transformation to reach the same result.
    To obtain the inverse transformation, we use the following observation.

    Observation:
    -# The affine transformation is invertible if the coefficient
       of \p var in this transformation (i.e. \f$a_\mathrm{var}\f$)
       is different from zero.
    -# If the transformation is invertible, then we can write
       \f[
  	 \mathrm{denominator} * {x'}_\mathrm{var}
	   = \sum_{i = 0}^{n - 1} a_i x_i + b
           = a_\mathrm{var} x_\mathrm{var}
               + \sum_{i \neq \mathrm{var}} a_i x_i + b,
       \f],
       the inverse transformation is
       \f[
	 a_\mathrm{var} x_\mathrm{var}
           = \mathrm{denominator} * {x'}_\mathrm{var}
               - \sum_{i \neq j} a_i x_i - b.
       \f].

    Then, if the transformation is invertible, all the entities that
    were up-to-date remain up-to-date. Otherwise only congruences remain
    up-to-date.

    \endif
  */
  void affine_preimage(Variable var,
		       const Linear_Expression& expr,
		       Coefficient_traits::const_reference denominator
		         = Coefficient_one());

  /*! \brief
    Assigns to \p *this the image of \p *this with respect to
    the \ref Grid_Generalized_Image "generalized affine relation"
    \f$\mathrm{var}' = \frac{\mathrm{expr}}{\mathrm{denominator}}
    \pmod{\mathrm{modulus}}\f$.

    \param var
    The left hand side variable of the generalized affine relation;

    \param expr
    The numerator of the right hand side affine expression;

    \param denominator
    The denominator of the right hand side affine expression.
    Optional argument with an automatic value of one;

    \param modulus
    The modulus of the congruence lhs %= rhs.  A modulus of zero
    indicates lhs == rhs.  Optional argument with an automatic value
    of one.

    \exception std::invalid_argument
    Thrown if \p denominator is zero or if \p expr and \p *this are
    dimension-incompatible or if \p var is not a space dimension of \p
    *this.
  */
  void generalized_affine_image(Variable var,
				const Linear_Expression& expr,
				Coefficient_traits::const_reference denominator
				= Coefficient_one(),
				Coefficient_traits::const_reference modulus
				= Coefficient_one());

  /*! \brief
    Assigns to \p *this the preimage of \p *this with respect to the
    \ref Grid_Generalized_Image "generalized affine relation"
    \f$\mathrm{var}' = \frac{\mathrm{expr}}{\mathrm{denominator}}
    \pmod{\mathrm{modulus}}\f$.

    \param var
    The left hand side variable of the generalized affine relation;

    \param expr
    The numerator of the right hand side affine expression;

    \param denominator
    The denominator of the right hand side affine expression.
    Optional argument with an automatic value of one;

    \param modulus
    The modulus of the congruence lhs %= rhs.  A modulus of zero
    indicates lhs == rhs.  Optional argument with an automatic value
    of one.

    \exception std::invalid_argument
    Thrown if \p denominator is zero or if \p expr and \p *this are
    dimension-incompatible or if \p var is not a space dimension of \p
    *this.
  */
  void generalized_affine_preimage(Variable var,
				   const Linear_Expression& expr,
				   Coefficient_traits::const_reference denominator
				   = Coefficient_one(),
				   Coefficient_traits::const_reference modulus
				   = Coefficient_one());

  /*! \brief
    Assigns to \p *this the image of \p *this with respect to
    the \ref Grid_Generalized_Image "generalized affine relation"
    \f$\mathrm{lhs}' = \mathrm{rhs} \pmod{\mathrm{modulus}}\f$.

    \param lhs
    The left hand side affine expression.

    \param rhs
    The right hand side affine expression.

    \param modulus
    The modulus of the congruence lhs %= rhs.  A modulus of zero
    indicates lhs == rhs.  Optional argument with an automatic value
    of one.

    \exception std::invalid_argument
    Thrown if \p *this is dimension-incompatible with \p lhs or \p
    rhs.
  */
  void generalized_affine_image(const Linear_Expression& lhs,
				const Linear_Expression& rhs,
				Coefficient_traits::const_reference modulus
				= Coefficient_one());

  /*! \brief
    Assigns to \p *this the preimage of \p *this with respect to the
    \ref Grid_Generalized_Image "generalized affine relation"
    \f$\mathrm{lhs}' = \mathrm{rhs} \pmod{\mathrm{modulus}}\f$.

    \param lhs
    The left hand side affine expression;

    \param rhs
    The right hand side affine expression;

    \param modulus
    The modulus of the congruence lhs %= rhs.  A modulus of zero
    indicates lhs == rhs.  Optional argument with an automatic value
    of one.

    \exception std::invalid_argument
    Thrown if \p *this is dimension-incompatible with \p lhs or \p
    rhs.
  */
  void generalized_affine_preimage(const Linear_Expression& lhs,
				   const Linear_Expression& rhs,
				   Coefficient_traits::const_reference modulus
				   = Coefficient_one());

  /*! \brief
    Assigns to \p *this the result of computing the \ref Grid_Time_Elapse
    "time-elapse" between \p *this and \p y.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void time_elapse_assign(const Grid& y);

  //! Assigns to \p *this its topological closure.
  void topological_closure_assign();

  /*! \brief
    Assigns to \p *this the result of computing the \ref Grid_Widening
    "Grid widening" between \p *this and \p y.

    \param y
    A grid that <EM>must</EM> be contained in \p *this;

    \param tp
    An optional pointer to an unsigned variable storing the number of
    available tokens (to be used when applying the
    \ref Grid_Widening_with_Tokens "widening with tokens" delay technique).

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void widening_assign(const Grid& y, unsigned* tp = NULL);

  /*! \brief
    Improves the result of the \ref Grid_Widening "Grid widening"
    computation by also enforcing those congruences in \p cgs that are
    satisfied by all the points of \p *this.

    \param y
    A grid that <EM>must</EM> be contained in \p *this;

    \param cgs
    The system of congruences used to improve the widened grid;

    \param tp
    An optional pointer to an unsigned variable storing the number of
    available tokens (to be used when applying the
    \ref Grid_Widening_with_Tokens "widening with tokens" delay technique).

    \exception std::invalid_argument
    Thrown if \p *this, \p y and \p cs are dimension-incompatible.
  */
  void limited_extrapolation_assign(const Grid& y,
				    const Congruence_System& cgs,
				    unsigned* tp = NULL);

  //@} // Space Dimension Preserving Member Functions that May Modify [...]

  //! \name Member Functions that May Modify the Dimension of the Vector Space
  //@{

  /*! \brief
    Adds \p m new space dimensions and embeds the old grid in the new
    vector space.

    \param m
    The number of dimensions to add.

    \exception std::length_error
    Thrown if adding \p m new space dimensions would cause the vector
    space to exceed dimension <CODE>max_space_dimension()</CODE>.

    The new space dimensions will be those having the highest indexes
    in the new grid, which is characterized by a system of congruences
    in which the variables which are the new dimensions can have any
    value.  For instance, when starting from the grid \f$\cL \sseq
    \Rset^2\f$ and adding a third space dimension, the result will be
    the grid
    \f[
      \bigl\{\,
        (x, y, z)^\transpose \in \Rset^3
      \bigm|
        (x, y)^\transpose \in \cL
      \,\bigr\}.
    \f]
  */
  void add_space_dimensions_and_embed(dimension_type m);

  /*! \brief
    Adds \p m new space dimensions to the grid and does not embed it
    in the new vector space.

    \param m
    The number of space dimensions to add.

    \exception std::length_error
    Thrown if adding \p m new space dimensions would cause the
    vector space to exceed dimension <CODE>max_space_dimension()</CODE>.

    The new space dimensions will be those having the highest indexes
    in the new grid, which is characterized by a system of congruences
    in which the variables running through the new dimensions are all
    constrained to be equal to 0.  For instance, when starting from
    the grid \f$\cL \sseq \Rset^2\f$ and adding a third space
    dimension, the result will be the grid
    \f[
      \bigl\{\,
        (x, y, 0)^\transpose \in \Rset^3
      \bigm|
        (x, y)^\transpose \in \cL
      \,\bigr\}.
    \f]
  */
  void add_space_dimensions_and_project(dimension_type m);

  /*! \brief
    Assigns to \p *this the \ref Grid_Concatenate "concatenation" of
    \p *this and \p y, taken in this order.

    \exception std::length_error
    Thrown if the concatenation would cause the vector space
    to exceed dimension <CODE>max_space_dimension()</CODE>.
  */
  void concatenate_assign(const Grid& y);

  //! Removes all the specified dimensions from the vector space.
  /*!
    \param to_be_removed
    The set of Variable objects corresponding to the space dimensions
    to be removed.

    \exception std::invalid_argument
    Thrown if \p *this is dimension-incompatible with one of the
    Variable objects contained in \p to_be_removed.
  */
  void remove_space_dimensions(const Variables_Set& to_be_removed);

  /*! \brief
    Removes the higher dimensions of the vector space so that the
    resulting space will have dimension \p new_dimension.

    \exception std::invalid_argument
    Thrown if \p new_dimensions is greater than the space dimension of
    \p *this.
  */
  void remove_higher_space_dimensions(dimension_type new_dimension);

  /*! \brief
    Remaps the dimensions of the vector space according to
    a \ref Grid_Map_Space_Dimensions "partial function".

    If \p pfunc maps only some of the dimensions of \p *this then the
    rest will be projected away.

    If the highest dimension mapped to by \p pfunc is higher than the
    highest dimension in \p *this then the number of dimensions in \p
    *this will be increased to the highest dimension mapped to by \p
    pfunc.

    \param pfunc
    The partial function specifying the destiny of each space
    dimension.

    The template class Partial_Function must provide the following
    methods.
    \code
      bool has_empty_codomain() const
    \endcode
    returns <CODE>true</CODE> if and only if the represented partial
    function has an empty codomain (i.e., it is always undefined).
    The <CODE>has_empty_codomain()</CODE> method will always be called
    before the methods below.  However, if
    <CODE>has_empty_codomain()</CODE> returns <CODE>true</CODE>, none
    of the functions below will be called.
    \code
      dimension_type max_in_codomain() const
    \endcode
    returns the maximum value that belongs to the codomain of the
    partial function.
    The <CODE>max_in_codomain()</CODE> method is called at most once.
    \code
      bool maps(dimension_type i, dimension_type& j) const
    \endcode
    Let \f$f\f$ be the represented function and \f$k\f$ be the value
    of \p i.  If \f$f\f$ is defined in \f$k\f$, then \f$f(k)\f$ is
    assigned to \p j and <CODE>true</CODE> is returned.  If \f$f\f$ is
    undefined in \f$k\f$, then <CODE>false</CODE> is returned.
    This method is called at most \f$n\f$ times, where \f$n\f$ is the
    dimension of the vector space enclosing the grid.

    The result is undefined if \p pfunc does not encode a partial
    function with the properties described in the
    \ref Grid_Map_Space_Dimensions "specification of the mapping operator".
  */
  template <typename Partial_Function>
  void map_space_dimensions(const Partial_Function& pfunc);

  //! Creates \p m copies of the space dimension corresponding to \p var.
  /*!
    \param var
    The variable corresponding to the space dimension to be replicated;

    \param m
    The number of replicas to be created.

    \exception std::invalid_argument
    Thrown if \p var does not correspond to a dimension of the vector
    space.

    \exception std::length_error
    Thrown if adding \p m new space dimensions would cause the vector
    space to exceed dimension <CODE>max_space_dimension()</CODE>.

    If \p *this has space dimension \f$n\f$, with \f$n > 0\f$,
    and <CODE>var</CODE> has space dimension \f$k \leq n\f$,
    then the \f$k\f$-th space dimension is
    \ref Grid_Expand_Space_Dimension "expanded" to \p m new space dimensions
    \f$n\f$, \f$n+1\f$, \f$\dots\f$, \f$n+m-1\f$.
  */
  void expand_space_dimension(Variable var, dimension_type m);

  //! Folds the space dimensions in \p to_be_folded into \p var.
  /*!
    \param to_be_folded
    The set of Variable objects corresponding to the space dimensions
    to be folded;

    \param var
    The variable corresponding to the space dimension that is the
    destination of the folding operation.

    \exception std::invalid_argument
    Thrown if \p *this is dimension-incompatible with \p var or with
    one of the Variable objects contained in \p to_be_folded.  Also
    thrown if \p var is contained in \p to_be_folded.

    If \p *this has space dimension \f$n\f$, with \f$n > 0\f$,
    <CODE>var</CODE> has space dimension \f$k \leq n\f$,
    \p to_be_folded is a set of variables whose maximum space dimension
    is also less than or equal to \f$n\f$, and \p var is not a member
    of \p to_be_folded, then the space dimensions corresponding to
    variables in \p to_be_folded are \ref Grid_Fold_Space_Dimensions "folded"
    into the \f$k\f$-th space dimension.
  */
  void fold_space_dimensions(const Variables_Set& to_be_folded, Variable var);

  //@} // Member Functions that May Modify the Dimension of the Vector Space

  friend bool Parma_Polyhedra_Library::operator==(const Grid& x,
						  const Grid& y);

  friend class Parma_Polyhedra_Library::Grid_Certificate;

  //! \name Miscellaneous Member Functions
  //@{

  //! Destructor.
  ~Grid();

  /*! \brief
    Swaps \p *this with grid \p y.  (\p *this and \p y can be
    dimension-incompatible.)
  */
  void swap(Grid& y);

  PPL_OUTPUT_DECLARATIONS;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Loads from \p s an ASCII representation (as produced by
    \ref ascii_dump) and sets \p *this accordingly.

     \return
     <CODE>true</CODE> if successful, else <CODE>false</CODE>.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  bool ascii_load(std::istream& s);

  //! Returns the total size in bytes of the memory occupied by \p *this.
  memory_size_type total_memory_in_bytes() const;

  //! Returns the size in bytes of the memory managed by \p *this.
  memory_size_type external_memory_in_bytes() const;

  //@} // Miscellaneous Member Functions

private:

  //! The system of congruences.
  Congruence_System con_sys;

  //! The system of generators.
  Grid_Generator_System gen_sys;

#define PPL_IN_Grid_CLASS
// Automatically generated from PPL source file ../src/Grid_Status.idefs.hh line 1
/* Grid::Status class declaration.
*/


#ifndef PPL_IN_Grid_CLASS
#error "Do not include Grid_Status.idefs.hh directly; use Grid.defs.hh instead."
#endif

//! A conjunctive assertion about a grid.
/*!
  The assertions supported that are in use are:
  - <EM>zero-dim universe</EM>: the grid is the zero-dimension
    vector space \f$\Rset^0 = \{\cdot\}\f$;
  - <EM>empty</EM>: the grid is the empty set;
  - <EM>congruences up-to-date</EM>: the grid is correctly
    characterized by the attached system of congruences, modulo the
    processing of pending generators;
  - <EM>generators up-to-date</EM>: the grid is correctly
    characterized by the attached system of generators, modulo the
    processing of pending congruences;
  - <EM>congruences minimized</EM>: the non-pending part of the system
    of congruences attached to the grid is in minimal form;
  - <EM>generators minimized</EM>: the non-pending part of the system
    of generators attached to the grid is in minimal form.

  Other supported assertions are:
  - <EM>congruences pending</EM>
  - <EM>generators pending</EM>
  - <EM>congruences' saturation matrix up-to-date</EM>
  - <EM>generators' saturation matrix up-to-date</EM>.

  Not all the conjunctions of these elementary assertions constitute
  a legal Status.  In fact:
  - <EM>zero-dim universe</EM> excludes any other assertion;
  - <EM>empty</EM>: excludes any other assertion;
  - <EM>congruences pending</EM> and <EM>generators pending</EM>
    are mutually exclusive;
  - <EM>congruences pending</EM> implies both <EM>congruences minimized</EM>
    and <EM>generators minimized</EM>;
  - <EM>generators pending</EM> implies both <EM>congruences minimized</EM>
    and <EM>generators minimized</EM>;
  - <EM>congruences minimized</EM> implies <EM>congruences up-to-date</EM>;
  - <EM>generators minimized</EM> implies <EM>generators up-to-date</EM>;
  - <EM>congruences' saturation matrix up-to-date</EM> implies both
    <EM>congruences up-to-date</EM> and <EM>generators up-to-date</EM>;
  - <EM>generators' saturation matrix up-to-date</EM> implies both
    <EM>congruences up-to-date</EM> and <EM>generators up-to-date</EM>.
*/
class Status {
public:
  //! By default Status is the <EM>zero-dim universe</EM> assertion.
  Status();

  //! \name Test, remove or add an individual assertion from the conjunction
  //@{
  bool test_zero_dim_univ() const;
  void reset_zero_dim_univ();
  void set_zero_dim_univ();

  bool test_empty() const;
  void reset_empty();
  void set_empty();

  bool test_c_up_to_date() const;
  void reset_c_up_to_date();
  void set_c_up_to_date();

  bool test_g_up_to_date() const;
  void reset_g_up_to_date();
  void set_g_up_to_date();

  bool test_c_minimized() const;
  void reset_c_minimized();
  void set_c_minimized();

  bool test_g_minimized() const;
  void reset_g_minimized();
  void set_g_minimized();

  bool test_sat_c_up_to_date() const;
  void reset_sat_c_up_to_date();
  void set_sat_c_up_to_date();

  bool test_sat_g_up_to_date() const;
  void reset_sat_g_up_to_date();
  void set_sat_g_up_to_date();

  bool test_c_pending() const;
  void reset_c_pending();
  void set_c_pending();

  bool test_g_pending() const;
  void reset_g_pending();
  void set_g_pending();
  //@} // Test, remove or add an individual assertion from the conjunction

  //! Checks if all the invariants are satisfied.
  bool OK() const;

  PPL_OUTPUT_DECLARATIONS;

  /*! \brief
    Loads from \p s an ASCII representation (as produced by \ref
    ascii_dump) and sets \p *this accordingly.  Returns
    <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise.
  */
  bool ascii_load(std::istream& s);

private:
  //! Status is implemented by means of a finite bitset.
  typedef unsigned int flags_t;

  //! \name Bitmasks for the individual assertions
  //@{
  static const flags_t ZERO_DIM_UNIV    = 0U;
  static const flags_t EMPTY            = 1U << 0;
  static const flags_t C_UP_TO_DATE     = 1U << 1;
  static const flags_t G_UP_TO_DATE     = 1U << 2;
  static const flags_t C_MINIMIZED      = 1U << 3;
  static const flags_t G_MINIMIZED      = 1U << 4;
  static const flags_t SAT_C_UP_TO_DATE = 1U << 5;
  static const flags_t SAT_G_UP_TO_DATE = 1U << 6;
  static const flags_t CS_PENDING       = 1U << 7;
  static const flags_t GS_PENDING       = 1U << 8;
  //@} // Bitmasks for the individual assertions

  //! This holds the current bitset.
  flags_t flags;

  //! Construct from a bitmask.
  Status(flags_t mask);

  //! Check whether <EM>all</EM> bits in \p mask are set.
  bool test_all(flags_t mask) const;

  //! Check whether <EM>at least one</EM> bit in \p mask is set.
  bool test_any(flags_t mask) const;

  //! Set the bits in \p mask.
  void set(flags_t mask);

  //! Reset the bits in \p mask.
  void reset(flags_t mask);
};

// Automatically generated from PPL source file ../src/Grid.defs.hh line 1959
#undef PPL_IN_Grid_CLASS

  //! The status flags to keep track of the grid's internal state.
  Status status;

  //! The number of dimensions of the enclosing vector space.
  dimension_type space_dim;

  enum Dimension_Kind {
    PARAMETER,
    LINE,
    GEN_VIRTUAL,
    PROPER_CONGRUENCE = PARAMETER,
    CON_VIRTUAL = LINE,
    EQUALITY = GEN_VIRTUAL
  };

  typedef std::vector<Dimension_Kind> Dimension_Kinds;

  // The type of row associated with each dimension.  If the virtual
  // rows existed then the reduced systems would be square and upper
  // or lower triangular, and the rows in each would have the types
  // given in this vector.  As the congruence system is reduced to an
  // upside-down lower triangular form the ordering of the congruence
  // types is last to first.
  Dimension_Kinds dim_kinds;

  //! Builds a grid from a system of congruences.
  /*!
    The grid inherits the space dimension of the congruence system.

    \param cgs
    The system of congruences defining the grid.
  */
  void construct(const Congruence_System& cgs);

  //! Builds a grid from a system of generators.
  /*!
    The grid inherits the space dimension of the generator system.

    \param gs
    The system of generators defining the grid;
  */
  void construct(const Grid_Generator_System& gs);

  //! \name Private Verifiers: Verify if Individual Flags are Set
  //@{

  //! Returns <CODE>true</CODE> if the grid is known to be empty.
  /*!
    The return value <CODE>false</CODE> does not necessarily
    implies that \p *this is non-empty.
  */
  bool marked_empty() const;

  //! Returns <CODE>true</CODE> if the system of congruences is up-to-date.
  bool congruences_are_up_to_date() const;

  //! Returns <CODE>true</CODE> if the system of generators is up-to-date.
  bool generators_are_up_to_date() const;

  //! Returns <CODE>true</CODE> if the system of congruences is minimized.
  bool congruences_are_minimized() const;

  //! Returns <CODE>true</CODE> if the system of generators is minimized.
  bool generators_are_minimized() const;

  //@} // Private Verifiers: Verify if Individual Flags are Set

  //! \name State Flag Setters: Set Only the Specified Flags
  //@{

  /*! \brief
    Sets \p status to express that the grid is the universe
    0-dimension vector space, clearing all corresponding matrices.
  */
  void set_zero_dim_univ();

  /*! \brief
    Sets \p status to express that the grid is empty, clearing all
    corresponding matrices.
  */
  void set_empty();

  //! Sets \p status to express that congruences are up-to-date.
  void set_congruences_up_to_date();

  //! Sets \p status to express that generators are up-to-date.
  void set_generators_up_to_date();

  //! Sets \p status to express that congruences are minimized.
  void set_congruences_minimized();

  //! Sets \p status to express that generators are minimized.
  void set_generators_minimized();

  //@} // State Flag Setters: Set Only the Specified Flags

  //! \name State Flag Cleaners: Clear Only the Specified Flag
  //@{

  //! Clears the \p status flag indicating that the grid is empty.
  void clear_empty();

  //! Sets \p status to express that congruences are out of date.
  void clear_congruences_up_to_date();

  //! Sets \p status to express that parameters are out of date.
  void clear_generators_up_to_date();

  //! Sets \p status to express that congruences are no longer minimized.
  void clear_congruences_minimized();

  //! Sets \p status to express that generators are no longer minimized.
  void clear_generators_minimized();

  //@} // State Flag Cleaners: Clear Only the Specified Flag

  //! \name Updating Matrices
  //@{

  //! Updates and minimizes the congruences from the generators.
  /*!
    \return
    Always <CODE>true</CODE>.
  */
  bool update_congruences() const;

  //! Updates and minimizes the generators from the congruences.
  /*!
    \return
    <CODE>false</CODE> if and only if \p *this turns out to be an
    empty grid.

    It is illegal to call this method when the Status field already
    declares the grid to be empty.
  */
  bool update_generators() const;

  //@} // Updating Matrices

  //! \name Minimization of Descriptions
  //@{

  //! Minimizes both the congruences and the generators.
  /*!
    \return
    <CODE>false</CODE> if and only if \p *this turns out to be an
    empty grid.

    Minimization is performed on each system only if the minimized
    Status field is clear.
  */
  bool minimize() const;

  //@} // Minimization of Descriptions

  enum Three_Valued_Boolean {
    TVB_TRUE,
    TVB_FALSE,
    TVB_DONT_KNOW
  };

  //! Polynomial but incomplete equivalence test between grids.
  Three_Valued_Boolean quick_equivalence_test(const Grid& y) const;

  //! Returns <CODE>true</CODE> if and only if \p *this is included in \p y.
  bool is_included_in(const Grid& y) const;

  //! Checks if and how \p expr is bounded in \p *this.
  /*!
    Returns <CODE>true</CODE> if and only if \p from_above is
    <CODE>true</CODE> and \p expr is bounded from above in \p *this,
    or \p from_above is <CODE>false</CODE> and \p expr is bounded
    from below in \p *this.

    \param expr
    The linear expression to test;

    \param method_call
    The call description of the public parent method, for example
    "bounded_from_above(e)".  Passed to throw_dimension_incompatible,
    as the first argument.

    \exception std::invalid_argument
    Thrown if \p expr and \p *this are dimension-incompatible.
  */
  bool bounds(const Linear_Expression& expr, const char* method_call) const;

  //! Maximizes or minimizes \p expr subject to \p *this.
  /*!
    \param expr
    The linear expression to be maximized or minimized subject to \p
    *this;

    \param method_call
    The call description of the public parent method, for example
    "maximize(e)".  Passed to throw_dimension_incompatible, as the
    first argument;

    \param ext_n
    The numerator of the extremum value;

    \param ext_d
    The denominator of the extremum value;

    \param included
    <CODE>true</CODE> if and only if the extremum of \p expr in \p
    *this can actually be reached (which is always the case);

    \param point
    When maximization or minimization succeeds, will be assigned the
    point where \p expr reaches the extremum value.

    \exception std::invalid_argument
    Thrown if \p expr and \p *this are dimension-incompatible.

    If \p *this is empty or \p expr is not bounded in the appropriate
    direction, <CODE>false</CODE> is returned and \p ext_n, \p ext_d,
    \p included and \p point are left untouched.
  */
  bool max_min(const Linear_Expression& expr,
	       char* method_call,
	       Coefficient& ext_n, Coefficient& ext_d, bool& included,
	       Grid_Generator* point = NULL) const;

  //! \name Widening- and Extrapolation-Related Functions
  //@{

  //! Copies a widened selection of congruences from \p y to \p selected_cgs.
  void select_wider_congruences(const Grid& y,
				Congruence_System& selected_cgs) const;

  //@} // Widening- and Extrapolation-Related Functions

  //! Adds new space dimensions to the given systems.
  /*!
    \param cgs
    A congruence system, to which columns are added;

    \param gs
    A generator system, to which rows and columns are added;

    \param dims
    The number of space dimensions to add.

    This method is invoked only by
    <CODE>add_space_dimensions_and_embed()</CODE>.
  */
  void add_space_dimensions(Congruence_System& cgs,
			    Grid_Generator_System& gs,
			    const dimension_type dims);

  //! Adds new space dimensions to the given systems.
  /*!
    \param gs
    A generator system, to which columns are added;

    \param cgs
    A congruence system, to which rows and columns are added;

    \param dims
    The number of space dimensions to add.

    This method is invoked only by
    <CODE>add_space_dimensions_and_project()</CODE>.
  */
  void add_space_dimensions(Grid_Generator_System& gs,
			    Congruence_System& cgs,
			    const dimension_type dims);

  //! \name Minimization-related Static Member Functions
  //@{

  //! Normalizes the divisors in \p sys.
  /*!
    Converts \p sys to an equivalent system in which the divisors are
    of equal value.

    \return
    The new system divisor, or zero if \p divisor was zero.

    \param sys
    The generator system to be normalized.

    \param divisor
    An extra divisor to include in the calculation of the common
    divisor of \p sys.

    \param first_point
    If \p first_point has a value other than NULL then it is taken as
    the first point in \p sys, and it is assumed that any following
    points have the same divisor as \p first_point.
  */
  static Coefficient
  normalize_divisors(Grid_Generator_System& sys,
		     Coefficient_traits::const_reference divisor
		     = Coefficient_one(),
		     Grid_Generator* first_point = NULL);

  //! Normalize all the divisors in \p sys and \p gen_sys.
  /*!
    Modify \p sys and \p gen_sys to use the same single divisor value
    for all generators, leaving each system representing the grid it
    represented originally.
  */
  static void normalize_divisors(Grid_Generator_System& sys,
				 Grid_Generator_System& gen_sys);

  /*! \brief
    Converts generator system \p dest to be equivalent to congruence
    system \p source.
  */
  static void conversion(Congruence_System& source,
			 Grid_Generator_System& dest,
			 Dimension_Kinds& dim_kinds);

  /*! \brief
    Converts congruence system \p dest to be equivalent to generator
    system \p source.
  */
  static void conversion(Grid_Generator_System& source,
			 Congruence_System& dest,
			 Dimension_Kinds& dim_kinds);

  //! Converts \p cgs to upper triangular (i.e. minimized) form.
  /*!
    Returns <CODE>true</CODE> if \p cgs represents the empty set,
    otherwise returns <CODE>false</CODE>.
  */
  static bool simplify(Congruence_System& cgs,
		       Dimension_Kinds& dim_kinds);

  //! Converts \p gs to lower triangular (i.e. minimized) form.
  /*!
    Expects \p gs to contain at least one point.
  */
  static void simplify(Grid_Generator_System& gs,
		       Dimension_Kinds& dim_kinds);

  //! Reduces the line \p row using the line \p pivot.
  /*!
    Uses the line \p pivot to change the representation of the line \p
    row so that the element at index \p col of \p row is zero.
  */
  // A member of Grid for access to Matrix::rows.
  static void reduce_line_with_line(Grid_Generator& row,
				    Grid_Generator& pivot,
				    dimension_type col);

  //! Reduces the equality \p row using the equality \p pivot.
  /*!
    Uses the equality \p pivot to change the representation of the
    equality \p row so that the element at index \p col of \p row is
    zero.
  */
  // A member of Grid for access to Matrix::rows.
  static void reduce_equality_with_equality(Congruence& row,
					    Congruence& pivot,
					    dimension_type col);

  //! Reduces \p row using \p pivot.
  /*!
    Uses the point, parameter or proper congruence at \p pivot to
    change the representation of the point, parameter or proper
    congruence at \p row so that the element at index \p col of \p row
    is zero.  Only elements from index \p start to index \p end are
    modified (i.e. it is assumed that all other elements are zero).
  */
  // Part of Grid for access to Matrix::rows.
  template <typename R>
  static void reduce_pc_with_pc(R& row,
				R& pivot,
				dimension_type col,
				dimension_type start,
				dimension_type end);

  //! Reduce \p row using \p pivot.
  /*!
    Use the line \p pivot to change the representation of the
    parameter \p row such that the element at index \p col of \p row
    is zero.
  */
  // A member of Grid for access to Matrix::rows.
  static void reduce_parameter_with_line(Grid_Generator& row,
					 Grid_Generator& pivot,
					 dimension_type col,
					 Grid_Generator_System& sys);

  //! Reduce \p row using \p pivot.
  /*!
    Use the equality \p pivot to change the representation of the
    congruence \p row such that element at index \p col of \p row is
    zero.
  */
  // A member of Grid for access to Matrix::rows.
  static void reduce_congruence_with_equality(Congruence& row,
					      Congruence& pivot,
					      dimension_type col,
					      Congruence_System& sys);

  //! Reduce column \p dim in rows preceding \p pivot_index in \p sys.
  /*!
    Only consider from index \p start to index \p end of the row at \p
    pivot_index.  Flag \p generators indicates whether \p sys is a
    congruence or generator system.
  */
  template <typename M, typename R>
  static void reduce_reduced(M& sys, dimension_type dim,
			     dimension_type pivot_index,
			     dimension_type start, dimension_type end,
			     Dimension_Kinds& dim_kinds,
			     bool generators = true);

  //! Multiply the elements of \p dest by \p multiplier.
  // A member of Grid for access to Matrix::rows and cgs::operator[].
  static void multiply_grid(const Coefficient& multiplier,
			    Congruence& cg, Congruence_System& dest,
			    const dimension_type num_rows,
			    const dimension_type num_dims);

  //! Multiply the elements of \p dest by \p multiplier.
  // A member of Grid for access to Grid_Generator::operator[].
  static void multiply_grid(const Coefficient& multiplier, Grid_Generator& gen,
			    Grid_Generator_System& dest, const dimension_type num_rows,
			    const dimension_type num_dims);

  /*! \brief
    If \p sys is lower triangular return <CODE>true</CODE>, else
    return <CODE>false</CODE>.
  */
  static bool lower_triangular(const Congruence_System& sys,
			       const Dimension_Kinds& dim_kinds);

  /*! \brief
    If \p sys is upper triangular return <CODE>true</CODE>, else
    return <CODE>false</CODE>.
  */
  static bool upper_triangular(const Grid_Generator_System& sys,
			       const Dimension_Kinds& dim_kinds);

#ifndef NDEBUG
  //! Checks that trailing rows contain only zero terms.
  /*!
    If all columns contain zero in the rows of \p system from row
    index \p first to row index \p last then return <code>true</code>,
    else return <code>false</code>.  \p row_size gives the number of
    columns in each row.

    This method is only used in assertions in the simplify methods.
  */
  template <typename M, typename R>
  static bool rows_are_zero(M& system,
			    dimension_type first,
			    dimension_type last,
			    dimension_type row_size);
#endif

  //@} // Minimization-Related Static Member Functions

  //! \name Exception Throwers
  //@{
protected:
  void throw_runtime_error(const char* method) const;
  void throw_invalid_argument(const char* method, const char* reason) const;

  void throw_dimension_incompatible(const char* method,
				    const char* other_name,
				    dimension_type other_dim) const;
  void throw_dimension_incompatible(const char* method,
				    const char* gr_name,
				    const Grid& gr) const;
  void throw_dimension_incompatible(const char* method,
				    const char* e_name,
				    const Linear_Expression& e) const;
  void throw_dimension_incompatible(const char* method,
				    const char* cg_name,
				    const Congruence& cg) const;
  void throw_dimension_incompatible(const char* method,
				    const char* c_name,
				    const Constraint& c) const;
  void throw_dimension_incompatible(const char* method,
				    const char* g_name,
				    const Grid_Generator& g) const;
  void throw_dimension_incompatible(const char* method,
				    const char* cgs_name,
				    const Congruence_System& cgs) const;
  void throw_dimension_incompatible(const char* method,
				    const char* cs_name,
				    const Constraint_System& cs) const;
  void throw_dimension_incompatible(const char* method,
				    const char* gs_name,
				    const Grid_Generator_System& gs) const;
  void throw_dimension_incompatible(const char* method,
				    const char* var_name,
				    const Variable var) const;
  void throw_dimension_incompatible(const char* method,
				    dimension_type required_space_dim) const;

  // Note: it has to be a static method, because it can be called inside
  // constructors (before actually constructing the grid object).
  static void throw_space_dimension_overflow(const char* method,
					     const char* reason);

  void throw_invalid_generator(const char* method,
			       const char* g_name) const;
  void throw_invalid_generators(const char* method,
				const char* gs_name) const;
  //@} // Exception Throwers

};


namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Grid */
void swap(Parma_Polyhedra_Library::Grid& x,
	  Parma_Polyhedra_Library::Grid& y);

} // namespace std

// Automatically generated from PPL source file ../src/Grid_Status.inlines.hh line 1
/* Grid::Status class implementation: inline functions.
*/


namespace Parma_Polyhedra_Library {

inline
Grid::Status::Status(flags_t mask)
  : flags(mask) {
}

inline
Grid::Status::Status()
  : flags(ZERO_DIM_UNIV) {
}

inline bool
Grid::Status::test_all(flags_t mask) const {
  return (flags & mask) == mask;
}

inline bool
Grid::Status::test_any(flags_t mask) const {
  return flags & mask;
}

inline void
Grid::Status::set(flags_t mask) {
  flags |= mask;
}

inline void
Grid::Status::reset(flags_t mask) {
  flags &= ~mask;
}

inline bool
Grid::Status::test_zero_dim_univ() const {
  return flags == ZERO_DIM_UNIV;
}

inline void
Grid::Status::reset_zero_dim_univ() {
  // This is a no-op if the current status is not zero-dim.
  if (flags == ZERO_DIM_UNIV)
    // In the zero-dim space, if it is not the universe it is empty.
    flags = EMPTY;
}

inline void
Grid::Status::set_zero_dim_univ() {
  // Zero-dim universe is incompatible with anything else.
  flags = ZERO_DIM_UNIV;
}

inline bool
Grid::Status::test_empty() const {
  return test_any(EMPTY);
}

inline void
Grid::Status::reset_empty() {
  reset(EMPTY);
}

inline void
Grid::Status::set_empty() {
  flags = EMPTY;
}

inline bool
Grid::Status::test_c_up_to_date() const {
  return test_any(C_UP_TO_DATE);
}

inline void
Grid::Status::reset_c_up_to_date() {
  reset(C_UP_TO_DATE);
}

inline void
Grid::Status::set_c_up_to_date() {
  set(C_UP_TO_DATE);
}

inline bool
Grid::Status::test_g_up_to_date() const {
  return test_any(G_UP_TO_DATE);
}

inline void
Grid::Status::reset_g_up_to_date() {
  reset(G_UP_TO_DATE);
}

inline void
Grid::Status::set_g_up_to_date() {
  set(G_UP_TO_DATE);
}

inline bool
Grid::Status::test_c_minimized() const {
  return test_any(C_MINIMIZED);
}

inline void
Grid::Status::reset_c_minimized() {
  reset(C_MINIMIZED);
}

inline void
Grid::Status::set_c_minimized() {
  set(C_MINIMIZED);
}

inline bool
Grid::Status::test_g_minimized() const {
  return test_any(G_MINIMIZED);
}

inline void
Grid::Status::reset_g_minimized() {
  reset(G_MINIMIZED);
}

inline void
Grid::Status::set_g_minimized() {
  set(G_MINIMIZED);
}


inline bool
Grid::Status::test_c_pending() const {
  return test_any(CS_PENDING);
}

inline void
Grid::Status::reset_c_pending() {
  reset(CS_PENDING);
}

inline void
Grid::Status::set_c_pending() {
  set(CS_PENDING);
}

inline bool
Grid::Status::test_g_pending() const {
  return test_any(GS_PENDING);
}

inline void
Grid::Status::reset_g_pending() {
  reset(GS_PENDING);
}

inline void
Grid::Status::set_g_pending() {
  set(GS_PENDING);
}


inline bool
Grid::Status::test_sat_c_up_to_date() const {
  return test_any(SAT_C_UP_TO_DATE);
}

inline void
Grid::Status::reset_sat_c_up_to_date() {
  reset(SAT_C_UP_TO_DATE);
}

inline void
Grid::Status::set_sat_c_up_to_date() {
  set(SAT_C_UP_TO_DATE);
}

inline bool
Grid::Status::test_sat_g_up_to_date() const {
  return test_any(SAT_G_UP_TO_DATE);
}

inline void
Grid::Status::reset_sat_g_up_to_date() {
  reset(SAT_G_UP_TO_DATE);
}

inline void
Grid::Status::set_sat_g_up_to_date() {
  set(SAT_G_UP_TO_DATE);
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Grid.inlines.hh line 1
/* Grid class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/Grid.inlines.hh line 28
#include <algorithm>

namespace Parma_Polyhedra_Library {

inline dimension_type
Grid::max_space_dimension() {
  using std::min;
  // One dimension is reserved to have a value of type dimension_type
  // that does not represent a legal dimension.
  return min(std::numeric_limits<dimension_type>::max() - 1,
	     min(Congruence_System::max_space_dimension(),
		 Grid_Generator_System::max_space_dimension()
		 )
	     );
}

inline void
Grid::set_congruences_up_to_date() {
  status.set_c_up_to_date();
}

inline
Grid::Grid(const Congruence_System& ccgs) {
  if (ccgs.space_dimension() > max_space_dimension())
    throw_space_dimension_overflow("Grid(ccgs)",
				   "the space dimension of ccgs "
				   "exceeds the maximum allowed "
				   "space dimension");
  construct(ccgs);
}

inline
Grid::Grid(Congruence_System& cgs) {
  if (cgs.space_dimension() > max_space_dimension())
    throw_space_dimension_overflow("Grid(cgs)",
				   "the space dimension of cgs "
				   "exceeds the maximum allowed "
				   "space dimension");
  construct(cgs);
}

inline
Grid::Grid(const Grid_Generator_System& gs) {
  if (gs.space_dimension() > max_space_dimension())
    throw_space_dimension_overflow("Grid(gs)",
				   "the space dimension of gs "
				   "exceeds the maximum allowed "
				   "space dimension");
  construct(gs);
}

inline
Grid::Grid(Grid_Generator_System& gs) {
  if (gs.space_dimension() > max_space_dimension())
    throw_space_dimension_overflow("Grid(gs)",
				   "the space dimension of gs "
				   "exceeds the maximum allowed "
				   "space dimension");
  construct(gs);
}

inline
Grid::~Grid() {
}

inline memory_size_type
Grid::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

inline dimension_type
Grid::space_dimension() const {
  return space_dim;
}

inline void
Grid::upper_bound_assign(const Grid& y) {
  join_assign(y);
}

inline bool
Grid::upper_bound_assign_if_exact(const Grid& y) {
  return join_assign_if_exact(y);
}

inline void
Grid::difference_assign(const Grid& y) {
  grid_difference_assign(y);
}

inline void
Grid::swap(Grid& y) {
  std::swap(con_sys, y.con_sys);
  std::swap(gen_sys, y.gen_sys);
  std::swap(status, y.status);
  std::swap(space_dim, y.space_dim);
  std::swap(dim_kinds, y.dim_kinds);
}

} // namespace Parma_Polyhedra_Library

/*! \relates Parma_Polyhedra_Library::Grid */
inline void
std::swap(Parma_Polyhedra_Library::Grid& x,
	  Parma_Polyhedra_Library::Grid& y) {
  x.swap(y);
}

namespace Parma_Polyhedra_Library {

inline bool
Grid::marked_empty() const {
  return status.test_empty();
}

inline bool
Grid::congruences_are_up_to_date() const {
  return status.test_c_up_to_date();
}

inline bool
Grid::generators_are_up_to_date() const {
  return status.test_g_up_to_date();
}

inline bool
Grid::congruences_are_minimized() const {
  return status.test_c_minimized();
}

inline bool
Grid::generators_are_minimized() const {
  return status.test_g_minimized();
}

inline void
Grid::set_generators_up_to_date() {
  status.set_g_up_to_date();
}

inline void
Grid::set_congruences_minimized() {
  set_congruences_up_to_date();
  status.set_c_minimized();
}

inline void
Grid::set_generators_minimized() {
  set_generators_up_to_date();
  status.set_g_minimized();
}

inline void
Grid::clear_empty() {
  status.reset_empty();
}

inline void
Grid::clear_congruences_minimized() {
  status.reset_c_minimized();
}

inline void
Grid::clear_generators_minimized() {
  status.reset_g_minimized();
}

inline void
Grid::clear_congruences_up_to_date() {
  clear_congruences_minimized();
  status.reset_c_up_to_date();
  // Can get rid of con_sys here.
}

inline void
Grid::clear_generators_up_to_date() {
  clear_generators_minimized();
  status.reset_g_up_to_date();
  // Can get rid of gen_sys here.
}

inline bool
Grid::bounds_from_above(const Linear_Expression& expr) const {
  return bounds(expr, "bounds_from_above(e)");
}

inline bool
Grid::bounds_from_below(const Linear_Expression& expr) const {
  return bounds(expr, "bounds_from_below(e)");
}

inline bool
Grid::maximize(const Linear_Expression& expr,
	       Coefficient& sup_n, Coefficient& sup_d, bool& maximum) const {
  return max_min(expr, "maximize(e, ...)", sup_n, sup_d, maximum);
}

inline bool
Grid::maximize(const Linear_Expression& expr,
	       Coefficient& sup_n, Coefficient& sup_d, bool& maximum,
	       Grid_Generator& point) const {
  return max_min(expr, "maximize(e, ...)", sup_n, sup_d, maximum, &point);
}

inline bool
Grid::minimize(const Linear_Expression& expr,
	       Coefficient& inf_n, Coefficient& inf_d, bool& minimum) const {
  return max_min(expr, "minimize(e, ...)", inf_n, inf_d, minimum);
}

inline bool
Grid::minimize(const Linear_Expression& expr,
	       Coefficient& inf_n, Coefficient& inf_d, bool& minimum,
	       Grid_Generator& point) const {
  return max_min(expr, "minimize(e, ...)", inf_n, inf_d, minimum, &point);
}

/*! \relates Grid */
inline bool
operator!=(const Grid& x, const Grid& y) {
  return !(x == y);
}

inline bool
Grid::strictly_contains(const Grid& y) const {
  const Grid& x = *this;
  return x.contains(y) && !y.contains(x);
}

inline void
Grid::topological_closure_assign() {
  return;
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Grid.templates.hh line 1
/* Grid class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/Grid.templates.hh line 29
#include <algorithm>
#include <deque>

namespace Parma_Polyhedra_Library {

template <typename Box>
Grid::Grid(const Box& box, From_Bounding_Box dummy)
  : con_sys(),
    gen_sys(NECESSARILY_CLOSED) {
  used(dummy);

  if (box.space_dimension() > max_space_dimension())
    throw_space_dimension_overflow("Grid(box, from_bounding_box)",
				   "the space dimension of box "
				   "exceeds the maximum allowed "
				   "space dimension");

  space_dim = box.space_dimension();

  TEMP_INTEGER(l_n);
  TEMP_INTEGER(l_d);

  // Check that all bounds are closed.  This must be done before the
  // empty check below, in case an open bound makes the grid empty.
  for (dimension_type k = space_dim; k-- > 0; ) {
    bool closed;
    // FIXME: Perhaps introduce box::is_bounded_and_closed.
    if (box.get_lower_bound(k, closed, l_n, l_d) && !closed)
      throw_invalid_argument("Grid(box, from_bounding_box)", "box");
    if (box.get_upper_bound(k, closed, l_n, l_d) && !closed)
      throw_invalid_argument("Grid(box, from_bounding_box)", "box");
  }

  if (box.is_empty()) {
    // Empty grid.
    set_empty();
    assert(OK());
    return;
  }

  if (space_dim == 0)
    set_zero_dim_univ();
  else {
    // Initialize the space dimension as indicated by the box.
    con_sys.increase_space_dimension(space_dim);
    // Add congruences according to `box'.
    TEMP_INTEGER(u_n);
    TEMP_INTEGER(u_d);
    for (dimension_type k = space_dim; k-- > 0; ) {
      bool closed;
      // TODO: Consider producing the system(s) in minimized form.
      // FIXME: Also create the generator system.
      if (box.get_lower_bound(k, closed, l_n, l_d)) {
	if (box.get_upper_bound(k, closed, u_n, u_d))
	  if (l_n * u_d == u_n * l_d) {
	    // A point interval sets dimension k of every point to a
	    // single value.
	    con_sys.insert(l_d * Variable(k) == l_n);
	    continue;
	  }
	// The only valid bounded interval is a point interval.
	throw_invalid_argument("Grid(box, from_bounding_box)", "box");
      }
      else if (box.get_upper_bound(k, closed, u_n, u_d))
	// An interval can only be a point or the universe.
	throw_invalid_argument("Grid(box, from_covering_box)",
			       "box");
      // A universe interval allows any value in dimension k.
    }
    set_congruences_up_to_date();
    gen_sys.unset_pending_rows();
    gen_sys.set_sorted(false);
  }

  assert(OK());
}

template <typename Box>
Grid::Grid(const Box& box, From_Covering_Box dummy)
  : con_sys(),
    gen_sys(NECESSARILY_CLOSED) {
  used(dummy);

  if (box.space_dimension() > max_space_dimension())
    throw_space_dimension_overflow("Grid(box, from_covering_box)",
				   "the space dimension of box "
				   "exceeds the maximum allowed "
				   "space dimension");

  space_dim = box.space_dimension();

  TEMP_INTEGER(l_n);
  TEMP_INTEGER(l_d);

  // Check that all bounds are closed.  This must be done before the
  // empty check below, in case an open bound makes the grid empty.
  for (dimension_type k = space_dim; k-- > 0; ) {
    bool closed;
    // FIXME: Perhaps introduce box::is_bounded_and_closed.
    if (box.get_lower_bound(k, closed, l_n, l_d) && !closed)
      throw_invalid_argument("Grid(box, from_covering_box)", "box");
    if (box.get_upper_bound(k, closed, l_n, l_d) && !closed)
      throw_invalid_argument("Grid(box, from_covering_box)", "box");
  }

  if (box.is_empty()) {
    // Empty grid.
    set_empty();
    assert(OK());
    return;
  }

  if (space_dim == 0)
    set_zero_dim_univ();
  else {
    // Initialize the space dimension as indicated by the box.
    con_sys.increase_space_dimension(space_dim);
    // Add congruences according to `box'.
    TEMP_INTEGER(u_n);
    TEMP_INTEGER(u_d);
    TEMP_INTEGER(d);
    for (dimension_type k = space_dim; k-- > 0; ) {
      bool closed;
      // TODO: Consider producing the system(s) in minimized form.
      // FIXME: Also create the generator system.
      if (box.get_lower_bound(k, closed, l_n, l_d)) {
	if (box.get_upper_bound(k, closed, u_n, u_d)) {
	  if (l_n * u_d == u_n * l_d)
	    // A point interval allows any point along the dimension
	    // k axis.
	    continue;
	  gcd_assign(d, l_d, u_d);
	  // `d' is the gcd of the divisors.
	  l_n *= (u_d / d);
	  d = l_d / d;
	  // `d' is now the smallest integer expression of the size
	  // of l_d relative to u_d.  `d * u_d' is the lcm of the
	  // divisors.
	  con_sys.insert((d * u_d * Variable(k) %= l_n) / ((u_n * d) - l_n));
	}
	else
	  // An interval bounded only from below produces an
	  // equality.
	  con_sys.insert(l_d * Variable(k) == l_n);
      }
      else
	if (box.get_upper_bound(k, closed, u_n, u_d))
	  // An interval bounded only from above produces an equality.
	  con_sys.insert(u_d * Variable(k) == u_n);
	else {
	  // Any universe interval produces an empty grid.
	  set_empty();
	  assert(OK());
	  return;
	}
    }
    set_congruences_up_to_date();
    gen_sys.set_sorted(false);
    gen_sys.unset_pending_rows();
  }

  assert(OK());
}

template <typename Box>
void
Grid::shrink_bounding_box(Box& box) const {
  // Dimension-compatibility check.
  if (space_dim > box.space_dimension())
    throw_dimension_incompatible("shrink_bounding_box(box)", "box",
				 box.space_dimension());

  TEMP_INTEGER(l_n);
  TEMP_INTEGER(l_d);

  // Check that all bounds are closed.
  for (dimension_type k = space_dim; k-- > 0; ) {
    bool closed;
    // FIXME: Perhaps introduce box::is_bounded_and_closed.
    if (box.get_lower_bound(k, closed, l_n, l_d) && !closed)
      throw_invalid_argument("shrink_bounding_box(box)", "box");
    if (box.get_upper_bound(k, closed, l_n, l_d) && !closed)
      throw_invalid_argument("shrink_bounding_box(box)", "box");
  }

  if (marked_empty()) {
    box.set_empty();
    return;
  }
  if (space_dim == 0)
    return;
  if (!generators_are_up_to_date() && !update_generators()) {
    // Updating found the grid empty.
    box.set_empty();
    return;
  }

  assert(gen_sys.num_generators() > 0);

  dimension_type num_dims = gen_sys.num_columns() - 2 /* parameter divisor */;
  dimension_type num_rows = gen_sys.num_generators();

  // Create a vector to record which dimensions are bounded.
  std::vector<bool> bounded_interval(num_dims, true);

  const Grid_Generator *first_point = NULL;
  // Clear the bound flag in `bounded_interval' for all dimensions in
  // which a line or sequence of points extends away from a single
  // value in the dimension.
  for (dimension_type row = 0; row < num_rows; ++row) {
    Grid_Generator& gen = const_cast<Grid_Generator&>(gen_sys[row]);
    if (gen.is_point()) {
      if (first_point == NULL) {
	first_point = &gen_sys[row];
	continue;
      }
      const Grid_Generator& point = *first_point;
      // Convert the point `gen' to a parameter.
      for (dimension_type dim = 0; dim < num_dims; ++dim)
	gen[dim] -= point[dim];
      gen.divisor() = point.divisor();
    }
    for (dimension_type col = num_dims; col > 0; )
      if (gen[col--] != 0)
	bounded_interval[col] = false;
  }

  // Attempt to set both bounds of each boundable interval to the
  // value of the associated coefficient in the point.
  const Grid_Generator& point = *first_point;
  TEMP_INTEGER(divisor);
  TEMP_INTEGER(gcd);
  TEMP_INTEGER(bound);
  TEMP_INTEGER(reduced_divisor);
  divisor = point.divisor();
  for (dimension_type dim = 0; dim < num_dims; ++dim)
    if (bounded_interval[dim]) {
      // Reduce the bound fraction first.
      gcd_assign(gcd, point[dim+1], divisor);
      exact_div_assign(bound, point[dim+1], gcd);
      exact_div_assign(reduced_divisor, divisor, gcd);
      box.raise_lower_bound(dim, true, bound, reduced_divisor);
      box.lower_upper_bound(dim, true, bound, reduced_divisor);
    }
}

template <typename Box>
void
Grid::get_covering_box(Box& box) const {
  // Dimension-compatibility check.
  if (space_dim > box.space_dimension())
    throw_dimension_incompatible("get_covering_box(box)", "box",
				 box.space_dimension());

  Box new_box(box.space_dimension());

  if (marked_empty()) {
    box = new_box;
    box.set_empty();
    return;
  }
  if (space_dim == 0) {
    return;
  }
  if (!generators_are_up_to_date() && !update_generators()) {
    // Updating found the grid empty.
    box = new_box;
    box.set_empty();
    return;
  }

  assert(gen_sys.num_generators() > 0);

  dimension_type num_dims = gen_sys.num_columns() - 2 /* parameter divisor */;
  dimension_type num_rows = gen_sys.num_generators();

  TEMP_INTEGER(divisor);
  TEMP_INTEGER(gcd);
  TEMP_INTEGER(bound);
  TEMP_INTEGER(reduced_divisor);

  if (num_rows > 1) {
    Row interval_sizes(num_dims, Row::Flags());
    std::vector<bool> interval_emptiness(num_dims, false);

    // Store in `interval_sizes', for each column (that is, for each
    // dimension), the GCD of all the values in that column where the
    // row is of type parameter.

    for (dimension_type dim = num_dims; dim-- > 0; )
      interval_sizes[dim] = 0;
    const Grid_Generator *first_point = NULL;
    for (dimension_type row = 0; row < num_rows; ++row) {
      Grid_Generator& gen = const_cast<Grid_Generator&>(gen_sys[row]);
      if (gen.is_line()) {
	for (dimension_type dim = 0; dim < num_dims; ++dim)
	  if (!interval_emptiness[dim] && gen[dim+1] != 0) {
	    // Empty interval, set both bounds for associated
      	    // dimension to zero.
	    new_box.lower_upper_bound(dim, true, 0, 1);
	    new_box.raise_lower_bound(dim, true, 0, 1);
	    interval_emptiness[dim] = true;
	  }
	continue;
      }
      if (gen.is_point()) {
	if (first_point == NULL) {
	  first_point = &gen_sys[row];
	  continue;
	}
	const Grid_Generator& point = *first_point;
	// Convert the point `gen' to a parameter.
	for (dimension_type dim = 0; dim <= num_dims; ++dim)
	  gen[dim] -= point[dim];
	gen.divisor() = point.divisor();
      }
      for (dimension_type dim = 0; dim < num_dims; ++dim)
	if (!interval_emptiness[dim])
	  gcd_assign(interval_sizes[dim], interval_sizes[dim], gen[dim+1]);
    }

    // For each dimension set the lower bound of the interval to the
    // grid value closest to the origin, and the upper bound to the
    // addition of the lower bound and the shortest distance in the
    // given dimension between any two grid points.
    const Grid_Generator& point = *first_point;
    divisor = point.divisor();
    TEMP_INTEGER(lower_bound);
    for (dimension_type dim = 0; dim < num_dims; ++dim) {
      if (interval_emptiness[dim])
	continue;

      lower_bound = point[dim+1];

      // If the interval size is zero then all points have the same
      // value in this dimension, so set only the lower bound.
      if (interval_sizes[dim] != 0) {
	// Make the lower bound as close as possible to the origin,
	// leaving the sign the same.
	lower_bound %= interval_sizes[dim];
	// Check if the lowest value the other side of the origin is
	// closer to the origin, prefering the lowest positive if they
	// are equal.
	if (lower_bound > 0) {
	  if (interval_sizes[dim] - lower_bound < lower_bound)
	    lower_bound -= interval_sizes[dim];
	}
	else if (lower_bound < 0
		 && interval_sizes[dim] + lower_bound < - lower_bound)
	  lower_bound += interval_sizes[dim];

	// Reduce the bound fraction first.
	bound = interval_sizes[dim] + lower_bound;
	gcd_assign(gcd, bound, divisor);
	exact_div_assign(bound, bound, gcd);
	exact_div_assign(reduced_divisor, divisor, gcd);
	new_box.lower_upper_bound(dim, true, bound, reduced_divisor);
      }

      // Reduce the bound fraction first.
      gcd_assign(gcd, lower_bound, divisor);
      exact_div_assign(lower_bound, lower_bound, gcd);
      exact_div_assign(reduced_divisor, divisor, gcd);
      new_box.raise_lower_bound(dim, true, lower_bound, reduced_divisor);
    }
  }
  else {
    const Grid_Generator& point = gen_sys[0];
    divisor = point.divisor();
    // The covering box of a single point has only lower bounds.
    for (dimension_type dim = 0; dim < num_dims; ++dim) {
      // Reduce the bound fraction first.
      gcd_assign(gcd, point[dim+1], divisor);
      exact_div_assign(bound, point[dim+1], gcd);
      exact_div_assign(reduced_divisor, divisor, gcd);
      new_box.raise_lower_bound(dim, true, bound, reduced_divisor);
    }
  }

  box = new_box;
}

template <typename Partial_Function>
void
Grid::map_space_dimensions(const Partial_Function& pfunc) {
  if (space_dim == 0)
    return;

  if (pfunc.has_empty_codomain()) {
    // All dimensions vanish: the grid becomes zero_dimensional.
    if (marked_empty()
	|| (!generators_are_up_to_date() && !update_generators())) {
      // Removing all dimensions from the empty grid.
      space_dim = 0;
      set_empty();
    }
    else
      // Removing all dimensions from a non-empty grid.
      set_zero_dim_univ();

    assert(OK());
    return;
  }

  dimension_type new_space_dimension = pfunc.max_in_codomain() + 1;

  if (new_space_dimension == space_dim) {
    // The partial function `pfunc' is indeed total and thus specifies
    // a permutation, that is, a renaming of the dimensions.  For
    // maximum efficiency, we will simply permute the columns of the
    // constraint system and/or the generator system.

    // We first compute suitable permutation cycles for the columns of
    // the `con_sys' and `gen_sys' matrices.  We will represent them
    // with a linear array, using 0 as a terminator for each cycle
    // (notice that the columns with index 0 of `con_sys' and
    // `gen_sys' represent the inhomogeneous terms, and thus are
    // unaffected by the permutation of dimensions).
    // Cycles of length 1 will be omitted so that, in the worst case,
    // we will have `space_dim' elements organized in `space_dim/2'
    // cycles, which means we will have at most `space_dim/2'
    // terminators.
    std::vector<dimension_type> cycles;
    cycles.reserve(space_dim + space_dim/2);

    // Used to mark elements as soon as they are inserted in a cycle.
    std::deque<bool> visited(space_dim);

    for (dimension_type i = space_dim; i-- > 0; ) {
      if (!visited[i]) {
	dimension_type j = i;
	do {
	  visited[j] = true;
	  dimension_type k;
	  (void) pfunc.maps(j, k);
	  if (k == j)
	    // Cycle of length 1: skip it.
	    goto skip;

	  cycles.push_back(j+1);
	  // Go along the cycle.
	  j = k;
	} while (!visited[j]);
	// End of cycle: mark it.
	cycles.push_back(0);
      skip:
	;
      }
    }

    // If `cycles' is empty then `pfunc' is the identity.
    if (cycles.empty())
      return;

    // Permute all that is up-to-date.
    if (congruences_are_up_to_date()) {
      con_sys.permute_columns(cycles);
      clear_congruences_minimized();
    }

    if (generators_are_up_to_date()) {
      gen_sys.permute_columns(cycles);
      clear_generators_minimized();
    }

    assert(OK());
    return;
  }

  // If control gets here, then `pfunc' is not a permutation and some
  // dimensions must be projected away.

  const Grid_Generator_System& old_gensys = generators();

  if (old_gensys.num_generators() == 0) {
    // The grid is empty.
    Grid new_grid(new_space_dimension, EMPTY);
    std::swap(*this, new_grid);
    assert(OK());
    return;
  }

  // Make a local copy of the partial function.
  std::vector<dimension_type> pfunc_maps(space_dim, not_a_dimension());
  for (dimension_type j = space_dim; j-- > 0; ) {
    dimension_type pfunc_j;
    if (pfunc.maps(j, pfunc_j))
      pfunc_maps[j] = pfunc_j;
  }

  Grid_Generator_System new_gensys;
  // Set sortedness, for the assertion met via gs::insert.
  new_gensys.set_sorted(false);
  // Get the divisor of the first point.
  Grid_Generator_System::const_iterator i;
  Grid_Generator_System::const_iterator old_gensys_end = old_gensys.end();
  for (i = old_gensys.begin(); i != old_gensys_end; ++i)
    if (i->is_point())
      break;
  assert(i != old_gensys_end);
  Coefficient_traits::const_reference system_divisor = i->divisor();
  for (Grid_Generator_System::const_iterator i = old_gensys.begin();
       i != old_gensys_end;
       ++i) {
    const Grid_Generator& old_g = *i;
    Linear_Expression e(0 * Variable(new_space_dimension-1));
    bool all_zeroes = true;
    for (dimension_type j = space_dim; j-- > 0; ) {
      if (old_g.coefficient(Variable(j)) != 0
	  && pfunc_maps[j] != not_a_dimension()) {
	e += Variable(pfunc_maps[j]) * old_g.coefficient(Variable(j));
	all_zeroes = false;
      }
    }
    switch (old_g.type()) {
    case Grid_Generator::LINE:
      if (!all_zeroes)
	new_gensys.insert(grid_line(e));
      break;
    case Grid_Generator::PARAMETER:
      if (!all_zeroes)
	new_gensys.insert(parameter(e, system_divisor));
      break;
    case Grid_Generator::POINT:
      new_gensys.insert(grid_point(e, old_g.divisor()));
      break;
    case Grid_Generator::CLOSURE_POINT:
    default:
      assert(0);
    }
  }

  Grid new_grid(new_gensys);
  std::swap(*this, new_grid);

  assert(OK(true));
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Grid.defs.hh line 2484

// Automatically generated from PPL source file ../src/C_Polyhedron.defs.hh line 1
/* C_Polyhedron class declaration.
*/


// Automatically generated from PPL source file ../src/C_Polyhedron.defs.hh line 29

//! A closed convex polyhedron.
/*! \ingroup PPL_CXX_interface
    An object of the class C_Polyhedron represents a
    <EM>topologically closed</EM> convex polyhedron
    in the vector space \f$\Rset^n\f$.

    When building a closed polyhedron starting from
    a system of constraints, an exception is thrown if the system
    contains a <EM>strict inequality</EM> constraint.
    Similarly, an exception is thrown when building a closed polyhedron
    starting from a system of generators containing a <EM>closure point</EM>.

    \note
    Such an exception will be obtained even if the system of
    constraints (resp., generators) actually defines
    a topologically closed subset of the vector space, i.e.,
    even if all the strict inequalities (resp., closure points)
    in the system happen to be redundant with respect to the
    system obtained by removing all the strict inequality constraints
    (resp., all the closure points).
    In contrast, when building a closed polyhedron starting from
    an object of the class NNC_Polyhedron,
    the precise topological closure test will be performed.
*/

class Parma_Polyhedra_Library::C_Polyhedron : public Polyhedron {
public:
  //! Builds either the universe or the empty C polyhedron.
  /*!
    \param num_dimensions
    The number of dimensions of the vector space enclosing the C polyhedron;

    \param kind
    Specifies whether a universe or an empty C polyhedron should be built.

    \exception std::length_error
    Thrown if \p num_dimensions exceeds the maximum allowed space dimension.

    Both parameters are optional:
    by default, a 0-dimension space universe C polyhedron is built.
  */
  explicit C_Polyhedron(dimension_type num_dimensions = 0,
			Degenerate_Element kind = UNIVERSE);

  //! Builds a C polyhedron from a system of constraints.
  /*!
    The polyhedron inherits the space dimension of the constraint system.

    \param cs
    The system of constraints defining the polyhedron.

    \exception std::invalid_argument
    Thrown if the system of constraints contains strict inequalities.
  */
  explicit C_Polyhedron(const Constraint_System& cs);

  //! Builds a C polyhedron recycling a system of constraints.
  /*!
    The polyhedron inherits the space dimension of the constraint system.

    \param cs
    The system of constraints defining the polyhedron.  It is not
    declared <CODE>const</CODE> because its data-structures will be
    recycled to build the polyhedron.

    \exception std::invalid_argument
    Thrown if the system of constraints contains strict inequalities.
  */
  explicit C_Polyhedron(Constraint_System& cs);

  //! Builds a C polyhedron from a system of generators.
  /*!
    The polyhedron inherits the space dimension of the generator system.

    \param gs
    The system of generators defining the polyhedron.

    \exception std::invalid_argument
    Thrown if the system of generators is not empty but has no points,
    or if it contains closure points.
  */
  explicit C_Polyhedron(const Generator_System& gs);

  //! Builds a C polyhedron recycling a system of generators.
  /*!
    The polyhedron inherits the space dimension of the generator system.

    \param gs
    The system of generators defining the polyhedron.  It is not
    declared <CODE>const</CODE> because its data-structures will be
    recycled to build the polyhedron.

    \exception std::invalid_argument
    Thrown if the system of generators is not empty but has no points,
    or if it contains closure points.
  */
  explicit C_Polyhedron(Generator_System& gs);

  //! Builds a C polyhedron from a system of congruences.
  /*!
    The polyhedron inherits the space dimension of the congruence system.

    \param cgs
    The system of congruences defining the polyhedron.  It is not
    declared <CODE>const</CODE> because its data-structures will be
    recycled to build the polyhedron.
  */
  explicit C_Polyhedron(const Congruence_System& cgs);

  //! Builds an C polyhedron recycling a system of congruences.
  /*!
    The polyhedron inherits the space dimension of the congruence
    system.

    \param cgs
    The system of congruences defining the polyhedron.  It is not
    declared <CODE>const</CODE> because its data-structures will be
    recycled to build the polyhedron.
  */
  explicit C_Polyhedron(Congruence_System& cgs);

  /*! \brief
    Builds a C polyhedron representing the topological closure
    of the NNC polyhedron \p y.
  */
  explicit C_Polyhedron(const NNC_Polyhedron& y);

  //! Builds a C polyhedron out of a generic, interval-based bounding box.
  /*!
    For a description of the methods that should be provided by
    the template class Box, see the documentation of the protected method:
      template \<typename Box\>
      Polyhedron::Polyhedron(Topology topol, const Box& box);

    \param box
    The bounding box representing the polyhedron to be built;

    \param dummy
    A dummy tag to syntactically differentiate this one from the other
    constructors.

    \exception std::length_error
    Thrown if the space dimension of \p box exceeds the maximum allowed
    space dimension.

    \exception std::invalid_argument
    Thrown if \p box has intervals that are not topologically closed
    (i.e., having some finite but open bounds).
  */
  template <typename Box>
  C_Polyhedron(const Box& box, From_Bounding_Box dummy);

  //! Ordinary copy-constructor.
  C_Polyhedron(const C_Polyhedron& y);

  /*! \brief
    The assignment operator.
    (\p *this and \p y can be dimension-incompatible.)
  */
  C_Polyhedron& operator=(const C_Polyhedron& y);

  //! Assigns to \p *this the topological closure of the NNC polyhedron \p y.
  C_Polyhedron& operator=(const NNC_Polyhedron& y);

  //! Destructor.
  ~C_Polyhedron();

  /*! \brief
    If the poly-hull of \p *this and \p y is exact it is assigned
    to \p *this and <CODE>true</CODE> is returned,
    otherwise <CODE>false</CODE> is returned.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  bool poly_hull_assign_if_exact(const C_Polyhedron& y);

  //! Same as poly_hull_assign_if_exact(y).
  bool upper_bound_assign_if_exact(const C_Polyhedron& y);
};

// Automatically generated from PPL source file ../src/C_Polyhedron.inlines.hh line 1
/* C_Polyhedron class implementation: inline functions.
*/


#include <algorithm>
#include <stdexcept>

namespace Parma_Polyhedra_Library {

inline
C_Polyhedron::C_Polyhedron(dimension_type num_dimensions,
			   Degenerate_Element kind)
  : Polyhedron(NECESSARILY_CLOSED,
	       num_dimensions <= max_space_dimension()
	       ? num_dimensions
	       : (throw_space_dimension_overflow(NECESSARILY_CLOSED,
						 "C_Polyhedron(n, k)",
						 "n exceeds the maximum "
						 "allowed space dimension"),
		  num_dimensions),
	       kind) {
}

inline
C_Polyhedron::C_Polyhedron(const Constraint_System& cs)
  : Polyhedron(NECESSARILY_CLOSED,
	       cs.space_dimension() <= max_space_dimension()
	       ? cs
	       : (throw_space_dimension_overflow(NECESSARILY_CLOSED,
						 "C_Polyhedron(cs)",
						 "the space dimension of cs "
						 "exceeds the maximum allowed "
						 "space dimension"), cs)) {
}

inline
C_Polyhedron::C_Polyhedron(Constraint_System& cs)
  : Polyhedron(NECESSARILY_CLOSED,
	       cs.space_dimension() <= max_space_dimension()
	       ? cs
	       : (throw_space_dimension_overflow(NECESSARILY_CLOSED,
						 "C_Polyhedron(cs)",
						 "the space dimension of cs "
						 "exceeds the maximum allowed "
						 "space dimension"), cs)) {
}

inline
C_Polyhedron::C_Polyhedron(const Generator_System& gs)
  : Polyhedron(NECESSARILY_CLOSED,
	       gs.space_dimension() <= max_space_dimension()
	       ? gs
	       : (throw_space_dimension_overflow(NECESSARILY_CLOSED,
						 "C_Polyhedron(cs)",
						 "the space dimension of gs "
						 "exceeds the maximum allowed "
						 "space dimension"), gs)){
}

inline
C_Polyhedron::C_Polyhedron(Generator_System& gs)
  : Polyhedron(NECESSARILY_CLOSED,
	       gs.space_dimension() <= max_space_dimension()
	       ? gs
	       : (throw_space_dimension_overflow(NECESSARILY_CLOSED,
						 "C_Polyhedron(cs)",
						 "the space dimension of gs "
						 "exceeds the maximum allowed "
						 "space dimension"), gs)){
}

template <typename Box>
inline
C_Polyhedron::C_Polyhedron(const Box& box, From_Bounding_Box)
  : Polyhedron(NECESSARILY_CLOSED,
	       box.space_dimension() <= max_space_dimension()
	       ? box
	       : (throw_space_dimension_overflow(NECESSARILY_CLOSED,
						 "C_Polyhedron(box): ",
						 "the space dimension of box "
						 "exceeds the maximum allowed "
						 "space dimension"), box)) {
}

inline
C_Polyhedron::C_Polyhedron(const C_Polyhedron& y)
  : Polyhedron(y) {
}

inline C_Polyhedron&
C_Polyhedron::operator=(const C_Polyhedron& y) {
  Polyhedron::operator=(y);
  return *this;
}

inline C_Polyhedron&
C_Polyhedron::operator=(const NNC_Polyhedron& y) {
  C_Polyhedron c_y(y);
  swap(c_y);
  return *this;
}

inline
C_Polyhedron::~C_Polyhedron() {
}

inline bool
C_Polyhedron::upper_bound_assign_if_exact(const C_Polyhedron& y) {
  return poly_hull_assign_if_exact(y);
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/C_Polyhedron.defs.hh line 212

// Automatically generated from PPL source file ../src/NNC_Polyhedron.defs.hh line 1
/* NNC_Polyhedron class declaration.
*/


// Automatically generated from PPL source file ../src/NNC_Polyhedron.defs.hh line 29

//! A not necessarily closed convex polyhedron.
/*! \ingroup PPL_CXX_interface
    An object of the class NNC_Polyhedron represents a
    <EM>not necessarily closed</EM> (NNC) convex polyhedron
    in the vector space \f$\Rset^n\f$.

    \note
    Since NNC polyhedra are a generalization of closed polyhedra,
    any object of the class C_Polyhedron can be (explicitly) converted
    into an object of the class NNC_Polyhedron.
    The reason for defining two different classes is that objects of
    the class C_Polyhedron are characterized by a more efficient
    implementation, requiring less time and memory resources.
*/
class Parma_Polyhedra_Library::NNC_Polyhedron : public Polyhedron {
public:
  //! Builds either the universe or the empty NNC polyhedron.
  /*!
    \param num_dimensions
    The number of dimensions of the vector space enclosing the NNC polyhedron;

    \param kind
    Specifies whether a universe or an empty NNC polyhedron should be built.

    \exception std::length_error
    Thrown if \p num_dimensions exceeds the maximum allowed space dimension.

    Both parameters are optional:
    by default, a 0-dimension space universe NNC polyhedron is built.
  */
  explicit NNC_Polyhedron(dimension_type num_dimensions = 0,
			  Degenerate_Element kind = UNIVERSE);

  //! Builds an NNC polyhedron from a system of constraints.
  /*!
    The polyhedron inherits the space dimension of the constraint system.

    \param cs
    The system of constraints defining the polyhedron.
  */
  explicit NNC_Polyhedron(const Constraint_System& cs);

  //! Builds an NNC polyhedron recycling a system of constraints.
  /*!
    The polyhedron inherits the space dimension of the constraint system.

    \param cs
    The system of constraints defining the polyhedron.  It is not
    declared <CODE>const</CODE> because its data-structures will be
    recycled to build the polyhedron.
  */
  explicit NNC_Polyhedron(Constraint_System& cs);

  //! Builds an NNC polyhedron from a system of generators.
  /*!
    The polyhedron inherits the space dimension of the generator system.

    \param gs
    The system of generators defining the polyhedron.

    \exception std::invalid_argument
    Thrown if the system of generators is not empty but has no points.
  */
  explicit NNC_Polyhedron(const Generator_System& gs);

  //! Builds an NNC polyhedron recycling a system of generators.
  /*!
    The polyhedron inherits the space dimension of the generator system.

    \param gs
    The system of generators defining the polyhedron.  It is not
    declared <CODE>const</CODE> because its data-structures will be
    recycled to build the polyhedron.

    \exception std::invalid_argument
    Thrown if the system of generators is not empty but has no points.
  */
  explicit NNC_Polyhedron(Generator_System& gs);

  //! Builds an NNC polyhedron from a system of congruences.
  /*!
    The polyhedron inherits the space dimension of the congruence system.

    \param cgs
    The system of congruences defining the polyhedron.  It is not
    declared <CODE>const</CODE> because its data-structures will be
    recycled to build the polyhedron.
  */
  explicit NNC_Polyhedron(const Congruence_System& cgs);

  //! Builds an NNC polyhedron recycling a system of congruences.
  /*!
    The polyhedron inherits the space dimension of the congruence
    system.

    \param cgs
    The system of congruences defining the polyhedron.  It is not
    declared <CODE>const</CODE> because its data-structures will be
    recycled to build the polyhedron.
  */
  explicit NNC_Polyhedron(Congruence_System& cgs);

  //! Builds an NNC polyhedron from the C polyhedron \p y.
  explicit NNC_Polyhedron(const C_Polyhedron& y);

  //! Builds an NNC polyhedron out of a generic, interval-based bounding box.
  /*!
    For a description of the methods that should be provided by
    the template class Box, see the documentation of the protected method:
      template \<typename Box\>
      Polyhedron::Polyhedron(Topology topol, const Box& box);

    \param box
    The bounding box representing the polyhedron to be built;

    \param dummy
    A dummy tag to syntactically differentiate this one from the other
    constructors.

    \exception std::length_error
    Thrown if the space dimension of \p box exceeds the maximum allowed
    space dimension.
  */
  template <typename Box>
  NNC_Polyhedron(const Box& box, From_Bounding_Box dummy);

  //! Ordinary copy-constructor.
  NNC_Polyhedron(const NNC_Polyhedron& y);

  /*! \brief
    The assignment operator.
    (\p *this and \p y can be dimension-incompatible.)
  */
  NNC_Polyhedron& operator=(const NNC_Polyhedron& y);

  //! Assigns to \p *this the C polyhedron \p y.
  NNC_Polyhedron& operator=(const C_Polyhedron& y);

  //! Destructor.
  ~NNC_Polyhedron();

  /*! \brief
    If the poly-hull of \p *this and \p y is exact it is assigned
    to \p *this and <CODE>true</CODE> is returned,
    otherwise <CODE>false</CODE> is returned.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  bool poly_hull_assign_if_exact(const NNC_Polyhedron& y);

  //! Same as poly_hull_assign_if_exact(y).
  bool upper_bound_assign_if_exact(const NNC_Polyhedron& y);
};

// Automatically generated from PPL source file ../src/NNC_Polyhedron.inlines.hh line 1
/* NNC_Polyhedron class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/NNC_Polyhedron.inlines.hh line 27

namespace Parma_Polyhedra_Library {

inline
NNC_Polyhedron::NNC_Polyhedron(dimension_type num_dimensions,
			       Degenerate_Element kind)
  : Polyhedron(NOT_NECESSARILY_CLOSED,
	       num_dimensions <= max_space_dimension()
	       ? num_dimensions
	       : (throw_space_dimension_overflow(NOT_NECESSARILY_CLOSED,
						 "NNC_Polyhedron(n, k)",
						 "n exceeds the maximum "
						 "allowed space dimension"),
		  num_dimensions),
	       kind) {
}

inline
NNC_Polyhedron::NNC_Polyhedron(const Constraint_System& cs)
  : Polyhedron(NOT_NECESSARILY_CLOSED,
	       cs.space_dimension() <= max_space_dimension()
	       ? cs
	       : (throw_space_dimension_overflow(NOT_NECESSARILY_CLOSED,
						 "NNC_Polyhedron(cs)",
						 "the space dimension of cs "
						 "exceeds the maximum allowed "
						 "space dimension"), cs)) {
}

inline
NNC_Polyhedron::NNC_Polyhedron(Constraint_System& cs)
  : Polyhedron(NOT_NECESSARILY_CLOSED,
	       cs.space_dimension() <= max_space_dimension()
	       ? cs
	       : (throw_space_dimension_overflow(NOT_NECESSARILY_CLOSED,
						 "NNC_Polyhedron(cs)",
						 "the space dimension of cs "
						 "exceeds the maximum allowed "
						 "space dimension"), cs)) {
}

inline
NNC_Polyhedron::NNC_Polyhedron(const Generator_System& gs)
  : Polyhedron(NOT_NECESSARILY_CLOSED,
	       gs.space_dimension() <= max_space_dimension()
	       ? gs
	       : (throw_space_dimension_overflow(NOT_NECESSARILY_CLOSED,
						 "NNC_Polyhedron(gs)",
						 "the space dimension of gs "
						 "exceeds the maximum allowed "
						 "space dimension"), gs)) {
}

inline
NNC_Polyhedron::NNC_Polyhedron(Generator_System& gs)
  : Polyhedron(NOT_NECESSARILY_CLOSED,
	       gs.space_dimension() <= max_space_dimension()
	       ? gs
	       : (throw_space_dimension_overflow(NOT_NECESSARILY_CLOSED,
						 "NNC_Polyhedron(gs)",
						 "the space dimension of gs "
						 "exceeds the maximum allowed "
						 "space dimension"), gs)) {
}

template <typename Box>
inline
NNC_Polyhedron::NNC_Polyhedron(const Box& box, From_Bounding_Box)
  : Polyhedron(NOT_NECESSARILY_CLOSED,
	       box.space_dimension() <= max_space_dimension()
	       ? box
	       : (throw_space_dimension_overflow(NOT_NECESSARILY_CLOSED,
						 "NNC_Polyhedron(box)",
						 "the space dimension of box "
						 "exceeds the maximum allowed "
						 "space dimension"), box)) {
}

inline
NNC_Polyhedron::NNC_Polyhedron(const NNC_Polyhedron& y)
  : Polyhedron(y) {
}

inline NNC_Polyhedron&
NNC_Polyhedron::operator=(const NNC_Polyhedron& y) {
  Polyhedron::operator=(y);
  return *this;
}

inline NNC_Polyhedron&
NNC_Polyhedron::operator=(const C_Polyhedron& y) {
  NNC_Polyhedron nnc_y(y);
  swap(nnc_y);
  return *this;
}

inline
NNC_Polyhedron::~NNC_Polyhedron() {
}

inline bool
NNC_Polyhedron::upper_bound_assign_if_exact(const NNC_Polyhedron& y) {
  return poly_hull_assign_if_exact(y);
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/NNC_Polyhedron.defs.hh line 186

// Automatically generated from PPL source file ../src/Widening_Function.types.hh line 1


namespace Parma_Polyhedra_Library {

template <typename PH>
class Widening_Function;

template <typename PH, typename CS>
class Limited_Widening_Function;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Widening_Function.defs.hh line 1
/* Widening_Function class declaration.
*/


// Automatically generated from PPL source file ../src/Widening_Function.defs.hh line 28

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Wraps a widening method into a function object.
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename PH>
class Parma_Polyhedra_Library::Widening_Function {
public:
  //! The (parametric) type of a widening method.
  typedef void (PH::* Widening_Method)(const PH&, unsigned*);

  //! Explicit unary constructor.
  explicit
  Widening_Function(Widening_Method wm);

  //! Function-application operator.
  /*!
    Computes <CODE>(x.*wm)(y, tp)</CODE>, where \p wm is the widening
    method stored at construction time.
  */
  void operator()(PH& x, const PH& y, unsigned* tp = 0) const;

private:
  //! The widening method.
  Widening_Method w_method;
};


#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Wraps a limited widening method into a function object.
/*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename PH, typename CS>
class Parma_Polyhedra_Library::Limited_Widening_Function {
public:
  //! The (parametric) type of a limited widening method.
  typedef void (PH::* Limited_Widening_Method)(const PH&,
					       const CS&,
					       unsigned*);

  //! Constructor.
  /*!
    \param lwm
    The limited widening method.

    \param cs
    The constraint system limiting the widening.
  */
  Limited_Widening_Function(Limited_Widening_Method lwm,
			    const CS& cs);

  //! Function-application operator.
  /*!
    Computes <CODE>(x.*lwm)(y, cs, tp)</CODE>, where \p lwm and \p cs
    are the limited widening method and the constraint system stored
    at construction time.
  */
  void operator()(PH& x, const PH& y, unsigned* tp = 0) const;

private:
  //! The limited widening method.
  Limited_Widening_Method lw_method;
  //! A constant reference to the constraint system limiting the widening.
  const CS& limiting_cs;
};

namespace Parma_Polyhedra_Library {

//! Wraps a widening method into a function object.
/*!
  \relates Polyhedra_Powerset

  \param wm
  The widening method.
*/
template <typename PH>
Widening_Function<PH>
widen_fun_ref(void (PH::* wm)(const PH&, unsigned*));

//! Wraps a limited widening method into a function object.
/*!
  \relates Polyhedra_Powerset

  \param lwm
  The limited widening method.

  \param cs
  The constraint system limiting the widening.
*/
template <typename PH, typename CS>
Limited_Widening_Function<PH, CS>
widen_fun_ref(void (PH::* lwm)(const PH&, const CS&, unsigned*),
	      const CS& cs);

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Widening_Function.inlines.hh line 1
/* Widening_Function class implementation: inline functions.
*/


#include <cassert>

namespace Parma_Polyhedra_Library {

template <typename PH>
Widening_Function<PH>::Widening_Function(Widening_Method wm)
  : w_method(wm) {
}

template <typename PH>
inline void
Widening_Function<PH>::
operator()(PH& x, const PH& y, unsigned* tp) const {
  (x.*w_method)(y, tp);
}

template <typename PH, typename CS>
Limited_Widening_Function<PH, CS>::
Limited_Widening_Function(Limited_Widening_Method lwm,
			  const CS& cs)
  : lw_method(lwm), limiting_cs(cs) {
}

template <typename PH, typename CS>
inline void
Limited_Widening_Function<PH, CS>::
operator()(PH& x, const PH& y, unsigned* tp) const {
  (x.*lw_method)(y, limiting_cs, tp);
}

/*! \relates Polyhedra_Powerset */
template <typename PH>
inline Widening_Function<PH>
widen_fun_ref(void (PH::* wm)(const PH&, unsigned*)) {
  return Widening_Function<PH>(wm);
}

/*! \relates Polyhedra_Powerset */
template <typename PH, typename CS>
inline Limited_Widening_Function<PH, CS>
widen_fun_ref(void (PH::* lwm)(const PH&, const CS&, unsigned*),
	      const CS& cs) {
  return Limited_Widening_Function<PH, CS>(lwm, cs);
}

} // namespace Parma_Polyhedra_Library


// Automatically generated from PPL source file ../src/Widening_Function.defs.hh line 125

// Automatically generated from PPL source file ../src/Ptr_Iterator.defs.hh line 1
/* Ptr_Iterator class declaration.
*/


// Automatically generated from PPL source file ../src/Ptr_Iterator.defs.hh line 27
#include <iterator>

namespace Parma_Polyhedra_Library {

namespace Implementation {

template<typename Q, typename R>
bool operator==(const Ptr_Iterator<Q>& x, const Ptr_Iterator<R>& y);

template<typename Q, typename R>
bool operator!=(const Ptr_Iterator<Q>& x, const Ptr_Iterator<R>& y);

template<typename Q, typename R>
bool operator<(const Ptr_Iterator<Q>& x, const Ptr_Iterator<R>& y);

template<typename Q, typename R>
bool operator<=(const Ptr_Iterator<Q>& x, const Ptr_Iterator<R>& y);

template<typename Q, typename R>
bool operator>(const Ptr_Iterator<Q>& x, const Ptr_Iterator<R>& y);

template<typename Q, typename R>
bool operator>=(const Ptr_Iterator<Q>& x, const Ptr_Iterator<R>& y);

template<typename Q, typename R>
typename Ptr_Iterator<Q>::difference_type operator-(const Ptr_Iterator<Q>& x,
						    const Ptr_Iterator<R>& y);

template<typename P>
Ptr_Iterator<P> operator+(typename Ptr_Iterator<P>::difference_type m,
			  const Ptr_Iterator<P>& y);

} // namespace Implementation

} // namespace Parma_Polyhedra_Library

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A class to define STL const and non-const iterators from pointer types.
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename P>
class Parma_Polyhedra_Library::Implementation::Ptr_Iterator
  : public std::iterator<typename std::iterator_traits<P>::iterator_category,
			 typename std::iterator_traits<P>::value_type,
			 typename std::iterator_traits<P>::difference_type,
			 typename std::iterator_traits<P>::pointer,
			 typename std::iterator_traits<P>::reference> {
public:
  typedef typename std::iterator_traits<P>::difference_type difference_type;
  typedef typename std::iterator_traits<P>::reference reference;
  typedef typename std::iterator_traits<P>::pointer pointer;

  //! Default constructor: no guarantees.
  Ptr_Iterator();

  //! Construct an iterator pointing at \p q.
  explicit Ptr_Iterator(const P& q);

  /*! \brief
    Copy-constructor allowing the construction of a const_iterator
    from a non-const iterator.
  */
  template<typename Q>
  Ptr_Iterator(const Ptr_Iterator<Q>& q);

  //! Dereference operator.
  reference operator*() const;

  //! Indirect member selector.
  pointer operator->() const;

  //! Subscript operator.
  reference operator[](const difference_type m) const;

  //! Prefix increment operator.
  Ptr_Iterator& operator++();

  //! Postfix increment operator.
  Ptr_Iterator operator++(int);

  //! Prefix decrement operator
  Ptr_Iterator& operator--();

  //! Postfix decrement operator.
  Ptr_Iterator operator--(int);

  //! Assignment-increment operator.
  Ptr_Iterator& operator+=(const difference_type m);

  //! Assignment-decrement operator.
  Ptr_Iterator& operator-=(const difference_type m);

  //! Returns the difference between \p *this and \p y.
  difference_type operator-(const Ptr_Iterator& y) const;

  //! Returns the sum of \p *this and \p m.
  Ptr_Iterator operator+(const difference_type m) const;

  //! Returns the difference of \p *this and \p m.
  Ptr_Iterator operator-(const difference_type m) const;

private:
  //! The base pointer implementing the iterator.
  P p;

  //! Returns the hidden pointer.
  const P& base() const;

  template <typename Q, typename R>
  friend bool Parma_Polyhedra_Library::Implementation::
  operator==(const Ptr_Iterator<Q>& x, const Ptr_Iterator<R>& y);

  template <typename Q, typename R>
  friend bool Parma_Polyhedra_Library::Implementation::
  operator!=(const Ptr_Iterator<Q>& x, const Ptr_Iterator<R>& y);

  template<typename Q, typename R>
  friend bool Parma_Polyhedra_Library::Implementation::
  operator<(const Ptr_Iterator<Q>& x, const Ptr_Iterator<R>& y);

  template<typename Q, typename R>
  friend bool Parma_Polyhedra_Library::Implementation::
  operator<=(const Ptr_Iterator<Q>& x, const Ptr_Iterator<R>& y);

  template<typename Q, typename R>
  friend bool Parma_Polyhedra_Library::Implementation::
  operator>(const Ptr_Iterator<Q>& x, const Ptr_Iterator<R>& y);

  template<typename Q, typename R>
  friend bool Parma_Polyhedra_Library::Implementation::
  operator>=(const Ptr_Iterator<Q>& x, const Ptr_Iterator<R>& y);

  template<typename Q, typename R>
  friend typename Ptr_Iterator<Q>::difference_type
  Parma_Polyhedra_Library::Implementation::
  operator-(const Ptr_Iterator<Q>& x, const Ptr_Iterator<R>& y);

  friend Ptr_Iterator<P>
  Parma_Polyhedra_Library::Implementation::
  operator+<>(typename Ptr_Iterator<P>::difference_type m,
	      const Ptr_Iterator<P>& y);
};

// Automatically generated from PPL source file ../src/Ptr_Iterator.inlines.hh line 1
/* Ptr_Iterator class implementation: inline functions.
*/


#include <algorithm>
#include <cassert>

namespace Parma_Polyhedra_Library {

namespace Implementation {

template <typename P>
inline const P&
Ptr_Iterator<P>::base() const {
  return p;
}

template <typename P>
inline
Ptr_Iterator<P>::Ptr_Iterator()
  : p(P()) {
}

template <typename P>
inline
Ptr_Iterator<P>::Ptr_Iterator(const P& q)
  : p(q) {
}

template <typename P>
template <typename Q>
inline
Ptr_Iterator<P>::Ptr_Iterator(const Ptr_Iterator<Q>& y)
  : p(y.base()) {
}

template <typename P>
inline typename Ptr_Iterator<P>::reference
Ptr_Iterator<P>::operator*() const {
  return *p;
}

template <typename P>
inline typename Ptr_Iterator<P>::pointer
Ptr_Iterator<P>::operator->() const {
  return p;
}

template <typename P>
inline typename Ptr_Iterator<P>::reference
Ptr_Iterator<P>::operator[](const difference_type m) const {
  return p[m];
}

template <typename P>
inline Ptr_Iterator<P>&
Ptr_Iterator<P>::operator++() {
  ++p;
  return *this;
}

template <typename P>
inline Ptr_Iterator<P>
Ptr_Iterator<P>::operator++(int) {
  return Ptr_Iterator(p++);
}

template <typename P>
inline Ptr_Iterator<P>&
Ptr_Iterator<P>::operator--() {
  --p;
  return *this;
}

template <typename P>
inline Ptr_Iterator<P>
Ptr_Iterator<P>::operator--(int) {
  return Ptr_Iterator(p--);
}


template <typename P>
inline Ptr_Iterator<P>&
Ptr_Iterator<P>::operator+=(const difference_type m) {
  p += m;
  return *this;
}

template <typename P>
inline Ptr_Iterator<P>&
Ptr_Iterator<P>::operator-=(const difference_type m) {
  p -= m;
  return *this;
}

template <typename P>
inline typename Ptr_Iterator<P>::difference_type
Ptr_Iterator<P>::operator-(const Ptr_Iterator& y) const {
  return p - y.p;
}

template <typename P>
inline Ptr_Iterator<P>
Ptr_Iterator<P>::operator+(const difference_type m) const {
  return Ptr_Iterator(p + m);
}

template <typename P>
inline Ptr_Iterator<P>
Ptr_Iterator<P>::operator-(const difference_type m) const {
  return Ptr_Iterator(p - m);
}

template<typename P, typename Q>
inline bool
operator==(const Ptr_Iterator<P>& x, const Ptr_Iterator<Q>& y) {
  return x.base() == y.base();
}

template<typename P, typename Q>
inline bool
operator!=(const Ptr_Iterator<P>& x, const Ptr_Iterator<Q>& y) {
  return x.base() != y.base();
}

template<typename P, typename Q>
inline bool
operator<(const Ptr_Iterator<P>& x, const Ptr_Iterator<Q>& y) {
  return x.base() < y.base();
}

template<typename P, typename Q>
inline bool
operator<=(const Ptr_Iterator<P>& x, const Ptr_Iterator<Q>& y) {
  return x.base() <= y.base();
}

template<typename P, typename Q>
inline bool
operator>(const Ptr_Iterator<P>& x, const Ptr_Iterator<Q>& y) {
  return x.base() > y.base();
}

template<typename P, typename Q>
inline bool
operator>=(const Ptr_Iterator<P>& x, const Ptr_Iterator<Q>& y) {
  return x.base() >= y.base();
}

template<typename P, typename Q>
inline typename Ptr_Iterator<P>::difference_type
operator-(const Ptr_Iterator<P>& x, const Ptr_Iterator<Q>& y) {
  return x.base() - y.base();
}

template<typename P>
inline Ptr_Iterator<P>
operator+(typename Ptr_Iterator<P>::difference_type m,
	  const Ptr_Iterator<P>& y) {
  return Ptr_Iterator<P>(m + y.base());
}

} // namespace Implementation

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Ptr_Iterator.defs.hh line 170

// Automatically generated from PPL source file ../src/DB_Row.defs.hh line 1
/* DB_Row class declaration.
*/


// Automatically generated from PPL source file ../src/DB_Row.defs.hh line 29
#include <cstddef>
#include <vector>

#ifndef EXTRA_ROW_DEBUG
#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  When EXTRA_ROW_DEBUG evaluates to <CODE>true</CODE>, each instance
  of the class DB_Row carries its own capacity; this enables extra
  consistency checks to be performed.
  \ingroup PPL_CXX_interface
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
#define EXTRA_ROW_DEBUG 0
#endif


#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! The handler of the actual DB_Row implementation.
/*! \ingroup PPL_CXX_interface
  Exception-safety is the only responsibility of this class: it has
  to ensure that its \p impl member is correctly deallocated.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename T>
class Parma_Polyhedra_Library::DB_Row_Impl_Handler {
public:
  //! Default constructor.
  DB_Row_Impl_Handler();

  //! Destructor.
  ~DB_Row_Impl_Handler();

  class Impl;

  //! A pointer to the actual implementation.
  Impl* impl;

#if EXTRA_ROW_DEBUG
  //! The capacity of \p impl (only available during debugging).
  dimension_type capacity_;
#endif // EXTRA_ROW_DEBUG

private:
  //! Private and unimplemented: copy construction is not allowed.
  DB_Row_Impl_Handler(const DB_Row_Impl_Handler&);

  //! Private and unimplemented: copy assignment is not allowed.
  DB_Row_Impl_Handler& operator=(const DB_Row_Impl_Handler&);
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! The base class for the single rows of matrices.
/*! \ingroup PPL_CXX_interface
  The class template DB_Row<T> allows for the efficient representation of
  the single rows of a DB_Matrix. It contains elements of type T stored
  as a vector. The class T is a family of extended numbers that
  must provide representation for
  \f$ -\infty \f$, \f$0\f$,\f$ +\infty \f$ (and, consequently for <EM>nan</EM>,
  <EM>not a number</EM>, since this arises as the ``result'' of
  undefined sums like \f$ +\infty + (-\infty) \f$).

  The class T must provide the following methods:

  \code
    T()
  \endcode
  is the default constructor: no assumption is made on the particular
  object constructed, provided <CODE>T().OK()</CODE> gives <CODE>true</CODE>
  (see below).
  \code
    ~T()
  \endcode
  is the destructor.
  \code
    bool is_nan() const
  \endcode
  returns <CODE>true</CODE> if and only \p *this represents
  the  <EM>not a number</EM> value.
  \code
    bool OK() const
  \endcode
  returns <CODE>true</CODE> if and only if \p *this satisfies all
  its invariants.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename T>
class Parma_Polyhedra_Library::DB_Row : private DB_Row_Impl_Handler<T> {
public:
  //! Pre-constructs a row: construction must be completed by construct().
  DB_Row();

  //! \name Post-constructors.
  //@{
  //! Constructs properly a default-constructed element.
  /*!
    Builds a row with size \p sz and minimum capacity.
  */
  void construct(dimension_type sz);

  //! Constructs properly a default-constructed element.
  /*!
    \param sz
    The size of the row that will be constructed.

    \param capacity
    The minimum capacity of the row that will be constructed.

    The row that we are constructing has a minimum capacity of
    (i.e., it can contain at least) \p elements, \p sz of which
    will be constructed now.
  */
  void construct(dimension_type sz, dimension_type capacity);

  //! Constructs properly a conservative approximation of \p y.
  /*!
    \param y
    A row containing the elements whose upward approximations will
    be used to properly construct \p *this.

    \param capacity
    The capacity of the constructed row.

    It is assumed that \p capacity is greater than or equal to the
    size of \p y.
  */
  template <typename U>
  void construct_upward_approximation(const DB_Row<U>& y,
				      dimension_type capacity);

  //@}

  //! Tight constructor: resizing will require reallocation.
  DB_Row(dimension_type sz);

  //! Sizing constructor with capacity.
  DB_Row(dimension_type sz, dimension_type capacity);

  //! Ordinary copy constructor.
  DB_Row(const DB_Row& y);

  //! Copy constructor with specified capacity.
  /*!
    It is assumed that \p capacity is greater than or equal to \p y size.
  */
  DB_Row(const DB_Row& y, dimension_type capacity);

  //! Copy constructor with specified size and capacity.
  /*!
    It is assumed that \p sz is greater than or equal to the size of \p y
    and, of course, that \p sz is less than or equal to \p capacity.
    Any new position is initialized to \f$+\infty\f$.
  */
  DB_Row(const DB_Row& y, dimension_type sz, dimension_type capacity);

  //! Destructor.
  ~DB_Row();

  //! Assignment operator.
  DB_Row& operator=(const DB_Row& y);

  //! Swaps \p *this with \p y.
  void swap(DB_Row& y);

  //! Assigns the implementation of \p y to \p *this.
  void assign(DB_Row& y);

  /*! \brief
    Allocates memory for a default constructed DB_Row object,
    allowing for \p capacity coefficients at most.

    It is assumed that no allocation has been performed before
    (otherwise, a memory leak will occur).
    After execution, the size of the DB_Row object is zero.
  */
  void allocate(dimension_type capacity);

  //! Expands the row to size \p new_size.
  /*!
    Adds new positions to the implementation of the row
    obtaining a new row with size \p new_size.
    It is assumed that \p new_size is between the current size
    and capacity of the row. The new positions are initialized
    to \f$+\infty\f$.
  */
  void expand_within_capacity(dimension_type new_size);

  //! Shrinks the row by erasing elements at the end.
  /*!
    Destroys elements of the row implementation
    from position \p new_size to the end.
    It is assumed that \p new_size is not greater than the current size.
  */
  void shrink(dimension_type new_size);

  //! Returns the size() of the largest possible DB_Row.
  static dimension_type max_size();

  //! Gives the number of coefficients currently in use.
  dimension_type size() const;

  //! \name Subscript operators.
  //@{
  //! Returns a reference to the element of the row indexed by \p k.
  T& operator[](dimension_type k);

  //! Returns a constant reference to the element of the row indexed by \p k.
  const T& operator[](dimension_type k) const;
  //@}

  //! A (non const) random access iterator to access the row's elements.
  typedef Implementation::Ptr_Iterator<T*> iterator;

  //! A const random access iterator to access the row's elements.
  typedef Implementation::Ptr_Iterator<const T*> const_iterator;

  /*! \brief
    Returns the const iterator pointing to the first element,
    if \p *this is not empty;
    otherwise, returns the past-the-end const iterator.
  */
  iterator begin();

  //! Returns the past-the-end iterator.
  iterator end();

  /*! \brief
    Returns the const iterator pointing to the first element,
    if \p *this is not empty;
    otherwise, returns the past-the-end const iterator.
  */
  const_iterator begin() const;

  //! Returns the past-the-end const iterator.
  const_iterator end() const;

  //! Checks if all the invariants are satisfied.
  bool OK(dimension_type row_size, dimension_type row_capacity) const;

private:
  template <typename U> friend class Parma_Polyhedra_Library::DB_Row;

  //! Exception-safe copy construction mechanism for coefficients.
  void copy_construct_coefficients(const DB_Row& y);

#if EXTRA_ROW_DEBUG
  //! Returns the capacity of the row (only available during debugging).
  dimension_type capacity() const;
#endif // defined(EXTRA_ROW_DEBUG)
};

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! \name Classical comparison operators.
//@{
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates DB_Row */
template <typename T>
bool operator==(const DB_Row<T>& x, const DB_Row<T>& y);

/*! \relates DB_Row */
template <typename T>
bool operator!=(const DB_Row<T>& x, const DB_Row<T>& y);
#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//@}
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS

} // namespace Parma_Polyhedra_Library


#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! The real implementation of a DB_Row object.
/*! \ingroup PPL_CXX_interface
  The class DB_Row_Impl_Handler::Impl provides the implementation of
  DB_Row objects and, in particular, of the corresponding memory
  allocation functions.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename T>
class Parma_Polyhedra_Library::DB_Row_Impl_Handler<T>::Impl {
public:
  //! \name Custom allocator and deallocator.
  //@{

  /*! \brief
    Allocates a chunk of memory able to contain \p capacity T objects
    beyond the specified \p fixed_size and returns a pointer to the new
    allocated memory.
  */
  static void* operator new(size_t fixed_size, dimension_type capacity);

  //! Uses the standard delete operator to free the memory \p p points to.
  static void operator delete(void* p);

  /*! \brief
    Placement version: uses the standard operator delete to free
    the memory \p p points to.
  */
  static void operator delete(void* p, dimension_type capacity);
  //@}

  //! Default constructor.
  Impl();

  //! Destructor.
  /*!
    Uses <CODE>shrink()</CODE> method with argument \f$0\f$
    to delete all the row elements.
  */
  ~Impl();

  //! Expands the row to size \p new_size.
  /*!
    It is assumed that \p new_size is between the current size and capacity.
  */
  void expand_within_capacity(dimension_type new_size);

  //! Shrinks the row by erasing elements at the end.
  /*!
    It is assumed that \p new_size is not greater than the current size.
  */
  void shrink(dimension_type new_size);

  //! Exception-safe copy construction mechanism for coefficients.
  void copy_construct_coefficients(const Impl& y);

  /*! \brief
    Exception-safe upward approximation construction mechanism
    for coefficients.
  */
  template <typename U>
  void construct_upward_approximation(const U& y);

  //! Returns the size() of the largest possible Impl.
  static dimension_type max_size();

  //! \name Size accessors.
  //@{
  //! Returns the actual size of \p this.
  dimension_type size() const;

  //! Sets to \p new_sz the actual size of \p *this.
  void set_size(dimension_type new_sz);

  //! Increments the size of \p *this by 1.
  void bump_size();
  //@}

  //! \name Subscript operators.
  //@{
  //! Returns a reference to the element of \p *this indexed by \p k.
  T& operator[](dimension_type k);

  //! Returns a constant reference to the element of \p *this indexed by \p k.
  const T& operator[](dimension_type k) const;
  //@}

private:
  //! The number of coefficients in the row.
  dimension_type size_;

  //! The vector of coefficients.
  T vec_[
#if !CXX_SUPPORTS_FLEXIBLE_ARRAYS
	       1
#endif
  ];

  //! Private and unimplemented: copy construction is not allowed.
  Impl(const Impl& y);

  //! Private and unimplemented: assignment is not allowed.
  Impl& operator=(const Impl&);

  //! Exception-safe copy construction mechanism.
  void copy_construct(const Impl& y);
};

namespace std {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::DB_Row */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename T>
void swap(Parma_Polyhedra_Library::DB_Row<T>& x,
	  Parma_Polyhedra_Library::DB_Row<T>& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Specializes <CODE>std::iter_swap</CODE>.
/*! \relates Parma_Polyhedra_Library::DB_Row */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename T>
void iter_swap(typename std::vector<Parma_Polyhedra_Library::DB_Row<T> >
	       ::iterator x,
	       typename std::vector<Parma_Polyhedra_Library::DB_Row<T> >
	       ::iterator y);

} // namespace std

// Automatically generated from PPL source file ../src/DB_Row.inlines.hh line 1
/* DB_Row class implementation: inline functions.
*/


#include <cassert>
#include <algorithm>
#include <iostream>
// Automatically generated from PPL source file ../src/DB_Row.inlines.hh line 30

namespace Parma_Polyhedra_Library {

template <typename T>
inline void*
DB_Row_Impl_Handler<T>::Impl::operator new(const size_t fixed_size,
					   const dimension_type capacity) {
#if CXX_SUPPORTS_FLEXIBLE_ARRAYS
  return ::operator new(fixed_size + capacity*sizeof(T));
#else
  assert(capacity >= 1);
  return ::operator new(fixed_size + (capacity-1)*sizeof(T));
#endif
}

template <typename T>
inline void
DB_Row_Impl_Handler<T>::Impl::operator delete(void* p) {
  ::operator delete(p);
}

template <typename T>
inline void
DB_Row_Impl_Handler<T>::Impl::operator delete(void* p, dimension_type) {
  ::operator delete(p);
}

template <typename T>
inline dimension_type
DB_Row_Impl_Handler<T>::Impl::max_size() {
  return size_t(-1)/sizeof(T);
}

template <typename T>
inline dimension_type
DB_Row_Impl_Handler<T>::Impl::size() const {
  return size_;
}

template <typename T>
inline void
DB_Row_Impl_Handler<T>::Impl::set_size(const dimension_type new_sz) {
  size_ = new_sz;
}

template <typename T>
inline void
DB_Row_Impl_Handler<T>::Impl::bump_size() {
  ++size_;
}

template <typename T>
inline
DB_Row_Impl_Handler<T>::Impl::Impl()
  : size_(0) {
}

template <typename T>
inline
DB_Row_Impl_Handler<T>::Impl::~Impl() {
  shrink(0);
}

template <typename T>
inline
DB_Row_Impl_Handler<T>::DB_Row_Impl_Handler()
  : impl(0) {
#if EXTRA_ROW_DEBUG
  capacity_ = 0;
#endif
}

template <typename T>
template <typename U>
void
DB_Row_Impl_Handler<T>::Impl::construct_upward_approximation(const U& y) {
  const dimension_type y_size = y.size();
#if CXX_SUPPORTS_FLEXIBLE_ARRAYS
  // Construct in direct order: will destroy in reverse order.
  for (dimension_type i = 0; i < y_size; ++i) {
    construct(vec_[i], y[i], ROUND_UP);
    bump_size();
  }
#else
  assert(y_size > 0);
  if (y_size > 0) {
    vec_[0] = y[0];
    bump_size();
    // Construct in direct order: will destroy in reverse order.
    for (dimension_type i = 1; i < y_size; ++i) {
      construct(vec_[i], y[i], ROUND_UP);
      bump_size();
    }
  }
#endif
}

template <typename T>
inline
DB_Row_Impl_Handler<T>::~DB_Row_Impl_Handler() {
  delete impl;
}

template <typename T>
inline T&
DB_Row_Impl_Handler<T>::Impl::operator[](const dimension_type k) {
  assert(k < size());
  return vec_[k];
}

template <typename T>
inline const T&
DB_Row_Impl_Handler<T>::Impl::operator[](const dimension_type k) const {
  assert(k < size());
  return vec_[k];
}

template <typename T>
inline dimension_type
DB_Row<T>::max_size() {
  return DB_Row_Impl_Handler<T>::Impl::max_size();
}

template <typename T>
inline dimension_type
DB_Row<T>::size() const {
  return this->impl->size();
}

#if EXTRA_ROW_DEBUG
template <typename T>
inline dimension_type
DB_Row<T>::capacity() const {
  return this->capacity_;
}
#endif // EXTRA_ROW_DEBUG

template <typename T>
inline
DB_Row<T>::DB_Row()
  : DB_Row_Impl_Handler<T>() {
}

template <typename T>
inline void
DB_Row<T>::allocate(
#if CXX_SUPPORTS_FLEXIBLE_ARRAYS
	       const
#endif
	       dimension_type capacity) {
  DB_Row<T>& x = *this;
  assert(capacity <= max_size());
#if !CXX_SUPPORTS_FLEXIBLE_ARRAYS
  if (capacity == 0)
    ++capacity;
#endif
  assert(x.impl == 0);
  x.impl = new (capacity) typename DB_Row_Impl_Handler<T>::Impl();
#if EXTRA_ROW_DEBUG
  assert(x.capacity_ == 0);
  x.capacity_ = capacity;
#endif
}

template <typename T>
inline void
DB_Row<T>::expand_within_capacity(const dimension_type new_size) {
  DB_Row<T>& x = *this;
  assert(x.impl);
#if EXTRA_ROW_DEBUG
  assert(new_size <= x.capacity_);
#endif
  x.impl->expand_within_capacity(new_size);
}

template <typename T>
inline void
DB_Row<T>::copy_construct_coefficients(const DB_Row& y) {
  DB_Row<T>& x = *this;
  assert(x.impl && y.impl);
#if EXTRA_ROW_DEBUG
  assert(y.size() <= x.capacity_);
#endif
  x.impl->copy_construct_coefficients(*(y.impl));
}

template <typename T>
template <typename U>
inline void
DB_Row<T>::construct_upward_approximation(const DB_Row<U>& y,
					  const dimension_type capacity) {
  DB_Row<T>& x = *this;
  assert(y.size() <= capacity && capacity <= max_size());
  allocate(capacity);
  assert(y.impl);
  x.impl->construct_upward_approximation(*(y.impl));
}

template <typename T>
inline void
DB_Row<T>::construct(const dimension_type sz,
		     const dimension_type capacity) {
  assert(sz <= capacity && capacity <= max_size());
  allocate(capacity);
  expand_within_capacity(sz);
}

template <typename T>
inline void
DB_Row<T>::construct(const dimension_type sz) {
  construct(sz, sz);
}

template <typename T>
inline
DB_Row<T>::DB_Row(const dimension_type sz,
		  const dimension_type capacity)
  : DB_Row_Impl_Handler<T>() {
  construct(sz, capacity);
}

template <typename T>
inline
DB_Row<T>::DB_Row(const dimension_type sz) {
  construct(sz);
}

template <typename T>
inline
DB_Row<T>::DB_Row(const DB_Row& y)
  : DB_Row_Impl_Handler<T>() {
  if (y.impl) {
    allocate(compute_capacity(y.size(), max_size()));
    copy_construct_coefficients(y);
  }
}

template <typename T>
inline
DB_Row<T>::DB_Row(const DB_Row& y,
		  const	dimension_type capacity)
  : DB_Row_Impl_Handler<T>() {
  assert(y.impl);
  assert(y.size() <= capacity && capacity <= max_size());
  allocate(capacity);
  copy_construct_coefficients(y);
}

template <typename T>
inline
DB_Row<T>::DB_Row(const DB_Row& y,
		  const dimension_type sz,
		  const	dimension_type capacity)
  : DB_Row_Impl_Handler<T>() {
  assert(y.impl);
  assert(y.size() <= sz && sz <= capacity && capacity <= max_size());
  allocate(capacity);
  copy_construct_coefficients(y);
  expand_within_capacity(sz);
}

template <typename T>
inline
DB_Row<T>::~DB_Row() {
}

template <typename T>
inline void
DB_Row<T>::shrink(const dimension_type new_size) {
  DB_Row<T>& x = *this;
  assert(x.impl);
  x.impl->shrink(new_size);
}

template <typename T>
inline void
DB_Row<T>::swap(DB_Row& y) {
  DB_Row<T>& x = *this;
  std::swap(x.impl, y.impl);
#if EXTRA_ROW_DEBUG
  std::swap(x.capacity_, y.capacity_);
#endif
}

template <typename T>
inline void
DB_Row<T>::assign(DB_Row& y) {
  DB_Row<T>& x = *this;
  x.impl = y.impl;
#if EXTRA_ROW_DEBUG
  x.capacity_ = y.capacity_;
#endif
}

template <typename T>
inline DB_Row<T>&
DB_Row<T>::operator=(const DB_Row& y) {
  // Copy-construct `tmp' from `y'.
  DB_Row tmp(y);
  // Swap the implementation of `*this' with the one of `tmp'.
  swap(tmp);
  // Now `tmp' goes out of scope, so the old `*this' will be destroyed.
  return *this;
}

template <typename T>
inline T&
DB_Row<T>::operator[](const dimension_type k) {
  DB_Row<T>& x = *this;
  return (*x.impl)[k];
}

template <typename T>
inline const T&
DB_Row<T>::operator[](const dimension_type k) const {
  const DB_Row<T>& x = *this;
  return (*x.impl)[k];
}

template <typename T>
inline void
DB_Row_Impl_Handler<T>::
Impl::expand_within_capacity(const dimension_type new_size) {
  assert(size() <= new_size && new_size <= max_size());
#if !CXX_SUPPORTS_FLEXIBLE_ARRAYS
  // vec_[0] is already constructed.
  if (size() == 0 && new_size > 0)
    bump_size();
#endif
  // Construct in direct order: will destroy in reverse order.
  for (dimension_type i = size(); i < new_size; ++i) {
    new (&vec_[i]) T(PLUS_INFINITY);
    bump_size();
  }
}

template <typename T>
void
DB_Row_Impl_Handler<T>::Impl::shrink(dimension_type new_size) {
  const dimension_type old_size = size();
  assert(new_size <= old_size);
  // Since ~T() does not throw exceptions, nothing here does.
  set_size(new_size);
#if !CXX_SUPPORTS_FLEXIBLE_ARRAYS
  // Make sure we do not try to destroy vec_[0].
  if (new_size == 0)
    ++new_size;
#endif
  // We assume construction was done "forward".
  // We thus perform destruction "backward".
  for (dimension_type i = old_size; i-- > new_size; )
    vec_[i].~T();
}

template <typename T>
void
DB_Row_Impl_Handler<T>::Impl::copy_construct_coefficients(const Impl& y) {
  const dimension_type y_size = y.size();
#if CXX_SUPPORTS_FLEXIBLE_ARRAYS
  // Construct in direct order: will destroy in reverse order.
  for (dimension_type i = 0; i < y_size; ++i) {
    new (&vec_[i]) T(y.vec_[i]);
    bump_size();
  }
#else
  assert(y_size > 0);
  if (y_size > 0) {
    vec_[0] = y.vec_[0];
    bump_size();
    // Construct in direct order: will destroy in reverse order.
    for (dimension_type i = 1; i < y_size; ++i) {
      new (&vec_[i]) T(y.vec_[i]);
      bump_size();
    }
  }
#endif
}

template <typename T>
typename DB_Row<T>::iterator
DB_Row<T>::begin() {
  DB_Row<T>& x = *this;
  return iterator(x.impl->vec_);
}

template <typename T>
typename DB_Row<T>::iterator
DB_Row<T>::end() {
  DB_Row<T>& x = *this;
  return iterator(x.impl->vec_ + x.impl->size_);
}

template <typename T>
typename DB_Row<T>::const_iterator
DB_Row<T>::begin() const {
  const DB_Row<T>& x = *this;
  return const_iterator(x.impl->vec_);
}

template <typename T>
typename DB_Row<T>::const_iterator
DB_Row<T>::end() const {
  const DB_Row<T>& x = *this;
  return const_iterator(x.impl->vec_ + x.impl->size_);
}

template <typename T>
inline bool
DB_Row<T>::OK(const dimension_type row_size,
	      const dimension_type
#if EXTRA_ROW_DEBUG
	      row_capacity
#endif
	      ) const {
#ifndef NDEBUG
  using std::endl;
  using std::cerr;
#endif

  const DB_Row<T>& x = *this;

  bool is_broken = false;
#if EXTRA_ROW_DEBUG
# if !CXX_SUPPORTS_FLEXIBLE_ARRAYS
  if (x.capacity_ == 0) {
    cerr << "Illegal row capacity: is 0, should be at least 1"
	 << endl;
    is_broken = true;
  }
  else if (x.capacity_ == 1 && row_capacity == 0)
    // This is fine.
    ;
  else
# endif
  if (x.capacity_ != row_capacity) {
    cerr << "DB_Row capacity mismatch: is " << x.capacity_
	 << ", should be " << row_capacity << "."
	 << endl;
    is_broken = true;
  }
#endif
  if (x.size() != row_size) {
#ifndef NDEBUG
    cerr << "DB_Row size mismatch: is " << x.size()
	 << ", should be " << row_size << "."
	 << endl;
#endif
    is_broken = true;
  }
#if EXTRA_ROW_DEBUG
  if (x.capacity_ < x.size()) {
#ifndef NDEBUG
    cerr << "DB_Row is completely broken: capacity is " << x.capacity_
	 << ", size is " << x.size() << "."
	 << endl;
#endif
    is_broken = true;
  }
#endif

  for (dimension_type i = x.size(); i-- > 0; ) {
    const T& element = x[i];
    // Not OK is bad.
    if (!element.OK()) {
      is_broken = true;
      break;
    }
    // In addition, nans should never occur.
    if (is_not_a_number(element)) {
#ifndef NDEBUG
      cerr << "Not-a-number found in DB_Row."
	   << endl;
#endif
      is_broken = true;
      break;
    }
  }

  return !is_broken;
}


/*! \relates DB_Row */
template <typename T>
inline bool
operator==(const DB_Row<T>& x, const DB_Row<T>& y) {
  if (x.size() != y.size())
    return false;
  for (dimension_type i = x.size(); i-- > 0; )
    if (x[i] != y[i])
      return false;
  return true;
}

/*! \relates DB_Row */
template <typename T>
inline bool
operator!=(const DB_Row<T>& x, const DB_Row<T>& y) {
  return !(x == y);
}

} // namespace Parma_Polyhedra_Library


namespace std {

/*! \relates Parma_Polyhedra_Library::DB_Row */
template <typename T>
inline void
swap(Parma_Polyhedra_Library::DB_Row<T>& x,
     Parma_Polyhedra_Library::DB_Row<T>& y) {
  x.swap(y);
}

/*! \relates Parma_Polyhedra_Library::DB_Row */
template <typename T>
inline void
iter_swap(typename std::vector<Parma_Polyhedra_Library::DB_Row<T> >
	  ::iterator x,
	  typename std::vector<Parma_Polyhedra_Library::DB_Row<T> >
	  ::iterator y) {
  swap(*x, *y);
}

} // namespace std

// Automatically generated from PPL source file ../src/DB_Row.defs.hh line 430

// Automatically generated from PPL source file ../src/DB_Matrix.defs.hh line 1
/* DB_Matrix class declaration.
*/


// Automatically generated from PPL source file ../src/DB_Matrix.defs.hh line 31
#include <vector>
#include <cstddef>
#include <iosfwd>

namespace Parma_Polyhedra_Library {

namespace IO_Operators {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Output operator.
/*! \relates Parma_Polyhedra_Library::DB_Matrix */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename T>
std::ostream&
operator<<(std::ostream& s, const DB_Matrix<T>& c);

} // namespace IO_Operators

} // namespace Parma_Polyhedra_Library


#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! The base class for the square matrices.
/*! \ingroup PPL_CXX_interface
  The templatic class DB_Matrix<T> allows for the representation of
  a square matrix of T objects.
  Each DB_Matrix<T> object can be viewed as a multiset of DB_Row<T>.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename T>
class Parma_Polyhedra_Library::DB_Matrix {
public:
  //! Returns the maximum number of rows a DB_Matrix can handle.
  static dimension_type max_num_rows();

  //! Returns the maximum number of columns a DB_Matrix can handle.
  static dimension_type max_num_columns();

  //! Builds an empty matrix.
  /*!
    DB_Rows' size and capacity are initialized to \f$0\f$.
  */
  DB_Matrix();

  //! Builds a square matrix having the specified dimension.
  explicit DB_Matrix(dimension_type n_rows);

  //! Copy-constructor.
  DB_Matrix(const DB_Matrix& y);

  //! Constructs a conservative approximation of \p y.
  template <typename U>
  explicit DB_Matrix(const DB_Matrix<U>& y);

  //! Destructor.
  ~DB_Matrix();

  //! Assignment operator.
  DB_Matrix& operator=(const DB_Matrix& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  //! A read-only iterator over the rows of the matrix.
  /*! \ingroup PPL_CXX_interface */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  class const_iterator {
  private:
    typedef typename std::vector<DB_Row<T> >::const_iterator Iter;
    //! The const iterator on the rows' vector \p rows.
    Iter i;

  public:
    typedef std::forward_iterator_tag iterator_category;
    typedef typename std::iterator_traits<Iter>::value_type value_type;
    typedef typename std::iterator_traits<Iter>::difference_type
    difference_type;
    typedef typename std::iterator_traits<Iter>::pointer pointer;
    typedef typename std::iterator_traits<Iter>::reference reference;

    //! Default constructor.
    const_iterator();

    /*! \brief
      Builds a const iterator on the matrix starting from
      an iterator \p b on the elements of the vector \p rows.
    */
    explicit const_iterator(const Iter& b);

    //! Ordinary copy-constructor.
    const_iterator(const const_iterator& y);

    //! Assignment operator.
    const_iterator& operator=(const const_iterator& y);

    //! Dereference operator.
    reference operator*() const;

    //! Indirect member selector.
    pointer operator->() const;

    //! Prefix increment operator.
    const_iterator& operator++();

    //! Postfix increment operator.
    const_iterator operator++(int);

    /*! \brief
      Returns <CODE>true</CODE> if and only if
      \p *this and \p y are identical.
    */
    bool operator==(const const_iterator& y) const;

    /*! \brief
      Returns <CODE>true</CODE> if and only if
      \p *this and \p y are different.
    */
    bool operator!=(const const_iterator& y) const;
  };

  /*! \brief
    Returns the const_iterator pointing to the first row,
    if \p *this is not empty;
    otherwise, returns the past-the-end const_iterator.
  */
  const_iterator begin() const;

  //! Returns the past-the-end const_iterator.
  const_iterator end() const;

private:
  template <typename U> friend class DB_Matrix;

  //! The rows of the matrix.
  std::vector<DB_Row<T> > rows;

  //! Size of the initialized part of each row.
  dimension_type row_size;

  /*! \brief
    Capacity allocated for each row, i.e., number of
    <CODE>long</CODE> objects that each row can contain.
  */
  dimension_type row_capacity;

public:
  //! Swaps \p *this with \p y.
  void swap(DB_Matrix& y);


  //! Makes the matrix grow by adding more rows and more columns.
  /*!
    \param new_n_rows
    The number of rows and columns of the resized matrix.

    A new matrix, with the specified dimension, is created.
    The contents of the old matrix are copied in the upper, left-hand
    corner of the new matrix, which is then assigned to \p *this.
  */
  void grow(dimension_type new_n_rows);

  //! Resizes the matrix without worrying about the old contents.
  /*!
    \param new_n_rows
    The number of rows and columns of the resized matrix.

    A new matrix, with the specified dimension, is created without copying
    the content of the old matrix and assigned to \p *this.
  */
  void resize_no_copy(dimension_type new_n_rows);

  //! Returns the number of rows in the matrix.
  dimension_type num_rows() const;

  //! \name Subscript operators.
  //@{
  //! Returns a reference to the \p k-th row of the matrix.
  DB_Row<T>& operator[](dimension_type k);

  //! Returns a constant reference to the \p k-th row of the matrix.
  const DB_Row<T>& operator[](dimension_type k) const;
  //@}

  PPL_OUTPUT_DECLARATIONS;

  /*! \brief
    Loads from \p s an ASCII representation (as produced by \ref ascii_dump)
    and sets \p *this accordingly.  Returns <CODE>true</CODE>
    if successful, <CODE>false</CODE> otherwise.
  */
  bool ascii_load(std::istream& s);

  //! Checks if all the invariants are satisfied.
  bool OK() const;
};

namespace std {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::DB_Matrix */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename T>
void swap(Parma_Polyhedra_Library::DB_Matrix<T>& x,
	  Parma_Polyhedra_Library::DB_Matrix<T>& y);

} // namespace std


namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns <CODE>true</CODE> if and only if \p x and \p y are identical.
/*! \relates DB_Matrix */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename T>
bool operator==(const DB_Matrix<T>& x, const DB_Matrix<T>& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Returns <CODE>true</CODE> if and only if \p x and \p y are different.
/*! \relates DB_Matrix */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename T>
bool operator!=(const DB_Matrix<T>& x, const DB_Matrix<T>& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Computes the rectilinear (or Manhattan) distance between \p x and \p y.
/*! \relates DB_Matrix
  If the rectilinear distance between \p x and \p y is defined,
  stores an approximation of it into to \p r
  and returns <CODE>true</CODE>;  returns <CODE>false</CODE> otherwise.

  The direction of the approximation is specified by \p dir.

  All computations are performed using the temporary variables
  \p tmp0, \p tmp1 and \p tmp2.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename Temp, typename To, typename T>
bool rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
				 const DB_Matrix<T>& x,
				 const DB_Matrix<T>& y,
				 const Rounding_Dir dir,
				 Temp& tmp0,
				 Temp& tmp1,
				 Temp& tmp2);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Computes the euclidean distance between \p x and \p y.
/*! \relates DB_Matrix
  If the Euclidean distance between \p x and \p y is defined,
  stores an approximation of it into to \p r
  and returns <CODE>true</CODE>;  returns <CODE>false</CODE> otherwise.

  The direction of the approximation is specified by \p dir.

  All computations are performed using the temporary variables
  \p tmp0, \p tmp1 and \p tmp2.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename Temp, typename To, typename T>
bool euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			       const DB_Matrix<T>& x,
			       const DB_Matrix<T>& y,
			       const Rounding_Dir dir,
			       Temp& tmp0,
			       Temp& tmp1,
			       Temp& tmp2);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Computes the \f$L_\infty\f$ distance between \p x and \p y.
/*! \relates DB_Matrix
  If the \f$L_\infty\f$ distance between \p x and \p y is defined,
  stores an approximation of it into to \p r
  and returns <CODE>true</CODE>;  returns <CODE>false</CODE> otherwise.

  The direction of the approximation is specified by \p dir.

  All computations are performed using the temporary variables
  \p tmp0, \p tmp1 and \p tmp2.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename Temp, typename To, typename T>
bool l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
				 const DB_Matrix<T>& x,
				 const DB_Matrix<T>& y,
				 const Rounding_Dir dir,
				 Temp& tmp0,
				 Temp& tmp1,
				 Temp& tmp2);

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/DB_Matrix.inlines.hh line 1
/* DB_Matrix class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/DB_Matrix.inlines.hh line 28
#include <cassert>
#include <iostream>

namespace Parma_Polyhedra_Library {

template <typename T>
inline void
DB_Matrix<T>::swap(DB_Matrix& y) {
  std::swap(rows, y.rows);
  std::swap(row_size, y.row_size);
  std::swap(row_capacity, y.row_capacity);
}

template <typename T>
inline dimension_type
DB_Matrix<T>::max_num_rows() {
  return std::vector<DB_Row<T> >().max_size();
}

template <typename T>
inline dimension_type
DB_Matrix<T>::max_num_columns() {
  return DB_Row<T>::max_size();
}

template <typename T>
inline
DB_Matrix<T>::const_iterator::const_iterator()
  : i(Iter()) {
}

template <typename T>
inline
DB_Matrix<T>::const_iterator::const_iterator(const Iter& b)
  : i(b) {
}

template <typename T>
inline
DB_Matrix<T>::const_iterator::const_iterator(const const_iterator& y)
  : i(y.i) {
}

template <typename T>
inline typename DB_Matrix<T>::const_iterator&
DB_Matrix<T>::const_iterator::operator=(const const_iterator& y) {
  i = y.i;
  return *this;
}

template <typename T>
inline typename DB_Matrix<T>::const_iterator::reference
DB_Matrix<T>::const_iterator::operator*() const {
  return *i;
}

template <typename T>
inline typename DB_Matrix<T>::const_iterator::pointer
DB_Matrix<T>::const_iterator::operator->() const {
  return &*i;
}

template <typename T>
inline typename DB_Matrix<T>::const_iterator&
DB_Matrix<T>::const_iterator::operator++() {
  ++i;
  return *this;
}

template <typename T>
inline typename DB_Matrix<T>::const_iterator
DB_Matrix<T>::const_iterator::operator++(int) {
  return const_iterator(i++);
}

template <typename T>
inline bool
DB_Matrix<T>::const_iterator::operator==(const const_iterator& y) const {
  return i == y.i;
}

template <typename T>
inline bool
DB_Matrix<T>::const_iterator::operator!=(const const_iterator& y) const {
  return !operator==(y);
}

template <typename T>
inline typename DB_Matrix<T>::const_iterator
DB_Matrix<T>::begin() const {
  return const_iterator(rows.begin());
}

template <typename T>
inline typename DB_Matrix<T>::const_iterator
DB_Matrix<T>::end() const {
  return const_iterator(rows.end());
}

template <typename T>
inline
DB_Matrix<T>::DB_Matrix()
  : rows(),
    row_size(0),
    row_capacity(0) {
}

template <typename T>
inline
DB_Matrix<T>::~DB_Matrix() {
}

template <typename T>
inline DB_Row<T>&
DB_Matrix<T>::operator[](const dimension_type k) {
  assert(k < rows.size());
  return rows[k];
}

template <typename T>
inline const DB_Row<T>&
DB_Matrix<T>::operator[](const dimension_type k) const {
  assert(k < rows.size());
  return rows[k];
}

template <typename T>
inline dimension_type
DB_Matrix<T>::num_rows() const {
  return rows.size();
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates DB_Matrix */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename T>
inline bool
operator!=(const DB_Matrix<T>& x, const DB_Matrix<T>& y) {
  return !(x == y);
}

template <typename T>
inline
DB_Matrix<T>::DB_Matrix(const dimension_type n_rows)
  : rows(n_rows),
    row_size(n_rows),
    row_capacity(compute_capacity(n_rows, max_num_columns())) {
  // Construct in direct order: will destroy in reverse order.
  for (dimension_type i = 0; i < n_rows; ++i)
    rows[i].construct(n_rows, row_capacity);
  assert(OK());
}

template <typename T>
inline
DB_Matrix<T>::DB_Matrix(const DB_Matrix& y)
  : rows(y.rows),
    row_size(y.row_size),
    row_capacity(compute_capacity(y.row_size, max_num_columns())) {
}

template <typename T>
template <typename U>
inline
DB_Matrix<T>::DB_Matrix(const DB_Matrix<U>& y)
  : rows(y.rows.size()),
    row_size(y.row_size),
    row_capacity(compute_capacity(y.row_size, max_num_columns())) {
  // Construct in direct order: will destroy in reverse order.
  for (dimension_type i = 0, n_rows = rows.size(); i < n_rows; ++i)
    rows[i].construct_upward_approximation(y[i], row_capacity);
  assert(OK());
}

template <typename T>
inline DB_Matrix<T>&
DB_Matrix<T>::operator=(const DB_Matrix& y) {
  // Without the following guard against auto-assignments we would
  // recompute the row capacity based on row size, possibly without
  // actually increasing the capacity of the rows.  This would lead to
  // an inconsistent state.
  if (this != &y) {
    // The following assignment may do nothing on auto-assignments...
    rows = y.rows;
    row_size = y.row_size;
    // ... hence the following assignment must not be done on
    // auto-assignments.
    row_capacity = compute_capacity(y.row_size, max_num_columns());
  }
  return *this;
}

template <typename T>
void
DB_Matrix<T>::grow(const dimension_type new_n_rows) {
  const dimension_type old_n_rows = rows.size();
  assert(new_n_rows >= old_n_rows);

  if (new_n_rows > old_n_rows) {
    if (new_n_rows <= row_capacity) {
      // We can recycle the old rows.
      if (rows.capacity() < new_n_rows) {
	// Reallocation will take place.
	std::vector<DB_Row<T> > new_rows;
	new_rows.reserve(compute_capacity(new_n_rows, max_num_rows()));
	new_rows.insert(new_rows.end(), new_n_rows, DB_Row<T>());
	// Construct the new rows.
	dimension_type i = new_n_rows;
	while (i-- > old_n_rows)
	  new_rows[i].construct(new_n_rows, row_capacity);
	// Steal the old rows.
	++i;
	while (i-- > 0)
	  new_rows[i].swap(rows[i]);
	// Put the new vector into place.
	std::swap(rows, new_rows);
      }
      else {
	// Reallocation will NOT take place.
	rows.insert(rows.end(), new_n_rows - old_n_rows, DB_Row<T>());
	for (dimension_type i = new_n_rows; i-- > old_n_rows; )
	  rows[i].construct(new_n_rows, row_capacity);
      }
    }
    else {
      // We cannot even recycle the old rows.
      DB_Matrix new_matrix;
      new_matrix.rows.reserve(compute_capacity(new_n_rows, max_num_rows()));
      new_matrix.rows.insert(new_matrix.rows.end(), new_n_rows, DB_Row<T>());
      // Construct the new rows.
      new_matrix.row_size = new_n_rows;
      new_matrix.row_capacity = compute_capacity(new_n_rows,
						 max_num_columns());
      dimension_type i = new_n_rows;
      while (i-- > old_n_rows)
	new_matrix.rows[i].construct(new_matrix.row_size,
				     new_matrix.row_capacity);
      // Copy the old rows.
      ++i;
      while (i-- > 0) {
	DB_Row<T> new_row(rows[i],
			  new_matrix.row_size,
			  new_matrix.row_capacity);
	std::swap(new_matrix.rows[i], new_row);
      }
      // Put the new vector into place.
      swap(new_matrix);
      return;
    }
  }
  // Here we have the right number of rows.
  if (new_n_rows > row_size) {
    // We need more columns.
    if (new_n_rows <= row_capacity)
      // But we have enough capacity: we resize existing rows.
      for (dimension_type i = old_n_rows; i-- > 0; )
	rows[i].expand_within_capacity(new_n_rows);
    else {
      // Capacity exhausted: we must reallocate the rows and
      // make sure all the rows have the same capacity.
      const dimension_type new_row_capacity
	= compute_capacity(new_n_rows, max_num_columns());
      for (dimension_type i = old_n_rows; i-- > 0; ) {
	DB_Row<T> new_row(rows[i], new_n_rows, new_row_capacity);
	std::swap(rows[i], new_row);
      }
      row_capacity = new_row_capacity;
    }
    // Rows have grown or shrunk.
    row_size = new_n_rows;
  }
}

template <typename T>
void
DB_Matrix<T>::resize_no_copy(const dimension_type new_n_rows) {
  dimension_type old_n_rows = rows.size();

  if (new_n_rows > old_n_rows) {
    // Rows will be inserted.
    if (new_n_rows <= row_capacity) {
      // We can recycle the old rows.
      if (rows.capacity() < new_n_rows) {
	// Reallocation (of vector `rows') will take place.
	std::vector<DB_Row<T> > new_rows;
	new_rows.reserve(compute_capacity(new_n_rows, max_num_rows()));
	new_rows.insert(new_rows.end(), new_n_rows, DB_Row<T>());
	// Construct the new rows (be careful: each new row must have
	// the same capacity as each one of the old rows).
	dimension_type i = new_n_rows;
	while (i-- > old_n_rows)
	  new_rows[i].construct(new_n_rows, row_capacity);
	// Steal the old rows.
	++i;
	while (i-- > 0)
	  new_rows[i].swap(rows[i]);
	// Put the new vector into place.
	std::swap(rows, new_rows);
      }
      else {
	// Reallocation (of vector `rows') will NOT take place.
	rows.insert(rows.end(), new_n_rows - old_n_rows, DB_Row<T>());
	// Be careful: each new row must have
	// the same capacity as each one of the old rows.
	for (dimension_type i = new_n_rows; i-- > old_n_rows; )
	  rows[i].construct(new_n_rows, row_capacity);
      }
    }
    else {
      // We cannot even recycle the old rows: allocate a new matrix and swap.
      DB_Matrix new_matrix(new_n_rows);
      swap(new_matrix);
      return;
    }
  }
  else if (new_n_rows < old_n_rows) {
    // Drop some rows.
    rows.erase(rows.begin() + new_n_rows, rows.end());
    // Shrink the existing rows.
    for (dimension_type i = new_n_rows; i-- > 0; )
      rows[i].shrink(new_n_rows);
    old_n_rows = new_n_rows;
  }
  // Here we have the right number of rows.
  if (new_n_rows > row_size) {
    // We need more columns.
    if (new_n_rows <= row_capacity)
      // But we have enough capacity: we resize existing rows.
      for (dimension_type i = old_n_rows; i-- > 0; )
	rows[i].expand_within_capacity(new_n_rows);
    else {
      // Capacity exhausted: we must reallocate the rows and
      // make sure all the rows have the same capacity.
      const dimension_type new_row_capacity
	= compute_capacity(new_n_rows, max_num_columns());
      for (dimension_type i = old_n_rows; i-- > 0; ) {
	DB_Row<T> new_row(new_n_rows, new_row_capacity);
	std::swap(rows[i], new_row);
      }
      row_capacity = new_row_capacity;
    }
  }
  // DB_Rows have grown or shrunk.
  row_size = new_n_rows;
}

template <typename T>
void
DB_Matrix<T>::ascii_dump(std::ostream& s) const {
  const DB_Matrix<T>& x = *this;
  const char separator = ' ';
  const dimension_type nrows = x.num_rows();
  s << nrows << separator << "\n";
  for (dimension_type i = 0; i < nrows;  ++i) {
    for (dimension_type j = 0; j < nrows; ++j) {
      using namespace IO_Operators;
      s << x[i][j] << separator;
    }
    s << "\n";
  }
}

PPL_OUTPUT_TEMPLATE_DEFINITIONS(T, DB_Matrix<T>);

template <typename T>
bool
DB_Matrix<T>::ascii_load(std::istream& s) {
  dimension_type nrows;
   if (!(s >> nrows))
    return false;
  resize_no_copy(nrows);
  DB_Matrix& x = *this;
  for (dimension_type i = 0; i < nrows;  ++i)
    for (dimension_type j = 0; j < nrows; ++j) {
      Result r = input(x[i][j], s, ROUND_UP);
      // FIXME: V_CVT_STR_UNK is probably not the only possible error.
      if (!s || r == V_CVT_STR_UNK)
	return false;
    }
  // Check for well-formedness.
  assert(OK());
  return true;
}


#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates DB_Matrix */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename T>
inline bool
operator==(const DB_Matrix<T>& x, const DB_Matrix<T>& y) {
  const dimension_type x_num_rows = x.num_rows();
  if (x_num_rows != y.num_rows())
    return false;
  for (dimension_type i = x_num_rows; i-- > 0; )
    if (x[i] != y[i])
      return false;
  return true;
}

template <typename To, typename From>
struct maybe_assign_struct {
  static inline Result
  function(const To*& top, To& tmp, const From& from, Rounding_Dir dir) {
    // When `To' and `From' are different types, we make the conversion
    // and use `tmp'.
    top = &tmp;
    return assign_r(tmp, from, dir);
  }
};

template <typename Type>
struct maybe_assign_struct<Type, Type> {
  static inline Result
  function(const Type*& top, Type&, const Type& from, Rounding_Dir) {
    // When the types are the same, conversion is unnecessary.
    top = &from;
    return V_EQ;
  }
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  Assigns to \p top a pointer to a location that holds the
  conversion, according to \p dir, of \p from to type \p To.  When
  necessary, and only when necessary, the variable \p tmp is used to
  hold the result of conversion.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename To, typename From>
inline Result
maybe_assign(const To*& top, To& tmp, const From& from, Rounding_Dir dir) {
  return maybe_assign_struct<To, From>::function(top, tmp, from, dir);
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates DB_Matrix */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename Specialization, typename Temp, typename To, typename T>
inline bool
l_m_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
		    const DB_Matrix<T>& x,
		    const DB_Matrix<T>& y,
		    const Rounding_Dir dir,
		    Temp& tmp0,
		    Temp& tmp1,
		    Temp& tmp2) {
  const dimension_type x_num_rows = x.num_rows();
  if (x_num_rows != y.num_rows())
    return false;
  assign_r(tmp0, 0, ROUND_NOT_NEEDED);
  for (dimension_type i = x_num_rows; i-- > 0; ) {
    const DB_Row<T>& x_i = x[i];
    const DB_Row<T>& y_i = y[i];
    for (dimension_type j = x_num_rows; j-- > 0; ) {
      const T& x_i_j = x_i[j];
      const T& y_i_j = y_i[j];
      if (is_plus_infinity(x_i_j)) {
	if (is_plus_infinity(y_i_j))
	  continue;
	else {
	pinf:
	  r = PLUS_INFINITY;
	  return true;
	}
      }
      else if (is_plus_infinity(y_i_j))
	goto pinf;

      const Temp* tmp1p;
      const Temp* tmp2p;
      if (x_i_j > y_i_j) {
	maybe_assign(tmp1p, tmp1, x_i_j, dir);
	maybe_assign(tmp2p, tmp2, y_i_j, inverse(dir));
      }
      else {
	maybe_assign(tmp1p, tmp1, y_i_j, dir);
	maybe_assign(tmp2p, tmp2, x_i_j, inverse(dir));
      }
      sub_assign_r(tmp1, *tmp1p, *tmp2p, dir);
      assert(tmp1 >= 0);
      Specialization::combine(tmp0, tmp1, dir);
    }
  }
  Specialization::finalize(tmp0, dir);
  assign_r(r, tmp0, dir);
  return true;
}

template <typename Temp>
struct Rectilinear_Distance_Specialization {
  static inline void
  combine(Temp& running, const Temp& current, Rounding_Dir dir) {
    add_assign_r(running, running, current, dir);
  }

  static inline void
  finalize(Temp&, Rounding_Dir) {
  }
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates DB_Matrix */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename Temp, typename To, typename T>
inline bool
rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			    const DB_Matrix<T>& x,
			    const DB_Matrix<T>& y,
			    const Rounding_Dir dir,
			    Temp& tmp0,
			    Temp& tmp1,
			    Temp& tmp2) {
  return
    l_m_distance_assign<Rectilinear_Distance_Specialization<Temp> >(r, x, y,
								    dir,
								    tmp0,
								    tmp1,
								    tmp2);
}


template <typename Temp>
struct Euclidean_Distance_Specialization {
  static inline void
  combine(Temp& running, Temp& current, Rounding_Dir dir) {
    mul_assign_r(current, current, current, dir);
    add_assign_r(running, running, current, dir);
  }

  static inline void
  finalize(Temp& running, Rounding_Dir dir) {
    sqrt_assign_r(running, running, dir);
  }
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates DB_Matrix */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename Temp, typename To, typename T>
inline bool
euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			  const DB_Matrix<T>& x,
			  const DB_Matrix<T>& y,
			  const Rounding_Dir dir,
			  Temp& tmp0,
			  Temp& tmp1,
			  Temp& tmp2) {
  return
    l_m_distance_assign<Euclidean_Distance_Specialization<Temp> >(r, x, y,
								  dir,
								  tmp0,
								  tmp1,
								  tmp2);
}


template <typename Temp>
struct L_Infinity_Distance_Specialization {
  static inline void
  combine(Temp& running, const Temp& current, Rounding_Dir) {
    if (current > running)
      running = current;
  }

  static inline void
  finalize(Temp&, Rounding_Dir) {
  }
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates DB_Matrix */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename Temp, typename To, typename T>
inline bool
l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			   const DB_Matrix<T>& x,
			   const DB_Matrix<T>& y,
			   const Rounding_Dir dir,
			   Temp& tmp0,
			   Temp& tmp1,
			   Temp& tmp2) {
  return
    l_m_distance_assign<L_Infinity_Distance_Specialization<Temp> >(r, x, y,
								   dir,
								   tmp0,
								   tmp1,
								   tmp2);
}

template <typename T>
bool
DB_Matrix<T>::OK() const {
#ifndef NDEBUG
  using std::endl;
  using std::cerr;
#endif

  // The matrix must be square.
  if (num_rows() != row_size) {
#ifndef NDEBUG
    cerr << "DB_Matrix has fewer columns than rows:\n"
	 << "row_size is " << row_size
	 << ", num_rows() is " << num_rows() << "!"
	 << endl;
#endif
    return false;
  }

  const DB_Matrix& x = *this;
  const dimension_type n_rows = x.num_rows();
  for (dimension_type i = 0; i < n_rows; ++i) {
    if (!x[i].OK(row_size, row_capacity))
      return false;
  }

  // All checks passed.
  return true;
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates Parma_Polyhedra_Library::DB_Matrix */  //FIXME!!
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename T>
std::ostream&
IO_Operators::operator<<(std::ostream& s, const DB_Matrix<T>& c) {
  const dimension_type n = c.num_rows();
  for (dimension_type i = 0; i < n; ++i) {
    for (dimension_type j = 0; j < n; ++j)
      s << c[i][j] << " ";
    s << "\n";
  }
  return s;
}

} // namespace Parma_Polyhedra_Library

namespace std {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates Parma_Polyhedra_Library::DB_Matrix */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename T>
inline void
swap(Parma_Polyhedra_Library::DB_Matrix<T>& x,
     Parma_Polyhedra_Library::DB_Matrix<T>& y) {
  x.swap(y);
}

} // namespace std

// Automatically generated from PPL source file ../src/DB_Matrix.defs.hh line 323

// Automatically generated from PPL source file ../src/BD_Shape.defs.hh line 1
/* BD_Shape class declaration.
*/


// Automatically generated from PPL source file ../src/BD_Shape.defs.hh line 40
#include <cstddef>
#include <iosfwd>
#include <vector>
#include <deque>


namespace Parma_Polyhedra_Library {

namespace IO_Operators {

//! Output operator.
/*! \relates Parma_Polyhedra_Library::BD_Shape
  Writes a textual representation of \p bds on \p s:
  <CODE>false</CODE> is written if \p bds is an empty polyhedron;
  <CODE>true</CODE> is written if \p bds is the universe polyhedron;
  a system of constraints defining \p bds is written otherwise,
  all constraints separated by ", ".
*/
template <typename T>
std::ostream&
operator<<(std::ostream& s, const BD_Shape<T>& bds);

} // namespace IO_Operators

//! Returns <CODE>true</CODE> if and only if \p x and \p y are the same BDS.
/*!
  \relates BD_Shape
  Note that \p x and \p y may be dimension-incompatible shapes:
  in this case, the value <CODE>false</CODE> is returned.
*/
template <typename T>
bool operator==(const BD_Shape<T>& x, const BD_Shape<T>& y);

//! Returns <CODE>true</CODE> if and only if \p x and \p y aren't the same BDS.
/*!
 \relates BD_Shape
  Note that \p x and \p y may be dimension-incompatible shapes:
  in this case, the value <CODE>true</CODE> is returned.
*/
template <typename T>
bool operator!=(const BD_Shape<T>& x, const BD_Shape<T>& y);

//! Computes the rectilinear (or Manhattan) distance between \p x and \p y.
/*! \relates BD_Shape
  If the rectilinear distance between \p x and \p y is defined,
  stores an approximation of it into \p r and returns <CODE>true</CODE>;
  returns <CODE>false</CODE> otherwise.

  The direction of the approximation is specified by \p dir.

  All computations are performed using variables of type
  Checked_Number<To, Extended_Number_Policy>.
*/
template <typename To, typename T>
bool rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
				 const BD_Shape<T>& x,
				 const BD_Shape<T>& y,
				 const Rounding_Dir dir);

//! Computes the rectilinear (or Manhattan) distance between \p x and \p y.
/*! \relates BD_Shape
  If the rectilinear distance between \p x and \p y is defined,
  stores an approximation of it into \p r and returns <CODE>true</CODE>;
  returns <CODE>false</CODE> otherwise.

  The direction of the approximation is specified by \p dir.

  All computations are performed using variables of type
  Checked_Number<Temp, Extended_Number_Policy>.
*/
template <typename Temp, typename To, typename T>
bool rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
				 const BD_Shape<T>& x,
				 const BD_Shape<T>& y,
				 const Rounding_Dir dir);

//! Computes the rectilinear (or Manhattan) distance between \p x and \p y.
/*! \relates BD_Shape
  If the rectilinear distance between \p x and \p y is defined,
  stores an approximation of it into \p r and returns <CODE>true</CODE>;
  returns <CODE>false</CODE> otherwise.

  The direction of the approximation is specified by \p dir.

  All computations are performed using the temporary variables
  \p tmp0, \p tmp1 and \p tmp2.
*/
template <typename Temp, typename To, typename T>
bool rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
				 const BD_Shape<T>& x,
				 const BD_Shape<T>& y,
				 const Rounding_Dir dir,
				 Temp& tmp0,
				 Temp& tmp1,
				 Temp& tmp2);

//! Computes the euclidean distance between \p x and \p y.
/*! \relates BD_Shape
  If the euclidean distance between \p x and \p y is defined,
  stores an approximation of it into \p r and returns <CODE>true</CODE>;
  returns <CODE>false</CODE> otherwise.

  The direction of the approximation is specified by \p dir.

  All computations are performed using variables of type
  Checked_Number<To, Extended_Number_Policy>.
*/
template <typename To, typename T>
bool euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			       const BD_Shape<T>& x,
			       const BD_Shape<T>& y,
			       const Rounding_Dir dir);

//! Computes the euclidean distance between \p x and \p y.
/*! \relates BD_Shape
  If the euclidean distance between \p x and \p y is defined,
  stores an approximation of it into \p r and returns <CODE>true</CODE>;
  returns <CODE>false</CODE> otherwise.

  The direction of the approximation is specified by \p dir.

  All computations are performed using variables of type
  Checked_Number<Temp, Extended_Number_Policy>.
*/
template <typename Temp, typename To, typename T>
bool euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			       const BD_Shape<T>& x,
			       const BD_Shape<T>& y,
			       const Rounding_Dir dir);

//! Computes the euclidean distance between \p x and \p y.
/*! \relates BD_Shape
  If the euclidean distance between \p x and \p y is defined,
  stores an approximation of it into \p r and returns <CODE>true</CODE>;
  returns <CODE>false</CODE> otherwise.

  The direction of the approximation is specified by \p dir.

  All computations are performed using the temporary variables
  \p tmp0, \p tmp1 and \p tmp2.
*/
template <typename Temp, typename To, typename T>
bool euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			       const BD_Shape<T>& x,
			       const BD_Shape<T>& y,
			       const Rounding_Dir dir,
			       Temp& tmp0,
			       Temp& tmp1,
			       Temp& tmp2);

//! Computes the \f$L_\infty\f$ distance between \p x and \p y.
/*! \relates BD_Shape
  If the \f$L_\infty\f$ distance between \p x and \p y is defined,
  stores an approximation of it into \p r and returns <CODE>true</CODE>;
  returns <CODE>false</CODE> otherwise.

  The direction of the approximation is specified by \p dir.

  All computations are performed using variables of type
  Checked_Number<To, Extended_Number_Policy>.
*/
template <typename To, typename T>
bool l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
				const BD_Shape<T>& x,
				const BD_Shape<T>& y,
				const Rounding_Dir dir);

//! Computes the \f$L_\infty\f$ distance between \p x and \p y.
/*! \relates BD_Shape
  If the \f$L_\infty\f$ distance between \p x and \p y is defined,
  stores an approximation of it into \p r and returns <CODE>true</CODE>;
  returns <CODE>false</CODE> otherwise.

  The direction of the approximation is specified by \p dir.

  All computations are performed using variables of type
  Checked_Number<Temp, Extended_Number_Policy>.
*/
template <typename Temp, typename To, typename T>
bool l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
				const BD_Shape<T>& x,
				const BD_Shape<T>& y,
				const Rounding_Dir dir);

//! Computes the \f$L_\infty\f$ distance between \p x and \p y.
/*! \relates BD_Shape
  If the \f$L_\infty\f$ distance between \p x and \p y is defined,
  stores an approximation of it into \p r and returns <CODE>true</CODE>;
  returns <CODE>false</CODE> otherwise.

  The direction of the approximation is specified by \p dir.

  All computations are performed using the temporary variables
  \p tmp0, \p tmp1 and \p tmp2.
*/
template <typename Temp, typename To, typename T>
bool l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
				const BD_Shape<T>& x,
				const BD_Shape<T>& y,
				const Rounding_Dir dir,
				Temp& tmp0,
				Temp& tmp1,
				Temp& tmp2);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Decodes the constraint \p c as a bounded difference.
/*!
  \return
  <CODE>true</CODE> if the constraint \p c is a
  \ref Bounded_Difference_Shapes "bounded difference";
  <CODE>false</CODE> otherwise.

  \param c
  The constraint to be decoded.

  \param c_space_dim
  The space dimension of the constraint \p c (it is <EM>assumed</EM>
  to match the actual space dimension of \p c).

  \param c_num_vars
  If <CODE>true</CODE> is returned, then it will be set to the number
  of variables having a non-zero coefficient. The only legal values
  will therefore be 0, 1 and 2.

  \param c_first_var
  If <CODE>true</CODE> is returned and if \p c_num_vars is not set to 0,
  then it will be set to the index of the first variable having
  a non-zero coefficient in \p c.

  \param c_second_var
  If <CODE>true</CODE> is returned and if \p c_num_vars is set to 2,
  then it will be set to the index of the second variable having
  a non-zero coefficient in \p c.

  \param c_coeff
  If <CODE>true</CODE> is returned and if \p c_num_vars is not set to 0,
  then it will be set to the value of the first non-zero coefficient
  in \p c.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
bool extract_bounded_difference(const Constraint& c,
				const dimension_type c_space_dim,
				dimension_type& c_num_vars,
				dimension_type& c_first_var,
				dimension_type& c_second_var,
				Coefficient& c_coeff);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Extracts leader indices from the predecessor relation.
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
void compute_leader_indices(const std::vector<dimension_type>& predecessor,
			    std::vector<dimension_type>& indices);

} // namespace Parma_Polyhedra_Library

//! A bounded difference shape.
/*! \ingroup PPL_CXX_interface
  The class template BD_Shape<T> allows for the efficient representation
  of a restricted kind of <EM>topologically closed</EM> convex polyhedra
  called <EM>bounded difference shapes</EM> (BDSs, for short).
  The name comes from the fact that the closed affine half-spaces that
  characterize the polyhedron can be expressed by constraints of the form
  \f$\pm x_i \leq k\f$ or \f$x_i - x_j \leq k\f$, where the inhomogeneous
  term \f$k\f$ is a rational number.

  Based on the class template type parameter \p T, a family of extended
  numbers is built and used to approximate the inhomogeneous term of
  bounded differences. These extended numbers provide a representation
  for the value \f$+\infty\f$, as well as <EM>rounding-aware</EM>
  implementations for several arithmetic functions.
  The value of the type parameter \p T may be one of the following:
    - a bounded precision integer type (e.g., \c int32_t or \c int64_t);
    - a bounded precision floating point type (e.g., \c float or \c double);
    - an unbounded integer or rational type, as provided by GMP
      (i.e., \c mpz_class or \c mpq_class).

  The user interface for BDSs is meant to be as similar as possible to
  the one developed for the polyhedron class C_Polyhedron.  At the
  interface level, bounded differences are specified using objects of
  type Constraint: such a constraint is a bounded difference if it is
  of the form
    \f[
      a_i x_i - a_j x_j \relsym b
    \f]
  where \f$\mathord{\relsym} \in \{ \leq, =, \geq \}\f$ and
  \f$a_i\f$, \f$a_j\f$, \f$b\f$ are integer coefficients such that
  \f$a_i = 0\f$, or \f$a_j = 0\f$, or \f$a_i = a_j\f$.
  The user is warned that the above Constraint object will be mapped
  into a <EM>correct</EM> approximation that, depending on the expressive
  power of the chosen template argument \p T, may loose some precision.
  In particular, constraint objects that do not encode a bounded difference
  will be simply (and safely) ignored.

  For instance, a Constraint object encoding \f$3x - 3y \leq 1\f$ will be
  approximated by:
    - \f$x - y \leq 1\f$,
      if \p T is a (bounded or unbounded) integer type;
    - \f$x - y \leq \frac{1}{3}\f$,
      if \p T is the unbounded rational type \c mpq_class;
    - \f$x - y \leq k\f$, where \f$k > \frac{1}{3}\f$,
      if \p T is a floating point type (having no exact representation
      for \f$\frac{1}{3}\f$).

  On the other hand, a Constraint object encoding \f$3x - y \leq 1\f$
  will be safely ignored in all of the above cases.

  In the following examples it is assumed that the type argument \p T
  is one of the possible instances listed above and that variables
  <CODE>x</CODE>, <CODE>y</CODE> and <CODE>z</CODE> are defined
  (where they are used) as follows:
  \code
    Variable x(0);
    Variable y(1);
    Variable z(2);
  \endcode

  \par Example 1
  The following code builds a BDS corresponding to a cube in \f$\Rset^3\f$,
  given as a system of constraints:
  \code
    Constraint_System cs;
    cs.insert(x >= 0);
    cs.insert(x <= 1);
    cs.insert(y >= 0);
    cs.insert(y <= 1);
    cs.insert(z >= 0);
    cs.insert(z <= 1);
    BD_Shape<T> bd(cs);
  \endcode
  Since only those constraints having the syntactic form of a
  <EM>bounded difference</EM> are considered, the following code
  will build the same BDS as above (i.e., the constraints 7, 8, and 9
  are ignored):
  \code
    Constraint_System cs;
    cs.insert(x >= 0);
    cs.insert(x <= 1);
    cs.insert(y >= 0);
    cs.insert(y <= 1);
    cs.insert(z >= 0);
    cs.insert(z <= 1);
    cs.insert(x + y <= 0);      // 7
    cs.insert(x - z + x >= 0);  // 8
    cs.insert(3*z - y <= 1);    // 9
    BD_Shape<T> bd(cs);
  \endcode
*/
template <typename T>
class Parma_Polyhedra_Library::BD_Shape {
private:
  /*! \brief
    The (extended) numeric type of the inhomogeneous term of
    the inequalities defining a BDS.
  */
  typedef Checked_Number<T, Extended_Number_Policy> N;

public:
  //! The numeric base type upon which bounded differences are built.
  typedef T base_type;

  /*! \brief
    The (extended) numeric type of the inhomogeneous term of the
    inequalities defining a BDS.
  */
  typedef N coefficient_type;

  //! Returns the maximum space dimension that a BDS can handle.
  static dimension_type max_space_dimension();

  //! \name Constructors, Assignment, Swap and Destructor
  //@{

  //! Builds a universe or empty BDS of the specified space dimension.
  /*!
    \param num_dimensions
    The number of dimensions of the vector space enclosing the BDS;

    \param kind
    Specifies whether the universe or the empty BDS has to be built.
  */
  explicit BD_Shape(dimension_type num_dimensions = 0,
		    Degenerate_Element kind = UNIVERSE);

  //! Ordinary copy-constructor.
  BD_Shape(const BD_Shape& y);

  //! Builds a conservative, upward approximation of \p y.
  template <typename U>
  explicit BD_Shape(const BD_Shape<U>& y);

  //! Builds a BDS from the system of constraints \p cs.
  /*!
    The BDS inherits the space dimension of \p cs.

    \param cs
    A system of constraints: constraints that are not
    \ref Bounded_Difference_Shapes "bounded differences"
    are ignored (even though they may have contributed
    to the space dimension).

    \exception std::invalid_argument
    Thrown if the system of constraints \p cs contains strict inequalities.
  */
  BD_Shape(const Constraint_System& cs);

  //! Builds a BDS from the system of generators \p gs.
  /*!
    Builds the smallest BDS containing the polyhedron defined by \p gs.
    The BDS inherits the space dimension of \p gs.

    \exception std::invalid_argument
    Thrown if the system of generators is not empty but has no points.
  */
  BD_Shape(const Generator_System& gs);

  //! Builds a BDS from the polyhedron \p ph.
  /*!
    Builds a BDS containing \p ph using algorithms whose complexity
    does not exceed the one specified by \p complexity.  If
    \p complexity is \p ANY_COMPLEXITY, then the BDS built is the
    smallest one containing \p ph.
  */
  BD_Shape(const Polyhedron& ph, Complexity_Class complexity = ANY_COMPLEXITY);

  /*! \brief
    The assignment operator
    (\p *this and \p y can be dimension-incompatible).
  */
  BD_Shape& operator=(const BD_Shape& y);

  /*! \brief
    Swaps \p *this with \p y
    (\p *this and \p y can be dimension-incompatible).
  */
  void swap(BD_Shape& y);

  //! Destructor.
  ~BD_Shape();

  //@} Constructors, Assignment, Swap and Destructor

  //! \name Member Functions that Do Not Modify the BD_Shape
  //@{

  //! Returns the dimension of the vector space enclosing \p *this.
  dimension_type space_dimension() const;

  /*! \brief
    Returns \f$0\f$, if \p *this is empty; otherwise, returns the
    \ref Affine_Independence_and_Affine_Dimension "affine dimension"
    of \p *this.
  */
  dimension_type affine_dimension() const;

  //! Returns a system of constraints defining \p *this.
  Constraint_System constraints() const;

  //! Returns a minimized system of constraints defining \p *this.
  Constraint_System minimized_constraints() const;

  //! Returns <CODE>true</CODE> if and only if \p *this contains \p y.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  bool contains(const BD_Shape& y) const;

  //! Returns <CODE>true</CODE> if and only if \p *this strictly contains \p y.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  bool strictly_contains(const BD_Shape& y) const;

  //! Returns the relations holding between \p *this and the constraint \p c.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this and constraint \p c are dimension-incompatible
    or if \p c is a strict inequality or if \p c is not a bounded
    difference constraint.
  */
  Poly_Con_Relation relation_with(const Constraint& c) const;

  //! Returns the relations holding between \p *this and the generator \p g.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this and generator \p g are dimension-incompatible.
  */
  Poly_Gen_Relation relation_with(const Generator& g) const;

  //! Returns <CODE>true</CODE> if and only if \p *this is an empty BDS.
  bool is_empty() const;

  //! Returns <CODE>true</CODE> if and only if \p *this is a universe BDS.
  bool is_universe() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this satisfies
    all its invariants.
  */
  bool OK() const;

  //@} Member Functions that Do Not Modify the BD_Shape

  //! \name Space-Dimension Preserving Member Functions that May Modify the BD_Shape
  //@{

  /*! \brief
    Adds a copy of constraint \p c to the system of bounded differences
    defining \p *this.

    \param c
    The constraint to be added. If it is not a bounded difference, it
    will be simply ignored.

    \exception std::invalid_argument
    Thrown if \p *this and constraint \p c are dimension-incompatible,
    or if \p c is a strict inequality.
  */
  void add_constraint(const Constraint& c);

  /*! \brief
    Adds a copy of constraint \p c to the system of bounded differences
    defining \p *this.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \param c
    The constraint to be added. If it is not a bounded difference, it
    will be simply ignored.

    \exception std::invalid_argument
    Thrown if \p *this and constraint \p c are dimension-incompatible,
    or if \p c is a strict inequality.
  */
  bool add_constraint_and_minimize(const Constraint& c);

  /*! \brief
    Adds the constraints in \p cs to the system of bounded differences
    defining \p *this.

    \param  cs
    The constraints that will be added. Constraints that are not bounded
    differences will be simply ignored.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible,
    or if \p cs contains a strict inequality.
  */
  void add_constraints(const Constraint_System& cs);

  /*! \brief
    Adds the constraints in \p cs to the system of bounded differences
    defining \p *this.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \param  cs
    The constraints that will be added. Constraints that are not bounded
    differences will be simply ignored.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are dimension-incompatible,
    or if \p cs contains a strict inequality.
  */
  bool add_constraints_and_minimize(const Constraint_System& cs);

  //! Assigns to \p *this the intersection of \p *this and \p y.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void intersection_assign(const BD_Shape& y);

  //! Assigns to \p *this the intersection of \p *this and \p y.
  /*!
    \return
    <CODE>false</CODE> if and only if the result is empty.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  bool intersection_assign_and_minimize(const BD_Shape& y);

  /*! \brief
    Assigns to \p *this the smallest BDS containing the convex union
    of \p *this and \p y.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void bds_hull_assign(const BD_Shape& y);

  /*! \brief
    Assigns to \p *this the smallest BDS containing the convex union
    of \p *this and \p y.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  bool bds_hull_assign_and_minimize(const BD_Shape& y);

  //! Same as bds_hull_assign.
  void upper_bound_assign(const BD_Shape& y);

  /*! \brief
    If the bds-hull of \p *this and \p y is exact, it is assigned
    to \p *this and <CODE>true</CODE> is returned,
    otherwise <CODE>false</CODE> is returned.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  bool bds_hull_assign_if_exact(const BD_Shape& y);

  //! Same as bds_hull_assign_if_exact.
  bool upper_bound_assign_if_exact(const BD_Shape& y);

  /*! \brief
    Assigns to \p *this
    the \ref Convex_Polyhedral_Difference "poly-difference"
    of \p *this and \p y.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void bds_difference_assign(const BD_Shape& y);

  //! Same as bds_difference_assign.
  void difference_assign(const BD_Shape& y);

  /*! \brief
    Assigns to \p *this the
    \ref Single_Update_Affine_Functions "affine image"
    of \p *this under the function mapping variable \p var into the
    affine expression specified by \p expr and \p denominator.

    \param var
    The variable to which the affine expression is assigned.

    \param expr
    The numerator of the affine expression.

    \param denominator
    The denominator of the affine expression.

    \exception std::invalid_argument
    Thrown if \p denominator is zero or if \p expr and \p *this
    are dimension-incompatible or if \p var is not a dimension of \p *this.
  */
  void affine_image(Variable var,
		    const Linear_Expression& expr,
		    Coefficient_traits::const_reference denominator
		    = Coefficient_one());

  /*! \brief
    Assigns to \p *this the
    \ref Single_Update_Affine_Functions "affine preimage"
    of \p *this under the function mapping variable \p var into the
    affine expression specified by \p expr and \p denominator.

    \param var
    The variable to which the affine expression is substituted.

    \param expr
    The numerator of the affine expression.

    \param denominator
    The denominator of the affine expression.

    \exception std::invalid_argument
    Thrown if \p denominator is zero or if \p expr and \p *this
    are dimension-incompatible or if \p var is not a dimension of \p *this.
  */
  void affine_preimage(Variable var,
		       const Linear_Expression& expr,
		       Coefficient_traits::const_reference denominator
		       = Coefficient_one());

  /*! \brief
    Assigns to \p *this the image of \p *this with respect to the
    \ref Generalized_Affine_Relations "affine relation"
    \f$\mathrm{var}' \relsym \frac{\mathrm{expr}}{\mathrm{denominator}}\f$,
    where \f$\mathord{\relsym}\f$ is the relation symbol encoded
    by \p relsym.

    \param var
    The left hand side variable of the generalized affine transfer function.

    \param relsym
    The relation symbol.

    \param expr
    The numerator of the right hand side affine expression.

    \param denominator
    The denominator of the right hand side affine expression.

    \exception std::invalid_argument
    Thrown if \p denominator is zero or if \p expr and \p *this
    are dimension-incompatible or if \p var is not a dimension
    of \p *this or if \p relsym is a strict relation symbol.
  */
  void generalized_affine_image(Variable var,
				Relation_Symbol relsym,
				const Linear_Expression& expr,
				Coefficient_traits::const_reference denominator
				= Coefficient_one());

  /*! \brief
    Assigns to \p *this the image of \p *this with respect to the
    \ref Generalized_Affine_Relations "affine relation"
    \f$\mathrm{lhs}' \relsym \mathrm{rhs}\f$, where
    \f$\mathord{\relsym}\f$ is the relation symbol encoded by \p relsym.

    \param lhs
    The left hand side affine expression.

    \param relsym
    The relation symbol.

    \param rhs
    The right hand side affine expression.

    \exception std::invalid_argument
    Thrown if \p *this is dimension-incompatible with \p lhs or \p rhs
    or if \p relsym is a strict relation symbol.
  */
  void generalized_affine_image(const Linear_Expression& lhs,
				Relation_Symbol relsym,
				const Linear_Expression& rhs);

  /*! \brief
    Assigns to \p *this the preimage of \p *this with respect to the
    \ref Generalized_Affine_Relations "affine relation"
    \f$\mathrm{var}' \relsym \frac{\mathrm{expr}}{\mathrm{denominator}}\f$,
    where \f$\mathord{\relsym}\f$ is the relation symbol encoded
    by \p relsym.

    \param var
    The left hand side variable of the generalized affine transfer function.

    \param relsym
    The relation symbol.

    \param expr
    The numerator of the right hand side affine expression.

    \param denominator
    The denominator of the right hand side affine expression.

    \exception std::invalid_argument
    Thrown if \p denominator is zero or if \p expr and \p *this
    are dimension-incompatible or if \p var is not a dimension
    of \p *this or if \p relsym is a strict relation symbol.
  */
  void generalized_affine_preimage(Variable var,
				   Relation_Symbol relsym,
				   const Linear_Expression& expr,
				   Coefficient_traits::const_reference
				   denominator = Coefficient_one());

  /*! \brief
    Assigns to \p *this the result of computing the
    \ref Time_Elapse_Operator "time-elapse" between \p *this and \p y.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void time_elapse_assign(const BD_Shape& y);

  /*! \brief
    Assigns to \p *this the result of computing the
    \ref CC76_extrapolation "CC76-extrapolation" between \p *this and \p y.

    \param y
    A BDS that <EM>must</EM> be contained in \p *this.

    \param tp
    An optional pointer to an unsigned variable storing the number of
    available tokens (to be used when applying the
    \ref Widening_with_Tokens "widening with tokens" delay technique).

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void CC76_extrapolation_assign(const BD_Shape& y, unsigned* tp = 0);

  /*! \brief
    Assigns to \p *this the result of computing the
    \ref CC76_extrapolation "CC76-extrapolation" between \p *this and \p y.

    \param y
    A BDS that <EM>must</EM> be contained in \p *this.

    \param first
    An iterator referencing the first stop-point.

    \param last
    An iterator referencing one past the last stop-point.

    \param tp
    An optional pointer to an unsigned variable storing the number of
    available tokens (to be used when applying the
    \ref Widening_with_Tokens "widening with tokens" delay technique).

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  template <typename Iterator>
  void CC76_extrapolation_assign(const BD_Shape& y,
				 Iterator first, Iterator last,
				 unsigned* tp = 0);

  /*! \brief
    Assigns to \p *this the result of computing the
    \ref BHMZ05_widening "BHMZ05-widening" of \p *this and \p y.

    \param y
    A BDS that <EM>must</EM> be contained in \p *this.

    \param tp
    An optional pointer to an unsigned variable storing the number of
    available tokens (to be used when applying the
    \ref Widening_with_Tokens "widening with tokens" delay technique).

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void BHMZ05_widening_assign(const BD_Shape& y, unsigned* tp = 0);

  /*! \brief
    Improves the result of the \ref BHMZ05_widening "BHMZ05-widening"
    computation by also enforcing those constraints in \p cs that are
    satisfied by all the points of \p *this.

    \param y
    A BDS that <EM>must</EM> be contained in \p *this.

    \param cs
    The system of constraints used to improve the widened BDS.

    \param tp
    An optional pointer to an unsigned variable storing the number of
    available tokens (to be used when applying the
    \ref Widening_with_Tokens "widening with tokens" delay technique).

    \exception std::invalid_argument
    Thrown if \p *this, \p y and \p cs are dimension-incompatible or
    if \p cs contains a strict inequality.
  */
  void limited_BHMZ05_extrapolation_assign(const BD_Shape& y,
					   const Constraint_System& cs,
					   unsigned* tp = 0);

  /*! \brief
    Assigns to \p *this the result of restoring in \p y the constraints
    of \p *this that were lost by
    \ref CC76_extrapolation "CC76-extrapolation" applications.

    \param y
    A BDS that <EM>must</EM> contain \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.

    \note
    As was the case for widening operators, the argument \p y is meant to
    denote the value computed in the previous iteration step, whereas
    \p *this denotes the value computed in the current iteration step
    (in the <EM>descreasing</EM> iteration sequence). Hence, the call
    <CODE>x.CC76_narrowing_assign(y)</CODE> will assign to \p x
    the result of the computation \f$\mathtt{y} \Delta \mathtt{x}\f$.
  */
  void CC76_narrowing_assign(const BD_Shape& y);

  /*! \brief
    Improves the result of the \ref CC76_extrapolation "CC76-extrapolation"
    computation by also enforcing those constraints in \p cs that are
    satisfied by all the points of \p *this.

    \param y
    A BDS that <EM>must</EM> be contained in \p *this.

    \param cs
    The system of constraints used to improve the widened BDS.

    \param tp
    An optional pointer to an unsigned variable storing the number of
    available tokens (to be used when applying the
    \ref Widening_with_Tokens "widening with tokens" delay technique).

    \exception std::invalid_argument
    Thrown if \p *this, \p y and \p cs are dimension-incompatible or
    if \p cs contains a strict inequality.
  */
  void limited_CC76_extrapolation_assign(const BD_Shape& y,
					 const Constraint_System& cs,
					 unsigned* tp = 0);

  /*! \brief
    Assigns to \p *this the result of computing the
    \ref H79_widening "H79-widening" between \p *this and \p y.

    \param y
    A BDS that <EM>must</EM> be contained in \p *this.

    \param tp
    An optional pointer to an unsigned variable storing the number of
    available tokens (to be used when applying the
    \ref Widening_with_Tokens "widening with tokens" delay technique).

    \exception std::invalid_argument
    Thrown if \p *this and \p y are dimension-incompatible.
  */
  void H79_widening_assign(const BD_Shape& y, unsigned* tp = 0);

  /*! \brief
    Improves the result of the \ref H79_widening "H79-widening"
    computation by also enforcing those constraints in \p cs that are
    satisfied by all the points of \p *this.

    \param y
    A BDS that <EM>must</EM> be contained in \p *this.

    \param cs
    The system of constraints used to improve the widened BDS.

    \param tp
    An optional pointer to an unsigned variable storing the number of
    available tokens (to be used when applying the
    \ref Widening_with_Tokens "widening with tokens" delay technique).

    \exception std::invalid_argument
    Thrown if \p *this, \p y and \p cs are dimension-incompatible.
  */
  void limited_H79_extrapolation_assign(const BD_Shape& y,
					const Constraint_System& cs,
					unsigned* tp = 0);

  //@} Space-Dimension Preserving Member Functions that May Modify [...]

  //! \name Member Functions that May Modify the Dimension of the Vector Space
  //@{

  //! Adds \p m new dimensions and embeds the old BDS into the new space.
  /*!
    \param m
    The number of dimensions to add.

    The new dimensions will be those having the highest indexes in the new
    BDS, which is defined by a system of bounded differences in which the
    variables running through the new dimensions are unconstrained.
    For instance, when starting from the BDS \f$\cB \sseq \Rset^2\f$
    and adding a third dimension, the result will be the BDS
    \f[
      \bigl\{\,
        (x, y, z)^\transpose \in \Rset^3
      \bigm|
        (x, y)^\transpose \in \cB
      \,\bigr\}.
    \f]
  */
  void add_space_dimensions_and_embed(dimension_type m);

  /*! \brief
    Adds \p m new dimensions to the BDS and does not embed it in
    the new vector space.

    \param m
    The number of dimensions to add.

    The new dimensions will be those having the highest indexes in the
    new BDS, which is defined by a system of bounded differences in
    which the variables running through the new dimensions are all
    constrained to be equal to 0.
    For instance, when starting from the BDS \f$\cB \sseq \Rset^2\f$
    and adding a third dimension, the result will be the BDS
    \f[
      \bigl\{\,
        (x, y, 0)^\transpose \in \Rset^3
      \bigm|
        (x, y)^\transpose \in \cB
      \,\bigr\}.
    \f]
  */
  void add_space_dimensions_and_project(dimension_type m);

  /*! \brief
    Seeing a BDS as a set of tuples (its points),
    assigns to \p *this all the tuples that can be obtained by concatenating,
    in the order given, a tuple of \p *this with a tuple of \p y.

    Let \f$B \sseq \Rset^n\f$ and \f$D \sseq \Rset^m\f$ be the BDSs
    corresponding, on entry, to \p *this and \p y, respectively.
    Upon successful completion, \p *this will represent the BDS
    \f$R \sseq \Rset^{n+m}\f$ such that
    \f[
      R \defeq
          \Bigl\{\,
            (x_1, \ldots, x_n, y_1, \ldots, y_m)^\transpose
          \Bigm|
            (x_1, \ldots, x_n)^\transpose \in B,
            (y_1, \ldots, y_m)^\transpose \in D
          \,\Bigl\}.
    \f]
    Another way of seeing it is as follows: first increases the space
    dimension of \p *this by adding \p y.space_dimension() new
    dimensions; then adds to the system of constraints of \p *this a
    renamed-apart version of the constraints of \p y.
  */
  void concatenate_assign(const BD_Shape& y);

  //! Removes all the specified dimensions.
  /*!
    \param to_be_removed
    The set of Variable objects corresponding to the dimensions to be removed.

    \exception std::invalid_argument
    Thrown if \p *this is dimension-incompatible with one of the Variable
    objects contained in \p to_be_removed.
  */
  void remove_space_dimensions(const Variables_Set& to_be_removed);

  /*! \brief
    Removes the higher dimensions so that the resulting space
    will have dimension \p new_dimension.

    \exception std::invalid_argument
    Thrown if \p new_dimension is greater than the space dimension
    of \p *this.
  */
  void remove_higher_space_dimensions(dimension_type new_dimension);

  /*! \brief
    Remaps the dimensions of the vector space according to
    a \ref Mapping_the_Dimensions_of_the_Vector_Space "partial function".

    \param pfunc
    The partial function specifying the destiny of each dimension.

    The template class PartialFunction must provide the following
    methods.
    \code
      bool has_empty_codomain() const
    \endcode
    returns <CODE>true</CODE> if and only if the represented partial
    function has an empty co-domain (i.e., it is always undefined).
    The <CODE>has_empty_codomain()</CODE> method will always be called
    before the methods below.  However, if
    <CODE>has_empty_codomain()</CODE> returns <CODE>true</CODE>, none
    of the functions below will be called.
    \code
      dimension_type max_in_codomain() const
    \endcode
    returns the maximum value that belongs to the co-domain
    of the partial function.
    \code
      bool maps(dimension_type i, dimension_type& j) const
    \endcode
    Let \f$f\f$ be the represented function and \f$k\f$ be the value
    of \p i.  If \f$f\f$ is defined in \f$k\f$, then \f$f(k)\f$ is
    assigned to \p j and <CODE>true</CODE> is returned.
    If \f$f\f$ is undefined in \f$k\f$, then <CODE>false</CODE> is
    returned.

    The result is undefined if \p pfunc does not encode a partial
    function with the properties described in the
    \ref Mapping_the_Dimensions_of_the_Vector_Space
    "specification of the mapping operator".
  */
  template <typename PartialFunction>
  void map_space_dimensions(const PartialFunction& pfunc);

  //@} // Member Functions that May Modify the Dimension of the Vector Space

  PPL_OUTPUT_DECLARATIONS;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Loads from \p s an ASCII representation (as produced by \ref ascii_dump)
    and sets \p *this accordingly.  Returns <CODE>true</CODE> if successful,
    <CODE>false</CODE> otherwise.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  bool ascii_load(std::istream& s);

  friend bool Parma_Polyhedra_Library::operator==<T>(const BD_Shape<T>& x,
						     const BD_Shape<T>& y);
  template <typename Temp, typename To, typename U>
  friend bool Parma_Polyhedra_Library::rectilinear_distance_assign
  (Checked_Number<To, Extended_Number_Policy>& r,
   const BD_Shape<U>& x, const BD_Shape<U>& y, const Rounding_Dir dir,
   Temp& tmp0, Temp& tmp1, Temp& tmp2);
  template <typename Temp, typename To, typename U>
  friend bool Parma_Polyhedra_Library::euclidean_distance_assign
  (Checked_Number<To, Extended_Number_Policy>& r,
   const BD_Shape<U>& x, const BD_Shape<U>& y, const Rounding_Dir dir,
   Temp& tmp0, Temp& tmp1, Temp& tmp2);
  template <typename Temp, typename To, typename U>
  friend bool Parma_Polyhedra_Library::l_infinity_distance_assign
  (Checked_Number<To, Extended_Number_Policy>& r,
   const BD_Shape<U>& x, const BD_Shape<U>& y, const Rounding_Dir dir,
   Temp& tmp0, Temp& tmp1, Temp& tmp2);

private:
  template <typename U> friend class Parma_Polyhedra_Library::BD_Shape;

  //! The matrix representing the system of bounded differences.
  DB_Matrix<N> dbm;

#define PPL_IN_BD_Shape_CLASS
// Automatically generated from PPL source file ../src/BDS_Status.idefs.hh line 1
/* BD_Shape<T>::Status class declaration.
*/


#ifndef PPL_IN_BD_Shape_CLASS
#error "Do not include BDS_Status.idefs.hh directly; use BD_Shape.defs.hh instead."
#endif

//! A conjunctive assertion about a BD_Shape<T> object.
/*! \ingroup PPL_CXX_interface
  The assertions supported are:
  - <EM>zero-dim universe</EM>: the BDS is the zero-dimension
    vector space \f$\Rset^0 = \{\cdot\}\f$;
  - <EM>empty</EM>: the BDS is the empty set;
  - <EM>shortest-path closed</EM>: the BDS is represented by a shortest-path
    closed system of bounded differences, so that all the constraints are
    as tight as possible;
  - <EM>shortest-path reduced</EM>: the BDS is represented by a shortest-path
    closed system of bounded differences and each constraint in such a system
    is marked as being either redundant or non-redundant.

  Not all the conjunctions of these elementary assertions constitute
  a legal Status.  In fact:
  - <EM>zero-dim universe</EM> excludes any other assertion;
  - <EM>empty</EM>: excludes any other assertion;
  - <EM>shortest-path reduced</EM> implies <EM>shortest-path closed</EM>.
*/
class Status {
public:
  //! By default Status is the <EM>zero-dim universe</EM> assertion.
  Status();

  //! \name Test, remove or add an individual assertion from the conjunction.
  //@{
  bool test_zero_dim_univ() const;
  void reset_zero_dim_univ();
  void set_zero_dim_univ();

  bool test_empty() const;
  void reset_empty();
  void set_empty();

  bool test_shortest_path_closed() const;
  void reset_shortest_path_closed();
  void set_shortest_path_closed();

  bool test_shortest_path_reduced() const;
  void reset_shortest_path_reduced();
  void set_shortest_path_reduced();
  //@}

  //! Checks if all the invariants are satisfied.
  bool OK() const;

  PPL_OUTPUT_DECLARATIONS;

  /*! \brief
    Loads from \p s an ASCII representation (as produced by \ref ascii_dump)
    and sets \p *this accordingly.
    Returns <CODE>true</CODE> if successful, <CODE>false</CODE> otherwise.
  */
  bool ascii_load(std::istream& s);

private:
  //! Status is implemented by means of a finite bitset.
  typedef unsigned int flags_t;

  //! \name Bit-masks for the individual assertions.
  //@{
  static const flags_t ZERO_DIM_UNIV         = 0U;
  static const flags_t EMPTY                 = 1U << 0;
  static const flags_t SHORTEST_PATH_CLOSED  = 1U << 1;
  static const flags_t SHORTEST_PATH_REDUCED = 1U << 2;
  //@}

  //! This holds the current bitset.
  flags_t flags;

  //! Construct from a bit-mask.
  Status(flags_t mask);

  //! Check whether <EM>all</EM> bits in \p mask are set.
  bool test_all(flags_t mask) const;

  //! Check whether <EM>at least one</EM> bit in \p mask is set.
  bool test_any(flags_t mask) const;

  //! Set the bits in \p mask.
  void set(flags_t mask);

  //! Reset the bits in \p mask.
  void reset(flags_t mask);
};

// Automatically generated from PPL source file ../src/BD_Shape.defs.hh line 1158
#undef PPL_IN_BD_Shape_CLASS

  //! The status flags to keep track of the internal state.
  Status status;

  //! A matrix of Booleans indicating which constraints are redundant.
  std::vector<std::deque<bool> > redundancy_dbm;

  //! Returns <CODE>true</CODE> if the BDS is known to be empty.
  /*!
    The return value <CODE>false</CODE> does not necessarily
    implies that \p *this is non-empty.
  */
  bool marked_empty()const;

  /*! \brief
    Returns <CODE>true</CODE> if the system of bounded differences
    is known to be shortest-path closed.

    The return value <CODE>false</CODE> does not necessarily
    implies that <CODE>this->dbm</CODE> is not shortest-path closed.
  */
  bool marked_shortest_path_closed()const;

  /*! \brief
    Returns <CODE>true</CODE> if the system of bounded differences
    is known to be shortest-path reduced.

    The return value <CODE>false</CODE> does not necessarily
    implies that <CODE>this->dbm</CODE> is not shortest-path reduced.
  */
  bool marked_shortest_path_reduced()const;

  //! Turns \p *this into an empty BDS.
  void set_empty();

  //! Turns \p *this into an zero-dimensional universe BDS.
  void set_zero_dim_univ();

  //! Assigns to <CODE>this->dbm</CODE> its shortest-path closure.
  void shortest_path_closure_assign() const;

  /*! \brief
    Assigns to <CODE>this->dbm</CODE> its shortest-path closure and
    records into <CODE>this->redundancy_dbm</CODE> which of the entries
    in <CODE>this->dbm</CODE> are redundant.
  */
  void shortest_path_reduction_assign() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if <CODE>this->dbm</CODE>
    is shortest-path closed and <CODE>this->redundancy_dbm</CODE>
    correctly flags the redundant entries in <CODE>this->dbm</CODE>.
  */
  bool is_shortest_path_reduced() const;

  //! Adds the constraint <CODE>dbm[i][j] \<= k</CODE>.
  void add_dbm_constraint(dimension_type i, dimension_type j, N k);
  //! Adds the constraint <CODE>dbm[i][j] \<= num/den</CODE>.
  void add_dbm_constraint(dimension_type i, dimension_type j,
			  Coefficient_traits::const_reference num,
			  Coefficient_traits::const_reference den);

  //! Removes all the constraints on row/column \p v.
  void forget_all_dbm_constraints(dimension_type v);
  //! Removes all binary constraints on row/column \p v.
  void forget_binary_dbm_constraints(dimension_type v);

  //! An helper function for the computation of affine relations.
  /*!
    For each dbm index \p u (less than or equal to \p last_v and different
    from \p v), deduce constraints of the form <CODE>v - u \<= c</CODE>,
    starting from \p pos_sum which is an upper bound for \p v.

    The shortest-path closure is able to deduce the constraint
    <CODE>v - u \<= ub_v - lb_u</CODE>. We can be more precise if variable
    \p u played an active role in the computation of the upper bound for
    \p v, i.e., if the corresponding coefficient
    <CODE>q == sc_expr[u]/sc_den</CODE> is greater than zero. In particular:
      - if <CODE>q \>= 1</CODE>, then <CODE>v - u \<= ub_v - ub_u</CODE>;
      - if <CODE>0 \< q \< 1</CODE>, then
        <CODE>v - u \<= ub_v - (q*ub_u + (1-q)*lb_u)</CODE>.
  */
  void deduce_v_minus_u_bounds(dimension_type v,
			       dimension_type last_v,
			       const Linear_Expression& sc_expr,
			       Coefficient_traits::const_reference sc_den,
			       const N& pos_sum);

  //! An helper function for the computation of affine relations.
  /*!
    For each dbm index \p u (less than or equal to \p last_v and different
    from \p v), deduce constraints of the form <CODE>u - v \<= c</CODE>,
    starting from \p neg_sum which is a lower bound for \p v.

    The shortest-path closure is able to deduce the constraint
    <CODE>u - v \<= ub_u - lb_v</CODE>. We can be more precise if variable
    \p u played an active role in the computation of the lower bound for
    \p v, i.e., if the corresponding coefficient
    <CODE>q == sc_expr[u]/sc_den</CODE> is greater than zero.
    In particular:
      - if <CODE>q \>= 1</CODE>, then <CODE>u - v \<= lb_u - lb_v</CODE>;
      - if <CODE>0 \< q \< 1</CODE>, then
        <CODE>u - v \<= (q*lb_u + (1-q)*ub_u) - lb_v</CODE>.
  */
  void deduce_u_minus_v_bounds(dimension_type v,
			       dimension_type last_v,
			       const Linear_Expression& sc_expr,
			       Coefficient_traits::const_reference sc_den,
			       const N& neg_sum);

  /*! \brief
    Adds to \p limiting_shape the bounded differences in \p cs
    that are satisfied by \p *this.
  */
  void get_limiting_shape(const Constraint_System& cs,
			  BD_Shape& limiting_shape) const;

  //! Compute the (zero-equivalence classes) predecessor relation.
  /*!
    It is assumed that the BDS is not empty and shortest-path closed.
  */
  void compute_predecessors(std::vector<dimension_type>& predecessor) const;

  //! Compute the leaders of zero-equivalence classes.
  /*!
    It is assumed that the BDS is not empty and shortest-path closed.
  */
  void compute_leaders(std::vector<dimension_type>& leaders) const;

#if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
  friend std::ostream&
  Parma_Polyhedra_Library::IO_Operators::operator<<<>(std::ostream& s,
						      const BD_Shape<T>& c);
#else
  // This is too lax than wanted.
  template <typename U>
  friend std::ostream&
  Parma_Polyhedra_Library::IO_Operators::operator<<(std::ostream& s,
						    const BD_Shape<U>& c);
#endif

  //! \name Exception Throwers
  //@{
  void throw_dimension_incompatible(const char* method,
				    const BD_Shape& x) const;

  void throw_dimension_incompatible(const char* method,
				    dimension_type required_dim) const;

  void throw_dimension_incompatible(const char* method,
				    const Constraint& c) const;

  void throw_dimension_incompatible(const char* method,
				    const Generator& g) const;

  void throw_dimension_incompatible(const char* method,
				    const char* name_row,
				    const Linear_Expression& y) const;

  static void throw_constraint_incompatible(const char* method);

  static void throw_expression_too_complex(const char* method,
					   const Linear_Expression& e);

  static void throw_generic(const char* method, const char* reason);
  //@} // Exception Throwers
};


namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::BD_Shape */
template <typename T>
void swap(Parma_Polyhedra_Library::BD_Shape<T>& x,
	  Parma_Polyhedra_Library::BD_Shape<T>& y);

} // namespace std

// Automatically generated from PPL source file ../src/BDS_Status.inlines.hh line 1
/* BD_Shape<T>::Status class implementation: inline functions.
*/


namespace Parma_Polyhedra_Library {

template <typename T>
inline
BD_Shape<T>::Status::Status(flags_t mask)
  : flags(mask) {
}

template <typename T>
inline
BD_Shape<T>::Status::Status()
  : flags(ZERO_DIM_UNIV) {
}

template <typename T>
inline bool
BD_Shape<T>::Status::test_all(flags_t mask) const {
  return (flags & mask) == mask;
}

template <typename T>
inline bool
BD_Shape<T>::Status::test_any(flags_t mask) const {
  return flags & mask;
}

template <typename T>
inline void
BD_Shape<T>::Status::set(flags_t mask) {
  flags |= mask;
}

template <typename T>
inline void
BD_Shape<T>::Status::reset(flags_t mask) {
  flags &= ~mask;
}

template <typename T>
inline bool
BD_Shape<T>::Status::test_zero_dim_univ() const {
  return flags == ZERO_DIM_UNIV;
}

template <typename T>
inline void
BD_Shape<T>::Status::reset_zero_dim_univ() {
  // This is a no-op if the current status is not zero-dim.
  if (flags == ZERO_DIM_UNIV)
    // In the zero-dim space, if it is not the universe it is empty.
    flags = EMPTY;
}

template <typename T>
inline void
BD_Shape<T>::Status::set_zero_dim_univ() {
  // Zero-dim universe is incompatible with anything else.
  flags = ZERO_DIM_UNIV;
}

template <typename T>
inline bool
BD_Shape<T>::Status::test_empty() const {
  return test_any(EMPTY);
}

template <typename T>
inline void
BD_Shape<T>::Status::reset_empty() {
  reset(EMPTY);
}

template <typename T>
inline void
BD_Shape<T>::Status::set_empty() {
  flags = EMPTY;
}

template <typename T>
inline bool
BD_Shape<T>::Status::test_shortest_path_closed() const {
  return test_any(SHORTEST_PATH_CLOSED);
}

template <typename T>
inline void
BD_Shape<T>::Status::reset_shortest_path_closed() {
  // A system is reduced only if it is also closed.
  reset(SHORTEST_PATH_CLOSED | SHORTEST_PATH_REDUCED);
}

template <typename T>
inline void
BD_Shape<T>::Status::set_shortest_path_closed() {
  set(SHORTEST_PATH_CLOSED);
}

template <typename T>
inline bool
BD_Shape<T>::Status::test_shortest_path_reduced() const {
  return test_any(SHORTEST_PATH_REDUCED);
}

template <typename T>
inline void
BD_Shape<T>::Status::reset_shortest_path_reduced() {
  reset(SHORTEST_PATH_REDUCED);
}

template <typename T>
inline void
BD_Shape<T>::Status::set_shortest_path_reduced() {
  assert(test_shortest_path_closed());
  set(SHORTEST_PATH_REDUCED);
}

template <typename T>
bool
BD_Shape<T>::Status::OK() const {
  if (test_zero_dim_univ())
    // Zero-dim universe is OK.
    return true;

  if (test_empty()) {
    Status copy = *this;
    copy.reset_empty();
    if (copy.test_zero_dim_univ())
      return true;
    else {
#ifndef NDEBUG
      std::cerr << "The empty flag is incompatible with any other one."
		<< std::endl;
#endif
      return false;
    }
  }

  // Shortest-path reduction implies shortest-path closure.
  if (test_shortest_path_reduced())
    if (test_shortest_path_closed())
      return true;
    else {
#ifndef NDEBUG
      std::cerr << "The shortest-path reduction flag should also imply "
		<< "the closure flag."
		<< std::endl;
#endif
      return false;
    }

  // Any other case is OK.
  return true;
}


namespace Implementation {

namespace BD_Shapes {

// These are the keywords that indicate the individual assertions.
const std::string zero_dim_univ = "ZE";
const std::string empty = "EM";
const std::string sp_closed = "SPC";
const std::string sp_reduced = "SPR";
const char yes = '+';
const char no = '-';
const char sep = ' ';

/*! \relates Parma_Polyhedra_Library::BD_Shape::Status
  Reads a keyword and its associated on/off flag from \p s.
  Returns <CODE>true</CODE> if the operation is successful,
  returns <CODE>false</CODE> otherwise.
  When successful, \p positive is set to <CODE>true</CODE> if the flag
  is on; it is set to <CODE>false</CODE> otherwise.
*/
inline bool
get_field(std::istream& s, const std::string& keyword, bool& positive) {
  std::string str;
  if (!(s >> str)
      || (str[0] != yes && str[0] != no)
      || str.substr(1) != keyword)
    return false;
  positive = (str[0] == yes);
  return true;
}

} // namespace BD_Shapes

} // namespace Implementation

template <typename T>
void
BD_Shape<T>::Status::ascii_dump(std::ostream& s) const {
  using namespace Implementation::BD_Shapes;
  s << (test_zero_dim_univ() ? yes : no) << zero_dim_univ << sep
    << (test_empty() ? yes : no) << empty << sep
    << sep
    << (test_shortest_path_closed() ? yes : no) << sp_closed << sep
    << (test_shortest_path_reduced() ? yes : no) << sp_reduced << sep;
}

PPL_OUTPUT_TEMPLATE_DEFINITIONS_ASCII_ONLY(T, BD_Shape<T>::Status);

template <typename T>
bool
BD_Shape<T>::Status::ascii_load(std::istream& s) {
  using namespace Implementation::BD_Shapes;
  bool positive;

  if (!get_field(s, zero_dim_univ, positive))
    return false;
  if (positive)
    set_zero_dim_univ();

  if (!get_field(s, empty, positive))
    return false;
  if (positive)
    set_empty();

  if (!get_field(s, sp_closed, positive))
    return false;
  if (positive)
    set_shortest_path_closed();
  else
    reset_shortest_path_closed();

  if (!get_field(s, sp_reduced, positive))
    return false;
  if (positive)
    set_shortest_path_reduced();
  else
    reset_shortest_path_reduced();

  // Check for well-formedness.
  assert(OK());
  return true;
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/BD_Shape.inlines.hh line 1
/* BD_Shape class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/BD_Shape.inlines.hh line 29
#include <cassert>
#include <vector>
#include <iostream>
#include <algorithm>

namespace Parma_Polyhedra_Library {

namespace Implementation {
namespace BD_Shapes {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Extract the numerator and denominator components of \p from.
/*! \relates Parma_Polyhedra_Library::BD_Shape */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename T, typename Policy>
inline void
numer_denom(const Checked_Number<T, Policy>& from,
	    Coefficient& num, Coefficient& den) {
  assert(!is_not_a_number(from)
	 && !is_minus_infinity(from)
	 && !is_plus_infinity(from));
  mpq_class q;
  assign_r(q, from, ROUND_NOT_NEEDED);
  num = q.get_num();
  den = q.get_den();
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Divides \p x by \p y into \p to, rounding the result towards plus infinity.
/*! \relates Parma_Polyhedra_Library::BD_Shape */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename T, typename Policy>
inline void
div_round_up(Checked_Number<T, Policy>& to,
	     Coefficient_traits::const_reference x,
	     Coefficient_traits::const_reference y) {
  mpq_class qx;
  mpq_class qy;
  // Note: this code assumes that a Coefficient is always convertible
  // to an mpq_class without loss of precision.
  assign_r(qx, x, ROUND_NOT_NEEDED);
  assign_r(qy, y, ROUND_NOT_NEEDED);
  div_assign_r(qx, qx, qy, ROUND_NOT_NEEDED);
  assign_r(to, qx, ROUND_UP);
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Assigns to \p x the minimum between \p x and \p y.
/*! \relates Parma_Polyhedra_Library::BD_Shape */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename N>
inline void
min_assign(N& x, const N& y) {
  if (x > y)
    x = y;
}

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Assigns to \p x the maximum between \p x and \p y.
/*! \relates Parma_Polyhedra_Library::BD_Shape */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename N>
inline void
max_assign(N& x, const N& y) {
  if (x < y)
    x = y;
}

} // namespace BD_Shapes
} // namespace Implementation


template <typename T>
inline dimension_type
BD_Shape<T>::max_space_dimension() {
  // One dimension is reserved to have a value of type dimension_type
  // that does not represent a legal dimension.
  return std::min(DB_Matrix<N>::max_num_rows() - 1,
		  DB_Matrix<N>::max_num_columns() - 1);
}

template <typename T>
inline bool
BD_Shape<T>::marked_empty() const {
  return status.test_empty();
}

template <typename T>
inline void
BD_Shape<T>::set_empty() {
  status.set_empty();
  assert(OK());
  assert(marked_empty());
}

template <typename T>
inline void
BD_Shape<T>::set_zero_dim_univ() {
  status.set_zero_dim_univ();
}

template <typename T>
inline bool
BD_Shape<T>::marked_shortest_path_closed() const {
  return status.test_shortest_path_closed();
}

template <typename T>
inline bool
BD_Shape<T>::marked_shortest_path_reduced() const {
  return status.test_shortest_path_reduced();
}

template <typename T>
inline
BD_Shape<T>::BD_Shape(const dimension_type num_dimensions,
		      const Degenerate_Element kind)
  : dbm(num_dimensions + 1), status(), redundancy_dbm() {
  if (kind == EMPTY)
    set_empty();
  else {
    if (num_dimensions > 0)
      // A (non zero-dim) universe BDS is closed.
      status.set_shortest_path_closed();
  }
  assert(OK());
}

template <typename T>
inline
BD_Shape<T>::BD_Shape(const BD_Shape& y)
  : dbm(y.dbm), status(y.status), redundancy_dbm() {
  if (y.marked_shortest_path_reduced())
    redundancy_dbm = y.redundancy_dbm;
}

template <typename T>
template <typename U>
inline
BD_Shape<T>::BD_Shape(const BD_Shape<U>& y)
  : dbm(y.dbm), status(), redundancy_dbm() {
  // TODO: handle flags properly, possibly taking special cases into account.
  if (y.marked_empty())
    set_empty();
  else if (y.status.test_zero_dim_univ())
    set_zero_dim_univ();
}

template <typename T>
inline bool
BD_Shape<T>::add_constraint_and_minimize(const Constraint& c) {
  add_constraint(c);
  shortest_path_closure_assign();
  return !marked_empty();
}

template <typename T>
inline void
BD_Shape<T>::add_constraints(const Constraint_System& cs) {
  for (Constraint_System::const_iterator i = cs.begin(),
	 iend = cs.end(); i != iend; ++i)
    add_constraint(*i);
  assert(OK());
}

template <typename T>
inline bool
BD_Shape<T>::add_constraints_and_minimize(const Constraint_System& cs) {
  add_constraints(cs);
  shortest_path_closure_assign();
  return !marked_empty();
}

template <typename T>
inline
BD_Shape<T>::BD_Shape(const Constraint_System& cs)
  : dbm(cs.space_dimension() + 1), status(), redundancy_dbm() {
  if (cs.space_dimension() > 0)
    // A (non zero-dim) universe BDS is shortest-path closed.
    status.set_shortest_path_closed();
  add_constraints(cs);
  assert(OK());
}

template <typename T>
inline dimension_type
BD_Shape<T>::affine_dimension() const {
  const dimension_type space_dim = space_dimension();

  // Shortest-path closure is necessary to detect emptiness
  // and all (possibly implicit) equalities.
  shortest_path_closure_assign();
  if (marked_empty())
    return 0;

  // The vector `predecessor' is used to represent equivalence classes:
  // `predecessor[i] == i' if and only if `i' is the leader of its
  // equivalence class (i.e., the minimum index in the class);
  std::vector<dimension_type> predecessor;
  compute_predecessors(predecessor);

  // Due to the fictitious variable `0', the affine dimension is one
  // less the number of equivalence classes.
  dimension_type affine_dim = 0;
  // Note: disregard the first equivalence class.
  for (dimension_type i = 1; i <= space_dim; ++i)
    if (predecessor[i] == i)
      ++affine_dim;

  return affine_dim;
}

template <typename T>
inline BD_Shape<T>&
BD_Shape<T>::operator=(const BD_Shape& y) {
  dbm = y.dbm;
  status = y.status;
  if (y.marked_shortest_path_reduced())
    redundancy_dbm = y.redundancy_dbm;
  return *this;
}

template <typename T>
inline
BD_Shape<T>::~BD_Shape() {
}

template <typename T>
inline void
BD_Shape<T>::swap(BD_Shape& y) {
  std::swap(dbm, y.dbm);
  std::swap(status, y.status);
  std::swap(redundancy_dbm, y.redundancy_dbm);
}

template <typename T>
inline dimension_type
BD_Shape<T>::space_dimension() const {
  return dbm.num_rows() - 1;
}

template <typename T>
inline bool
BD_Shape<T>::is_empty() const {
  shortest_path_closure_assign();
  return marked_empty();
}

template <typename T>
inline bool
operator==(const BD_Shape<T>& x, const BD_Shape<T>& y) {
  const dimension_type x_space_dim = x.space_dimension();
  // Dimension-compatibility check.
  if (x_space_dim != y.space_dimension())
    return false;

  // Zero-dim BDSs are equal if and only if they are both empty or universe.
  if (x_space_dim == 0)
    if (x.marked_empty())
      return y.marked_empty();
    else
      return !y.marked_empty();

  // The exact equivalence test requires shortest-path closure.
  x.shortest_path_closure_assign();
  y.shortest_path_closure_assign();

  // If one of two BDSs is empty, then they are equal
  // if and only if the other BDS is empty too.
  if (x.marked_empty())
    return y.marked_empty();
  if (y.marked_empty())
    return false;
  // Check for syntactic equivalence of the two (shortest-path closed)
  // systems of bounded differences.
  return x.dbm == y.dbm;
}

template <typename T>
inline bool
operator!=(const BD_Shape<T>& x, const BD_Shape<T>& y) {
  return !(x == y);
}

/*! \relates BD_Shape */
template <typename Temp, typename To, typename T>
inline bool
rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			    const BD_Shape<T>& x,
			    const BD_Shape<T>& y,
			    const Rounding_Dir dir,
			    Temp& tmp0,
			    Temp& tmp1,
			    Temp& tmp2) {
  const dimension_type x_space_dim = x.space_dimension();
  // Dimension-compatibility check.
  if (x_space_dim != y.space_dimension())
    return false;

  // Zero-dim BDSs are equal if and only if they are both empty or universe.
  if (x_space_dim == 0) {
    if (x.marked_empty() == y.marked_empty())
      assign_r(r, 0, ROUND_NOT_NEEDED);
    else
      r = PLUS_INFINITY;
    return true;
  }

  // The distance computation requires shortest-path closure.
  x.shortest_path_closure_assign();
  y.shortest_path_closure_assign();

  // If one of two BDSs is empty, then they are equal if and only if
  // the other BDS is empty too.
  if (x.marked_empty() ||  y.marked_empty()) {
   if (x.marked_empty() == y.marked_empty())
      assign_r(r, 0, ROUND_NOT_NEEDED);
    else
      r = PLUS_INFINITY;
   return true;
  }

  return rectilinear_distance_assign(r, x.dbm, y.dbm, dir, tmp0, tmp1, tmp2);
}

/*! \relates BD_Shape */
template <typename Temp, typename To, typename T>
inline bool
rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			    const BD_Shape<T>& x,
			    const BD_Shape<T>& y,
			    const Rounding_Dir dir) {
  static Checked_Number<Temp, Extended_Number_Policy> tmp0;
  static Checked_Number<Temp, Extended_Number_Policy> tmp1;
  static Checked_Number<Temp, Extended_Number_Policy> tmp2;
  return rectilinear_distance_assign(r, x, y, dir, tmp0, tmp1, tmp2);
}

/*! \relates BD_Shape */
template <typename To, typename T>
inline bool
rectilinear_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			    const BD_Shape<T>& x,
			    const BD_Shape<T>& y,
			    const Rounding_Dir dir) {
  return rectilinear_distance_assign<To, To, T>(r, x, y, dir);
}

/*! \relates BD_Shape */
template <typename Temp, typename To, typename T>
inline bool
euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			  const BD_Shape<T>& x,
			  const BD_Shape<T>& y,
			  const Rounding_Dir dir,
			  Temp& tmp0,
			  Temp& tmp1,
			  Temp& tmp2) {
  const dimension_type x_space_dim = x.space_dimension();
  // Dimension-compatibility check.
  if (x_space_dim != y.space_dimension())
    return false;

  // Zero-dim BDSs are equal if and only if they are both empty or universe.
  if (x_space_dim == 0) {
    if (x.marked_empty() == y.marked_empty())
      assign_r(r, 0, ROUND_NOT_NEEDED);
    else
      r = PLUS_INFINITY;
    return true;
  }

  // The distance computation requires shortest-path closure.
  x.shortest_path_closure_assign();
  y.shortest_path_closure_assign();

  // If one of two BDSs is empty, then they are equal if and only if
  // the other BDS is empty too.
  if (x.marked_empty() ||  y.marked_empty()) {
   if (x.marked_empty() == y.marked_empty())
      assign_r(r, 0, ROUND_NOT_NEEDED);
    else
      r = PLUS_INFINITY;
   return true;
  }

  return euclidean_distance_assign(r, x.dbm, y.dbm, dir, tmp0, tmp1, tmp2);
}

/*! \relates BD_Shape */
template <typename Temp, typename To, typename T>
inline bool
euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			  const BD_Shape<T>& x,
			  const BD_Shape<T>& y,
			  const Rounding_Dir dir) {
  static Checked_Number<Temp, Extended_Number_Policy> tmp0;
  static Checked_Number<Temp, Extended_Number_Policy> tmp1;
  static Checked_Number<Temp, Extended_Number_Policy> tmp2;
  return euclidean_distance_assign(r, x, y, dir, tmp0, tmp1, tmp2);
}

/*! \relates BD_Shape */
template <typename To, typename T>
inline bool
euclidean_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			  const BD_Shape<T>& x,
			  const BD_Shape<T>& y,
			  const Rounding_Dir dir) {
  return euclidean_distance_assign<To, To, T>(r, x, y, dir);
}

/*! \relates BD_Shape */
template <typename Temp, typename To, typename T>
inline bool
l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			   const BD_Shape<T>& x,
			   const BD_Shape<T>& y,
			   const Rounding_Dir dir,
			   Temp& tmp0,
			   Temp& tmp1,
			   Temp& tmp2) {
  const dimension_type x_space_dim = x.space_dimension();
  // Dimension-compatibility check.
  if (x_space_dim != y.space_dimension())
    return false;

  // Zero-dim BDSs are equal if and only if they are both empty or universe.
  if (x_space_dim == 0) {
    if (x.marked_empty() == y.marked_empty())
      assign_r(r, 0, ROUND_NOT_NEEDED);
    else
      r = PLUS_INFINITY;
    return true;
  }

  // The distance computation requires shortest-path closure.
  x.shortest_path_closure_assign();
  y.shortest_path_closure_assign();

  // If one of two BDSs is empty, then they are equal if and only if
  // the other BDS is empty too.
  if (x.marked_empty() ||  y.marked_empty()) {
   if (x.marked_empty() == y.marked_empty())
      assign_r(r, 0, ROUND_NOT_NEEDED);
    else
      r = PLUS_INFINITY;
   return true;
  }

  return l_infinity_distance_assign(r, x.dbm, y.dbm, dir, tmp0, tmp1, tmp2);
}

/*! \relates BD_Shape */
template <typename Temp, typename To, typename T>
inline bool
l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			   const BD_Shape<T>& x,
			   const BD_Shape<T>& y,
			   const Rounding_Dir dir) {
  static Checked_Number<Temp, Extended_Number_Policy> tmp0;
  static Checked_Number<Temp, Extended_Number_Policy> tmp1;
  static Checked_Number<Temp, Extended_Number_Policy> tmp2;
  return l_infinity_distance_assign(r, x, y, dir, tmp0, tmp1, tmp2);
}

/*! \relates BD_Shape */
template <typename To, typename T>
inline bool
l_infinity_distance_assign(Checked_Number<To, Extended_Number_Policy>& r,
			   const BD_Shape<T>& x,
			   const BD_Shape<T>& y,
			   const Rounding_Dir dir) {
  return l_infinity_distance_assign<To, To, T>(r, x, y, dir);
}

template <typename T>
inline void
BD_Shape<T>::add_dbm_constraint(const dimension_type i,
				const dimension_type j,
				N k) {
  // Private method: the caller has to ensure the following.
  assert(i <= space_dimension() && j <= space_dimension() && i != j);
  N& dbm_ij = dbm[i][j];
  if (dbm_ij > k) {
    dbm_ij = k;
    if (marked_shortest_path_closed())
      status.reset_shortest_path_closed();
  }
  assert(OK());
}

template <typename T>
inline void
BD_Shape<T>::add_dbm_constraint(const dimension_type i,
				const dimension_type j,
				Coefficient_traits::const_reference num,
				Coefficient_traits::const_reference den) {
  // Private method: the caller has to ensure the following.
  assert(i <= space_dimension() && j <= space_dimension() && i != j);
  assert(den != 0);
  N k;
  Implementation::BD_Shapes::div_round_up(k, num, den);
  add_dbm_constraint(i, j, k);
}

template <typename T>
inline bool
BD_Shape<T>::strictly_contains(const BD_Shape& y) const {
  const BD_Shape<T>& x = *this;
  return x.contains(y) && !y.contains(x);
}

template <typename T>
inline bool
BD_Shape<T>::bds_hull_assign_and_minimize(const BD_Shape& y) {
  bds_hull_assign(y);
  assert(marked_empty()
	 || space_dimension() == 0 || marked_shortest_path_closed());
  return !marked_empty();
}

template <typename T>
inline void
BD_Shape<T>::upper_bound_assign(const BD_Shape& y) {
  bds_hull_assign(y);
}

template <typename T>
inline bool
BD_Shape<T>::bds_hull_assign_if_exact(const BD_Shape&) {
  // TODO: this must be properly implemented.
  return false;
}

template <typename T>
inline bool
BD_Shape<T>::upper_bound_assign_if_exact(const BD_Shape& y) {
  return bds_hull_assign_if_exact(y);
}

template <typename T>
inline void
BD_Shape<T>::difference_assign(const BD_Shape& y) {
  bds_difference_assign(y);
}

template <typename T>
inline void
BD_Shape<T>::remove_higher_space_dimensions(const dimension_type new_dim) {
  // Dimension-compatibility check: the variable having
  // maximum index is the one occurring last in the set.
  if (new_dim > space_dimension())
    throw_dimension_incompatible("remove_higher_space_dimensions(nd)",
				 new_dim);

  // The removal of no dimensions from any BDS is a no-op.
  // Note that this case also captures the only legal removal of
  // dimensions from a zero-dim space BDS.
  if (new_dim == space_dimension()) {
    assert(OK());
    return;
  }

  // Shortest-path closure is necessary as in remove_space_dimensions().
  shortest_path_closure_assign();
  dbm.resize_no_copy(new_dim + 1);

  // Shortest-path closure is maintained.
  // TODO: see whether or not reduction can be (efficiently!) maintained too.
  if (marked_shortest_path_reduced())
    status.reset_shortest_path_reduced();

  // If we removed _all_ dimensions from a non-empty BDS,
  // the zero-dim universe BDS has been obtained.
  if (new_dim == 0 && !marked_empty())
    set_zero_dim_univ();
  assert(OK());
}

template <typename T>
inline bool
BD_Shape<T>::intersection_assign_and_minimize(const BD_Shape& y) {
  intersection_assign(y);
  shortest_path_closure_assign();
  return !marked_empty();
}

template <typename T>
inline void
BD_Shape<T>::CC76_extrapolation_assign(const BD_Shape& y, unsigned* tp) {
  static N stop_points[] = {
    N(-2, ROUND_UP),
    N(-1, ROUND_UP),
    N( 0, ROUND_UP),
    N( 1, ROUND_UP),
    N( 2, ROUND_UP)
  };
  CC76_extrapolation_assign(y,
			    stop_points,
			    stop_points
			    + sizeof(stop_points)/sizeof(stop_points[0]),
			    tp);
}

template <typename T>
inline void
BD_Shape<T>::H79_widening_assign(const BD_Shape& y, unsigned* tp) {
  // See the documentation for polyhedra.
  C_Polyhedron px(constraints());
  C_Polyhedron py(y.constraints());
  px.H79_widening_assign(py, tp);
  BD_Shape x(px);
  swap(x);
  assert(OK());
}

template <typename T>
inline void
BD_Shape<T>::limited_H79_extrapolation_assign(const BD_Shape& y,
					      const Constraint_System& cs,
					      unsigned* tp) {
  // See the documentation for polyhedra.
  C_Polyhedron px(constraints());
  C_Polyhedron py(y.constraints());
  px.limited_H79_extrapolation_assign(py, cs, tp);
  BD_Shape x(px);
  swap(x);
  assert(OK());
}

template <typename T>
inline void
BD_Shape<T>::time_elapse_assign(const BD_Shape& y) {
  // Dimension-compatibility check.
  if (space_dimension() != y.space_dimension())
    throw_dimension_incompatible("time_elapse_assign(y)", y);
  // See the documentation for polyhedra.
  C_Polyhedron px(constraints());
  C_Polyhedron py(y.constraints());
  px.time_elapse_assign(py);
  BD_Shape x(px);
  swap(x);
  assert(OK());
}

template <typename T>
inline void
BD_Shape<T>::forget_all_dbm_constraints(const dimension_type v) {
  assert(0 < v && v <= dbm.num_rows());
  DB_Row<N>& dbm_v = dbm[v];
  for (dimension_type i = dbm.num_rows(); i-- > 0; ) {
    dbm_v[i] = PLUS_INFINITY;
    dbm[i][v] = PLUS_INFINITY;
  }
}

template <typename T>
inline void
BD_Shape<T>::forget_binary_dbm_constraints(const dimension_type v) {
  assert(0 < v && v <= dbm.num_rows());
  DB_Row<N>& dbm_v = dbm[v];
  for (dimension_type i = dbm.num_rows()-1; i > 0; --i) {
    dbm_v[i] = PLUS_INFINITY;
    dbm[i][v] = PLUS_INFINITY;
  }
}

} // namespace Parma_Polyhedra_Library

namespace std {

/*! \relates Parma_Polyhedra_Library::BD_Shape */
template <typename T>
inline void
swap(Parma_Polyhedra_Library::BD_Shape<T>& x,
     Parma_Polyhedra_Library::BD_Shape<T>& y) {
  x.swap(y);
}

} // namespace std

// Automatically generated from PPL source file ../src/BD_Shape.templates.hh line 1
/* BD_Shape class implementation: non-inline template functions.
*/


// Automatically generated from PPL source file ../src/BD_Shape.templates.hh line 29
#include <cassert>
#include <vector>
#include <deque>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <algorithm>

namespace Parma_Polyhedra_Library {

template <typename T>
BD_Shape<T>::BD_Shape(const Generator_System& gs)
  : dbm(gs.space_dimension() + 1), status(), redundancy_dbm() {
  using Implementation::BD_Shapes::max_assign;
  using Implementation::BD_Shapes::div_round_up;

  const Generator_System::const_iterator gs_begin = gs.begin();
  const Generator_System::const_iterator gs_end = gs.end();
  if (gs_begin == gs_end) {
    // An empty generator system defines the empty polyhedron.
    set_empty();
    assert(OK());
    return;
  }

  const dimension_type space_dim = space_dimension();
  DB_Row<N>& dbm_0 = dbm[0];
  N tmp;

  bool dbm_initialized = false;
  bool point_seen = false;
  // Going through all the points and closure points.
  for (Generator_System::const_iterator i = gs_begin; i != gs_end; ++i) {
    const Generator& g = *i;
    switch (g.type()) {
    case Generator::POINT:
      point_seen = true;
      // Intentionally fall through.
    case Generator::CLOSURE_POINT:
      if (!dbm_initialized) {
	// When handling the first (closure) point, we initialize the DBM.
	dbm_initialized = true;
	const Coefficient& d = g.divisor();
	for (dimension_type i = space_dim; i > 0; --i) {
	  const Coefficient& g_i = g.coefficient(Variable(i-1));
	  DB_Row<N>& dbm_i = dbm[i];
	  for (dimension_type j = space_dim; j > 0; --j)
	    if (i != j)
	      div_round_up(dbm_i[j], g.coefficient(Variable(j-1)) - g_i, d);
	  div_round_up(dbm_i[0], -g_i, d);
	}
	for (dimension_type j = space_dim; j > 0; --j)
	  div_round_up(dbm_0[j], g.coefficient(Variable(j-1)), d);
	// Note: no need to initialize the first element of the main diagonal.
      }
      else {
	// This is not the first point: the DBM already contains
	// valid values and we must compute maxima.
	const Coefficient& d = g.divisor();
	for (dimension_type i = space_dim; i > 0; --i) {
	  const Coefficient& g_i = g.coefficient(Variable(i-1));
	  DB_Row<N>& dbm_i = dbm[i];
	  // The loop correctly handles the case when i == j.
	  for (dimension_type j = space_dim; j > 0; --j) {
	    div_round_up(tmp, g.coefficient(Variable(j-1)) - g_i, d);
	    max_assign(dbm_i[j], tmp);
	  }
	  div_round_up(tmp, -g_i, d);
	  max_assign(dbm_i[0], tmp);
	}
	for (dimension_type j = space_dim; j > 0; --j) {
	  div_round_up(tmp, g.coefficient(Variable(j-1)), d);
	  max_assign(dbm_0[j], tmp);
	}
      }
      break;
    default:
      // Lines and rays temporarily ignored.
      break;
    }
  }

  if (!point_seen)
    // The generator system is not empty, but contains no points.
    throw std::invalid_argument("PPL::BD_Shape<T>::BD_Shape(gs):\n"
				"the non-empty generator system gs "
				"contains no points.");

  // Going through all the lines and rays.
  for (Generator_System::const_iterator i = gs_begin; i != gs_end; ++i) {
    const Generator& g = *i;
    switch (g.type()) {
    case Generator::LINE:
      for (dimension_type i = space_dim; i > 0; --i) {
	const Coefficient& g_i = g.coefficient(Variable(i-1));
	DB_Row<N>& dbm_i = dbm[i];
	// The loop correctly handles the case when i == j.
	for (dimension_type j = space_dim; j > 0; --j)
	  if (g_i != g.coefficient(Variable(j-1)))
	    dbm_i[j] = PLUS_INFINITY;
	if (g_i != 0)
	  dbm_i[0] = PLUS_INFINITY;
      }
      for (dimension_type j = space_dim; j > 0; --j)
	if (g.coefficient(Variable(j-1)) != 0)
	  dbm_0[j] = PLUS_INFINITY;
      break;
    case Generator::RAY:
      for (dimension_type i = space_dim; i > 0; --i) {
	const Coefficient& g_i = g.coefficient(Variable(i-1));
	DB_Row<N>& dbm_i = dbm[i];
	// The loop correctly handles the case when i == j.
	for (dimension_type j = space_dim; j > 0; --j)
	  if (g_i < g.coefficient(Variable(j-1)))
	    dbm_i[j] = PLUS_INFINITY;
	if (g_i < 0)
	  dbm_i[0] = PLUS_INFINITY;
      }
      for (dimension_type j = space_dim; j > 0; --j)
	if (g.coefficient(Variable(j-1)) > 0)
	  dbm_0[j] = PLUS_INFINITY;
      break;
    default:
      // Points and closure points already dealt with.
      break;
    }
  }
  status.set_shortest_path_closed();
  assert(OK());
}

template <typename T>
BD_Shape<T>::BD_Shape(const Polyhedron& ph, const Complexity_Class complexity)
  : dbm(), status(), redundancy_dbm() {
  using Implementation::BD_Shapes::div_round_up;
  const dimension_type num_dimensions = ph.space_dimension();

  if (ph.marked_empty()) {
    *this = BD_Shape(num_dimensions, EMPTY);
    return;
  }

  if (num_dimensions == 0) {
    *this = BD_Shape(num_dimensions, UNIVERSE);
    return;
  }

  // Build from generators when we do not care about complexity
  // or when the process has polynomial complexity.
  if (complexity == ANY_COMPLEXITY
      || (!ph.has_pending_constraints() && ph.generators_are_up_to_date())) {
    *this = BD_Shape(ph.generators());
    return;
  }

  // We cannot afford exponential complexity, we do not have a complete set
  // of generators for the polyhedron, and the polyhedron is not trivially
  // empty or zero-dimensional.  Constraints, however, are up to date.
  assert(ph.constraints_are_up_to_date());

  if (!ph.has_something_pending() && ph.constraints_are_minimized()) {
    // If the constraint system of the polyhedron is minimized,
    // the test `is_universe()' has polynomial complexity.
    if (ph.is_universe()) {
      *this = BD_Shape(num_dimensions, UNIVERSE);
      return;
    }
  }

  // See if there is at least one inconsistent constraint in `ph.con_sys'.
  for (Constraint_System::const_iterator i = ph.con_sys.begin(),
	 cs_end = ph.con_sys.end(); i != cs_end; ++i)
    if (i->is_inconsistent()) {
      *this = BD_Shape(num_dimensions, EMPTY);
      return;
    }

  // If `complexity' allows it, use simplex to derive the exact (modulo
  // the fact that our BDSs are topologically closed) variable bounds.
  if (complexity == SIMPLEX_COMPLEXITY) {
    LP_Problem lp;
    lp.set_optimization_mode(MAXIMIZATION);

    const Constraint_System& ph_cs = ph.constraints();
    if (!ph_cs.has_strict_inequalities())
      lp.add_constraints(ph_cs);
    else
      // Adding to `lp' a topologically closed version of `ph_cs'.
      for (Constraint_System::const_iterator i = ph_cs.begin(),
	     iend = ph_cs.end(); i != iend; ++i) {
	const Constraint& c = *i;
	lp.add_constraint(c.is_equality()
			  ? (Linear_Expression(c) == 0)
			  : (Linear_Expression(c) >= 0));
      }

    // Check for unsatisfiability.
    if (!lp.is_satisfiable()) {
      *this = BD_Shape(num_dimensions, EMPTY);
      return;
    }

    // Get all the upper bounds.
    LP_Problem_Status lp_status;
    Generator g(point());
    TEMP_INTEGER(num);
    TEMP_INTEGER(den);
    for (dimension_type i = 1; i <= num_dimensions; ++i) {
      Variable x(i-1);
      // Evaluate optimal upper bound for `x <= ub'.
      lp.set_objective_function(x);
      lp_status = lp.solve();
      if (lp_status == UNBOUNDED_LP_PROBLEM)
	dbm[0][i] = PLUS_INFINITY;
      else {
	assert(lp_status == OPTIMIZED_LP_PROBLEM);
	g = lp.optimizing_point();
	lp.evaluate_objective_function(g, num, den);
	div_round_up(dbm[0][i], num, den);
      }
      // Evaluate optimal upper bound for `x - y <= ub'.
      for (dimension_type j = 1; j <= num_dimensions; ++j) {
	if (i == j)
	  continue;
	Variable y(j-1);
	lp.set_objective_function(x - y);
	lp_status = lp.solve();
	if (lp_status == UNBOUNDED_LP_PROBLEM)
	  dbm[j][i] = PLUS_INFINITY;
	else {
	  assert(lp_status == OPTIMIZED_LP_PROBLEM);
	  g = lp.optimizing_point();
	  lp.evaluate_objective_function(g, num, den);
	  div_round_up(dbm[j][i], num, den);
	}
      }
      // Evaluate optimal upper bound for `-x <= ub'.
      lp.set_objective_function(-x);
      lp_status = lp.solve();
      if (lp_status == UNBOUNDED_LP_PROBLEM)
	dbm[i][0] = PLUS_INFINITY;
      else {
	assert(lp_status == OPTIMIZED_LP_PROBLEM);
	g = lp.optimizing_point();
	lp.evaluate_objective_function(g, num, den);
	div_round_up(dbm[i][0], num, den);
      }
    }
    status.set_shortest_path_closed();
    return;
  }

  // Extract easy-to-find bounds from constraints.
  *this = BD_Shape(ph.con_sys);
}

template <typename T>
void
BD_Shape<T>::add_constraint(const Constraint& c) {
  using Implementation::BD_Shapes::div_round_up;

  const dimension_type c_space_dim = c.space_dimension();
  // Dimension-compatibility check.
  if (c_space_dim > space_dimension())
    throw_dimension_incompatible("add_constraint(c)", c);
  // Strict inequalities are not allowed.
  if (c.is_strict_inequality())
    throw_constraint_incompatible("add_constraint(c)");

  dimension_type num_vars = 0;
  dimension_type i = 0;
  dimension_type j = 0;
  TEMP_INTEGER(coeff);
  // Constraints that are not bounded differences are ignored.
  if (!extract_bounded_difference(c, c_space_dim, num_vars, i, j, coeff))
    return;

  if (num_vars == 0) {
    // Dealing with a trivial constraint.
    if (c.inhomogeneous_term() < 0)
      set_empty();
    return;
  }

  // Select the cell to be modified for the "<=" part of the constraint,
  // and set `coeff' to the absolute value of itself.
  N& x = (coeff < 0) ? dbm[i][j] : dbm[j][i];
  N& y = (coeff < 0) ? dbm[j][i] : dbm[i][j];
  if (coeff < 0)
    coeff = -coeff;

  bool changed = false;
  // Compute the bound for `x', rounding towards plus infinity.
  N d;
  div_round_up(d, c.inhomogeneous_term(), coeff);
  if (x > d) {
    x = d;
    changed = true;
  }

  if (c.is_equality()) {
    // Also compute the bound for `y', rounding towards plus infinity.
    div_round_up(d, -c.inhomogeneous_term(), coeff);
    if (y > d) {
      y = d;
      changed = true;
    }
  }

  // In general, adding a constraint does not preserve the shortest-path
  // closure or reduction of the system of bounded differences.
  if (changed && marked_shortest_path_closed())
    status.reset_shortest_path_closed();
  assert(OK());
}

template <typename T>
void
BD_Shape<T>::concatenate_assign(const BD_Shape& y) {
  BD_Shape& x = *this;

  const dimension_type x_space_dim = x.space_dimension();
  const dimension_type y_space_dim = y.space_dimension();

  // If `y' is an empty 0-dim space system of bounded differences,
  // let `*this' become empty.
  if (y_space_dim == 0 && y.marked_empty()) {
    set_empty();
    assert(OK());
    return;
  }

  // If `x' is an empty 0-dim space BDS, then it is sufficient to adjust
  // the dimension of the vector space.
  if (x_space_dim == 0 && marked_empty()) {
    dbm.grow(y_space_dim + 1);
    assert(OK());
    return;
  }
  // First we increase the space dimension of `x' by adding
  // `y.space_dimension()' new dimensions.
  // The matrix for the new system of constraints is obtained
  // by leaving the old system of constraints in the upper left-hand side
  // and placing the constraints of `y' in the lower right-hand side,
  // except the constraints as `y(i) >= cost' or `y(i) <= cost', that are
  // placed in the right position on the new matrix.
  add_space_dimensions_and_embed(y_space_dim);
  const dimension_type new_space_dim = x_space_dim + y_space_dim;
  for (dimension_type i = x_space_dim + 1; i <= new_space_dim; ++i) {
    DB_Row<N>& dbm_i = dbm[i];
    dbm_i[0] = y.dbm[i - x_space_dim][0];
    dbm[0][i] = y.dbm[0][i - x_space_dim];
    for (dimension_type j = x_space_dim + 1; j <= new_space_dim; ++j)
      dbm_i[j] = y.dbm[i - x_space_dim][j - x_space_dim];
  }

  if (marked_shortest_path_closed())
    status.reset_shortest_path_closed();
  assert(OK());
}

template <typename T>
bool
BD_Shape<T>::contains(const BD_Shape& y) const {
  const BD_Shape<T>& x = *this;
  const dimension_type x_space_dim = x.space_dimension();

  // Dimension-compatibility check.
  if (x_space_dim != y.space_dimension())
    throw_dimension_incompatible("contains(y)", y);

  // The zero-dimensional universe shape contains any other
  // dimension-compatible shape.
  // The zero-dimensional empty shape only contains another
  // zero-dimensional empty shape.
  if (x_space_dim == 0) {
    if (!marked_empty())
      return true;
    else
      return y.marked_empty();
  }

  /*
    The `y' system of bounded differences need be closed.
    In fact if, for example, in `*this' we have the constraints:

    x1 - x2 <= 1;
    x1      <= 3;
    x2      <= 2;

    in `y' the constraints are:

    x1 - x2 <= 0;
    x2      <= 1;

    without closure it returns "false", instead if we close `y' we have
    the implicit constraint

    x1      <= 1;

    and so we obtain the right result "true".
  */
  y.shortest_path_closure_assign();

  // An empty shape is contained in any other dimension-compatible shapes.
  if (y.marked_empty())
    return true;

  // `*this' contains `y' if and only if every cell of `dbm'
  // is greater than or equal to the correspondent one of `y.dbm'.
  for (dimension_type i = x_space_dim + 1; i-- > 0; ) {
    const DB_Row<N>& x_dbm_i = x.dbm[i];
    const DB_Row<N>& y_dbm_i = y.dbm[i];
    for (dimension_type j = x_space_dim + 1; j-- > 0; )
      if (x_dbm_i[j] < y_dbm_i[j])
	return false;
  }
  return true;
}

template <typename T>
bool
BD_Shape<T>::is_universe() const {
  if (marked_empty())
    return false;

  const dimension_type space_dim = space_dimension();
  // If the BDS is non-empty and zero-dimensional,
  // then it is necessarily the universe BDS.
  if (space_dim == 0)
    return true;

  // A system of bounded differences defining the universe BDS can only
  // contain trivial constraints.
  for (dimension_type i = space_dim + 1; i-- > 0; ) {
    const DB_Row<N>& dbm_i = dbm[i];
    for (dimension_type j = space_dim + 1; j-- > 0; )
      if (!is_plus_infinity(dbm_i[j]))
	return false;
  }
  return true;
}

template <typename T>
void
BD_Shape<T>
::compute_predecessors(std::vector<dimension_type>& predecessor) const {
  assert(!marked_empty() && marked_shortest_path_closed());
  assert(predecessor.size() == 0);
  // Variables are ordered according to their index.
  // The vector `predecessor' is used to indicate which variable
  // immediately precedes a given one in the corresponding equivalence class.
  // The `leader' of an equivalence class is the element having minimum
  // index: leaders are their own predecessors.
  const dimension_type pred_size = dbm.num_rows();
  // Initially, each variable is leader of its own zero-equivalence class.
  predecessor.reserve(pred_size);
  for (dimension_type i = 0; i < pred_size; ++i)
    predecessor.push_back(i);
  // Now compute actual predecessors.
  for (dimension_type i = pred_size; i-- > 1; )
    if (i == predecessor[i]) {
      const DB_Row<N>& dbm_i = dbm[i];
      for (dimension_type j = i; j-- > 0; )
	if (j == predecessor[j]) {
	  N negated_dbm_ji;
	  if (neg_assign_r(negated_dbm_ji, dbm[j][i], ROUND_NOT_NEEDED) == V_EQ
	      && negated_dbm_ji == dbm_i[j]) {
	    // Choose as predecessor the variable having the smaller index.
	    predecessor[i] = j;
	    break;
	  }
	}
    }
}

template <typename T>
void
BD_Shape<T>::compute_leaders(std::vector<dimension_type>& leaders) const {
  assert(!marked_empty() && marked_shortest_path_closed());
  assert(leaders.size() == 0);
  // Compute predecessor information.
  compute_predecessors(leaders);
  // Flatten the predecessor chains so as to obtain leaders.
  assert(leaders[0] == 0);
  for (dimension_type i = 1, iend = leaders.size(); i != iend; ++i) {
    const dimension_type l_i = leaders[i];
    assert(l_i <= i);
    if (l_i != i) {
      const dimension_type ll_i = leaders[l_i];
      assert(ll_i == leaders[ll_i]);
      leaders[i] = ll_i;
    }
  }
}

template <typename T>
bool
BD_Shape<T>::is_shortest_path_reduced() const {
  // If the BDS is empty, it is also reduced.
  if (marked_empty())
    return true;

  // A shortest-path reduced dbm is just a dbm with an indication of
  // those constraints that are redundant. If there is no indication
  // of the redundant constraints, then it cannot be reduced.
  if (!marked_shortest_path_reduced())
    return false;

  const BD_Shape x_copy = *this;
  const dimension_type x_space_dim = x_copy.space_dimension();
  x_copy.shortest_path_closure_assign();
  // If we just discovered emptyness, it cannot be reduced.
  if (x_copy.marked_empty())
    return false;

  // The vector `leader' is used to indicate which variables are equivalent.
  std::vector<dimension_type> leader(x_space_dim + 1);

  // We store the leader.
  for (dimension_type i = x_space_dim + 1; i-- > 0; )
    leader[i] = i;

  // Step 1: we store really the leader with the corrected value.
  // We search for the equivalent or zero-equivalent variables.
  // The variable(i-1) and variable(j-1) are equivalent if and only if
  // m_i_j == -(m_j_i).
  for (dimension_type i = 0; i < x_space_dim; ++i) {
    const DB_Row<N>& xdbm_i = x_copy.dbm[i];
    for (dimension_type j = i + 1; j <= x_space_dim; ++j) {
      N negated_xdbm_ji;
      if (neg_assign_r(negated_xdbm_ji, x_copy.dbm[j][i],
		       ROUND_NOT_NEEDED) == V_EQ
	  && negated_xdbm_ji == xdbm_i[j])
	// Two equivalent variables have got the same leader
	// (the smaller variable).
	leader[j] = leader[i];
    }
  }

  // Step 2: we check if there are redundant constraints in the zero_cycle
  // free systems of bounded differences, considering only the leaders.
  // A constraint `c' is redundant, when there are two constraints such that
  // their sum is the same constraint with the inhomogeneous term
  // less than or equal to the `c' one.
  N c;
  for (dimension_type k = 0; k <= x_space_dim; ++k)
    if (leader[k] == k) {
      const DB_Row<N>& x_k = x_copy.dbm[k];
      for (dimension_type i = 0; i <= x_space_dim; ++i)
	if (leader[i] == i) {
	  const DB_Row<N>& x_i = x_copy.dbm[i];
	  const std::deque<bool>& redundancy_i = redundancy_dbm[i];
	  const N& x_i_k = x_i[k];
	  for (dimension_type j = 0; j <= x_space_dim; ++j)
	    if (leader[j] == j) {
	      const N& x_i_j = x_i[j];
	      if (!is_plus_infinity(x_i_j)) {
		add_assign_r(c, x_i_k, x_k[j], ROUND_UP);
		if (x_i_j >= c && !redundancy_i[j])
		  return false;
	      }
	    }
	}
    }

  // The vector `var_conn' is used to check if there is a single cycle
  // that connected all zero-equivalent variables between them.
  // The value `space_dim + 1' is used to indicate that the equivalence
  // class contains a single variable.
  std::vector<dimension_type> var_conn(x_space_dim + 1);
  for (dimension_type i = x_space_dim + 1; i-- > 0; )
    var_conn[i] = x_space_dim + 1;

  // Step 3: we store really the `var_conn' with the right value, putting
  // the variable with the selected variable is connected:
  // we check the row of each variable:
  // a- each leader could be connected with only zero-equivalent one,
  // b- each no-leader with only another zero-equivalent one.
  for (dimension_type i = 0; i <= x_space_dim; ++i) {
    // It count with how many variables the selected variable is
    // connected.
    dimension_type t = 0;
    dimension_type ld_i = leader[i];
    // Case a: leader.
    if (ld_i == i) {
      for (dimension_type j = 0; j <= x_space_dim; ++j) {
	dimension_type ld_j = leader[j];
	// Only the connectedness with equivalent variables
	// is considered.
	if (j != ld_j)
	  if (!redundancy_dbm[i][j]) {
	    if (t == 1)
	      // Two no-leaders couldn't connected with the same leader.
	      return false;
	    else
	      if (ld_j != i)
		// The variables isn't in the same equivalence class.
		return false;
	      else {
		++t;
		var_conn[i] = j;
	      }
	  }
      }
    }
    // Case b: no-leader.
    else {
      for (dimension_type j = 0; j <= x_space_dim; ++j) {
	if (!redundancy_dbm[i][j]) {
	  dimension_type ld_j = leader[j];
	  if (ld_i != ld_j)
	    // The variables isn't in the same equivalence class.
	    return false;
	  else {
	    if (t == 1)
	      // Two variables couldn't connected with the same leader.
	      return false;
	    else {
	      ++t;
	      var_conn[i] = j;
	    }
	  }
	  // A no-leader must be connected with
	  // another variable.
	  if (t == 0)
	    return false;
	}
      }
    }
  }

  // The vector `just_checked' is used to check if
  // a variable is already checked.
  std::vector<bool> just_checked(x_space_dim + 1);
  for (dimension_type i = x_space_dim + 1; i-- > 0; )
    just_checked[i] = false;

  // Step 4: we check if there are single cycles that
  // connected all the zero-equivalent variables between them.
  for (dimension_type i = 0; i <= x_space_dim; ++i) {
    bool jc_i = just_checked[i];
    // We do not re-check the already considered single cycles.
    if (!jc_i) {
      dimension_type v_con = var_conn[i];
      // We consider only the equivalence classes with
      // 2 or plus variables.
      if (v_con != x_space_dim + 1) {
	// There is a single cycle if taken a variable,
	// we return to this same variable.
	while (v_con != i) {
	  just_checked[v_con] = true;
	  v_con = var_conn[v_con];
	  // If we re-pass to an already considered variable,
	  // then we haven't a single cycle.
	  if (just_checked[v_con])
	    return false;
	}
      }
    }
    just_checked[i] = true;
  }

  // The system bounded differences is just reduced.
  return true;
}

template <typename T>
Poly_Con_Relation
BD_Shape<T>::relation_with(const Constraint& c) const {
  using Implementation::BD_Shapes::div_round_up;

  const dimension_type c_space_dim = c.space_dimension();
  const dimension_type space_dim = space_dimension();

  // Dimension-compatibility check.
  if (c_space_dim > space_dim)
    throw_dimension_incompatible("relation_with(c)", c);

  shortest_path_closure_assign();

  if (marked_empty())
    return Poly_Con_Relation::saturates()
      && Poly_Con_Relation::is_included()
      && Poly_Con_Relation::is_disjoint();

  if (space_dim == 0) {
    if ((c.is_equality() && c.inhomogeneous_term() != 0)
	|| (c.is_inequality() && c.inhomogeneous_term() < 0))
      return Poly_Con_Relation::is_disjoint();
    else if (c.is_strict_inequality() && c.inhomogeneous_term() == 0)
      // The constraint 0 > 0 implicitly defines the hyperplane 0 = 0;
      // thus, the zero-dimensional point also saturates it.
      return Poly_Con_Relation::saturates()
	&& Poly_Con_Relation::is_disjoint();
    else if (c.is_equality() || c.inhomogeneous_term() == 0)
      return Poly_Con_Relation::saturates()
	&& Poly_Con_Relation::is_included();
    else
      // The zero-dimensional point saturates
      // neither the positivity constraint 1 >= 0,
      // nor the strict positivity constraint 1 > 0.
      return Poly_Con_Relation::is_included();
  }

  dimension_type num_vars = 0;
  dimension_type i = 0;
  dimension_type j = 0;
  TEMP_INTEGER(coeff);
  // Constraints that are not bounded differences are not compatible.
  if (!extract_bounded_difference(c, c_space_dim, num_vars, i, j, coeff))
    throw_constraint_incompatible("relation_with(c)");

  if (num_vars == 0) {
    // Dealing with a trivial constraint.
    switch (sgn(c.inhomogeneous_term())) {
    case -1:
      return Poly_Con_Relation::is_disjoint();
    case 0:
      if (c.is_strict_inequality())
	return Poly_Con_Relation::saturates()
	  && Poly_Con_Relation::is_disjoint();
      else
	return Poly_Con_Relation::saturates()
	  && Poly_Con_Relation::is_included();
    case 1:
      return Poly_Con_Relation::is_included();
    }
  }

  // Select the cell to be checked for the "<=" part of the constraint,
  // and set `coeff' to the absolute value of itself.
  const N& x = (coeff < 0) ? dbm[i][j] : dbm[j][i];
  const N& y = (coeff < 0) ? dbm[j][i] : dbm[i][j];
  if (coeff < 0)
    coeff = -coeff;
  N d;
  div_round_up(d, c.inhomogeneous_term(), coeff);
  N d1;
  div_round_up(d1, -c.inhomogeneous_term(), coeff);

  switch (c.type()) {
  case Constraint::EQUALITY:
    if (d == x && d1 == y)
      return Poly_Con_Relation::saturates()
	&& Poly_Con_Relation::is_included();
    else if (d < y && d1 > x)
      return Poly_Con_Relation::is_disjoint();
    else
      return Poly_Con_Relation::strictly_intersects();
  case Constraint::NONSTRICT_INEQUALITY:
    if (d >= x && d1 >= y)
      return Poly_Con_Relation::saturates()
	&& Poly_Con_Relation::is_included();
    else if (d >= x)
      return Poly_Con_Relation::is_included();
    else if (d < x && d1 > y)
      return Poly_Con_Relation::is_disjoint();
    else
      return Poly_Con_Relation::strictly_intersects();
  case Constraint::STRICT_INEQUALITY:
    if (d >= x && d1 >= y)
      return Poly_Con_Relation::saturates()
	&& Poly_Con_Relation::is_disjoint();
    else if (d > x)
      return Poly_Con_Relation::is_included();
    else if (d <= x && d1 >= y)
      return Poly_Con_Relation::is_disjoint();
    else
      return Poly_Con_Relation::strictly_intersects();
  }
  // Quiet a compiler warning: this program point is unreachable.
  throw std::runtime_error("PPL internal error");
}

template <typename T>
Poly_Gen_Relation
BD_Shape<T>::relation_with(const Generator& g) const {
  const dimension_type space_dim = space_dimension();
  const dimension_type g_space_dim = g.space_dimension();

  // Dimension-compatibility check.
  if (space_dim < g_space_dim)
    throw_dimension_incompatible("relation_with(g)", g);

  // The empty bdiff cannot subsume a generator.
  if (marked_empty())
    return Poly_Gen_Relation::nothing();

  // A universe BD shape in a zero-dimensional space subsumes
  // all the generators of a zero-dimensional space.
  if (space_dim == 0)
    return Poly_Gen_Relation::subsumes();

  const bool is_line = g.is_line();

  // The relation between the bdiff and the given generator is obtained
  // checking if the generator satisfies all the constraints in the bdiff.
  // To check if the generator satisfies all the constraints it's enough
  // studying the sign of the scalar product between the generator and
  // all the constraints in the bdiff.

  // We find in `*this' all the constraints.
  for (dimension_type i = 0; i <= space_dim; ++i) {
    for (dimension_type j = i + 1; j <= space_dim; ++j) {
      const Variable x(j - 1);
      const bool x_dimension_incompatible = x.space_dimension() > g_space_dim;
      const N& dbm_ij = dbm[i][j];
      const N& dbm_ji = dbm[j][i];
      N negated_dbm_ji;
      const bool is_equality
	= neg_assign_r(negated_dbm_ji, dbm_ji, ROUND_NOT_NEEDED) == V_EQ
	&& negated_dbm_ji == dbm_ij;
      const bool dbm_ij_is_infinity = is_plus_infinity(dbm_ij);
      const bool dbm_ji_is_infinity = is_plus_infinity(dbm_ji);
      if (i != 0) {
	const Variable y(i - 1);
	const bool y_dimension_incompatible
	  = y.space_dimension() > g_space_dim;
	const bool is_trivial_zero
	  = (x_dimension_incompatible && g.coefficient(y) == 0)
	  || (y_dimension_incompatible && g.coefficient(x) == 0)
	  || (x_dimension_incompatible && y_dimension_incompatible);
	if (is_equality) {
	  // We have one equality constraint.
	  // The constraint has form ax - ay = b.
	  // The scalar product has the form
	  // 'a * y_i - a * x_j'
	  // where y_i = g.coefficient(y) and x_j = g.coefficient(x).
	  // It is not zero when both the coefficients of the
	  // variables x and y are not zero or when these coefficients
 	  if (!is_trivial_zero && g.coefficient(x) != g.coefficient(y))
	    return Poly_Gen_Relation::nothing();
	}
	else
	  // We have the binary inequality constraints.
	  if (!dbm_ij_is_infinity) {
	  // The constraint has form ax - ay <= b.
	  // The scalar product has the form
	  // 'a * y_i - a * x_j'
	    if (is_line
		&& !is_trivial_zero
		&& g.coefficient(x) != g.coefficient(y))
	      return Poly_Gen_Relation::nothing();
	    else
	      if (g.coefficient(y) < g.coefficient(x))
		return Poly_Gen_Relation::nothing();
	  }
	  else if (!dbm_ji_is_infinity) {
	    // The constraint has form ay - ax <= b.
	    // The scalar product has the form
	    // 'a * x_j - a* y_i'.
	    if (is_line
		&& !is_trivial_zero
		&& g.coefficient(x) != g.coefficient(y))
	      return Poly_Gen_Relation::nothing();
	    else if (g.coefficient(x) < g.coefficient(y))
	      return Poly_Gen_Relation::nothing();
	  }
      }
      else {
	// Here i == 0.
	if (is_equality) {
	  // The constraint has form ax = b.
	  // To satisfy the constraint it's necessary that the scalar product
	  // is not zero.It happens when the coefficient of the variable 'x'
	  // in the generator is not zero, because the scalar
	  // product has the form:
	  // 'a * x_i' where x_i = g.coefficient(x)..
	  if (!x_dimension_incompatible && g.coefficient(x) != 0)
	    return Poly_Gen_Relation::nothing();
	}
	else
	  // We have the unary inequality constraints.
	  if (!dbm_ij_is_infinity) {
	    // The constraint has form ax <= b.
	    // The scalar product has the form:
	    // '-a * x_i' where x_i = g.coefficient(x).
	    if (is_line
		&& !x_dimension_incompatible
		&& g.coefficient(x) != 0)
	      return Poly_Gen_Relation::nothing();
	    else if (g.coefficient(x) > 0)
	      return Poly_Gen_Relation::nothing();
	  }
	  else if (!dbm_ji_is_infinity) {
	    // The constraint has form -ax <= b.
	    // The scalar product has the form:
	    // 'a * x_i' where x_i = g.coefficient(x).
	    if (is_line
		&& !x_dimension_incompatible
		&& g.coefficient(x) != 0)
	      return Poly_Gen_Relation::nothing();
	    else if (g.coefficient(x) < 0)
	      return Poly_Gen_Relation::nothing();
	  }
      }
    }
  }
  return Poly_Gen_Relation::subsumes();
}

template <typename T>
void
BD_Shape<T>::shortest_path_closure_assign() const {
  using Implementation::BD_Shapes::min_assign;

  // Do something only if necessary.
  if (marked_empty() || marked_shortest_path_closed())
    return;
  const dimension_type num_dimensions = space_dimension();
  // Zero-dimensional BDSs are necessarily shortest-path closed.
  if (num_dimensions == 0)
    return;

  // Even though the BDS will not change, its internal representation
  // is going to be modified by the Floyd-Warshall algorithm.
  BD_Shape& x = const_cast<BD_Shape<T>&>(*this);

  // Fill the main diagonal with zeros.
  for (dimension_type h = num_dimensions + 1; h-- > 0; ) {
    assert(is_plus_infinity(x.dbm[h][h]));
    assign_r(x.dbm[h][h], 0, ROUND_NOT_NEEDED);
  }

  N sum;
  for (dimension_type k = num_dimensions + 1; k-- > 0; ) {
    const DB_Row<N>& xdbm_k = x.dbm[k];
    for (dimension_type i = num_dimensions + 1; i-- > 0; ) {
      DB_Row<N>& xdbm_i = x.dbm[i];
      const N& xdbm_i_k = xdbm_i[k];
      if (!is_plus_infinity(xdbm_i_k))
	for (dimension_type j = num_dimensions + 1; j-- > 0; ) {
	  const N& xdbm_k_j = xdbm_k[j];
	  if (!is_plus_infinity(xdbm_k_j)) {
	    // Rounding upward for correctness.
	    add_assign_r(sum, xdbm_i_k, xdbm_k_j, ROUND_UP);
	    min_assign(xdbm_i[j], sum);
	  }
	}
    }
  }

  // Check for emptyness: the BDS is empty if and only if there is a
  // negative value on the main diagonal of `dbm'.
  for (dimension_type h = num_dimensions + 1; h-- > 0; ) {
    N& x_dbm_hh = x.dbm[h][h];
    if (x_dbm_hh < 0) {
      x.status.set_empty();
      return;
    }
    else {
      assert(x_dbm_hh == 0);
      // Restore PLUS_INFINITY on the main diagonal.
      x_dbm_hh = PLUS_INFINITY;
    }
  }

  // The BDS is not empty and it is now shortest-path closed.
  x.status.set_shortest_path_closed();
}

template <typename T>
void
BD_Shape<T>::shortest_path_reduction_assign() const {
  // Do something only if necessary.
  if (marked_shortest_path_reduced())
    return;

  // First find the tighest constraints for this BDS.
  shortest_path_closure_assign();

  // If `*this' is empty, then there is nothing to reduce.
  if (marked_empty())
    return;

  // Step 1: compute zero-equivalence classes.
  // Variables corresponding to indices `i' and `j' are zero-equivalent
  // if they lie on a zero-weight loop; since the matrix is shortest-path
  // closed, this happens if and only if dbm[i][j] == -dbm[j][i].
  std::vector<dimension_type> predecessor;
  compute_predecessors(predecessor);
  std::vector<dimension_type> leaders;
  compute_leader_indices(predecessor, leaders);
  const dimension_type num_leaders = leaders.size();

  const dimension_type space_dim = space_dimension();
  // TODO: directly work on `redundancy_dbm' so as to minimize allocations.
  std::deque<bool> redundancy_row(space_dim + 1, true);
  std::vector<std::deque<bool> > redundancy(space_dim + 1, redundancy_row);

  // Step 2: flag non-redundant constraints in the (zero-cycle-free)
  // subsystem of bounded differences having only leaders as variables.
  N c;
  for (dimension_type l_i = 0; l_i < num_leaders; ++l_i) {
    const dimension_type i = leaders[l_i];
    const DB_Row<N>& dbm_i = dbm[i];
    std::deque<bool>& redundancy_i = redundancy[i];
    for (dimension_type l_j = 0; l_j < num_leaders; ++l_j) {
      const dimension_type j = leaders[l_j];
      if (redundancy_i[j]) {
	const N& dbm_i_j = dbm_i[j];
	redundancy_i[j] = false;
	for (dimension_type l_k = 0; l_k < num_leaders; ++l_k) {
	  const dimension_type k = leaders[l_k];
	  add_assign_r(c, dbm_i[k], dbm[k][j], ROUND_UP);
	  if (dbm_i_j >= c) {
	    redundancy_i[j] = true;
	    break;
	  }
	}
      }
    }
  }

  // Step 3: flag non-redundant constraints in zero-equivalence classes.
  // Each equivalence class must have a single 0-cycle connecting
  // all the equivalent variables in increasing order.
  std::deque<bool> dealt_with(space_dim + 1, false);
  for (dimension_type i = space_dim + 1; i-- > 0; )
    // We only need to deal with non-singleton zero-equivalence classes
    // that haven't already been dealt with.
    if (i != predecessor[i] && !dealt_with[i]) {
      dimension_type j = i;
      while (true) {
	const dimension_type pred_j = predecessor[j];
	if (j == pred_j) {
	  // We finally found the leader of `i'.
	  assert(redundancy[i][j]);
	  redundancy[i][j] = false;
	  // Here we dealt with `j' (i.e., `pred_j'), but it is useless
	  // to update `dealt_with' because `j' is a leader.
	  break;
	}
	// We haven't found the leader of `i' yet.
	assert(redundancy[pred_j][j]);
	redundancy[pred_j][j] = false;
	dealt_with[pred_j] = true;
	j = pred_j;
      }
    }

  // Even though shortest-path reduction is not going to change the BDS,
  // it might change its internal representation.
  BD_Shape<T>& x = const_cast<BD_Shape<T>&>(*this);
  std::swap(x.redundancy_dbm, redundancy);
  x.status.set_shortest_path_reduced();

  assert(is_shortest_path_reduced());
}

template <typename T>
void
BD_Shape<T>::bds_hull_assign(const BD_Shape& y) {
  const dimension_type space_dim = space_dimension();

  // Dimension-compatibility check.
  if (space_dim != y.space_dimension())
    throw_dimension_incompatible("bds_hull_assign(y)", y);

  // The poly-hull of a polyhedron `bd' with an empty polyhedron is `bd'.
  y.shortest_path_closure_assign();
  if (y.marked_empty())
    return;
  shortest_path_closure_assign();
  if (marked_empty()) {
    *this = y;
    return;
  }

  // The bds-hull consists in constructing `*this' with the maximum
  // elements selected from `*this' and `y'.
  assert(space_dim == 0 || marked_shortest_path_closed());
  for (dimension_type i = space_dim + 1; i-- > 0; ) {
    DB_Row<N>& dbm_i = dbm[i];
    const DB_Row<N>& y_dbm_i = y.dbm[i];
    for (dimension_type j = space_dim + 1; j-- > 0; ) {
      N& dbm_ij = dbm_i[j];
      const N& y_dbm_ij = y_dbm_i[j];
      if (dbm_ij < y_dbm_ij)
	dbm_ij = y_dbm_ij;
    }
  }
  // The result is still closed.
  assert(OK());
}

template <typename T>
void
BD_Shape<T>::bds_difference_assign(const BD_Shape& y) {
  const dimension_type space_dim = space_dimension();

  // Dimension-compatibility check.
  if (space_dim != y.space_dimension())
    throw_dimension_incompatible("bds_difference_assign(y)", y);

  BD_Shape new_bdiffs(space_dim, EMPTY);

  BD_Shape& x = *this;

  x.shortest_path_closure_assign();
  // The difference of an empty system of bounded differences
  // and of a system of bounded differences `p' is empty.
  if (x.marked_empty())
    return;
  y.shortest_path_closure_assign();
  // The difference of a system of bounded differences `p'
  // and an empty system of bounded differences is `p'.
  if (y.marked_empty())
    return;

  // If both systems of bounded differences are zero-dimensional,
  // then at this point they are necessarily universe system of
  // bounded differences, so that their difference is empty.
  if (space_dim == 0) {
    x.set_empty();
    return;
  }

  // TODO: This is just an executable specification.
  //       Have to find a more efficient method.
  if (y.contains(x)) {
    x.set_empty();
    return;
  }

  // We take a constraint of the system y at the time and we
  // consider its complementary. Then we intersect the union
  // of these complementaries with the system x.
  const Constraint_System& y_cs = y.constraints();
  for (Constraint_System::const_iterator i = y_cs.begin(),
	 y_cs_end = y_cs.end(); i != y_cs_end; ++i) {
    const Constraint& c = *i;
    // If the system of bounded differences `x' is included
    // in the system of bounded differences defined by `c',
    // then `c' _must_ be skipped, as adding its complement to `x'
    // would result in the empty system of bounded differences,
    // and as we would obtain a result that is less precise
    // than the bds-difference.
    if (x.relation_with(c).implies(Poly_Con_Relation::is_included()))
      continue;
    BD_Shape z = x;
    const Linear_Expression e = Linear_Expression(c);
    bool change = false;
    if (c.is_nonstrict_inequality())
      change = z.add_constraint_and_minimize(e <= 0);
    if (c.is_equality()) {
      BD_Shape w = x;
      if (w.add_constraint_and_minimize(e <= 0))
	new_bdiffs.bds_hull_assign(w);
      change = z.add_constraint_and_minimize(e >= 0);
    }
    if (change)
      new_bdiffs.bds_hull_assign(z);
  }
  *this = new_bdiffs;
  // The result is still closed, because both bds_hull_assign() and
  // add_constraint_and_minimize() preserve closure.
  assert(OK());
}

template <typename T>
void
BD_Shape<T>::add_space_dimensions_and_embed(const dimension_type m) {
  // Adding no dimensions is a no-op.
  if (m == 0)
    return;

  const dimension_type space_dim = space_dimension();
  const dimension_type new_space_dim = space_dim + m;
  const bool was_zero_dim_univ = (!marked_empty() && space_dim == 0);

  // To embed an n-dimension space BDS in a (n+m)-dimension space,
  // we just add `m' rows and columns in the system of bounded differences,
  // initialized to PLUS_INFINITY.
  dbm.grow(new_space_dim + 1);

  // Shortest-path closure is maintained (if it was holding).
  // TODO: see whether reduction can be (efficiently!) maintained too.
  if (marked_shortest_path_reduced())
    status.reset_shortest_path_reduced();

  // If `*this' was the zero-dim space universe BDS,
  // the we can set the shortest-path closure flag.
  if (was_zero_dim_univ)
    status.set_shortest_path_closed();

  assert(OK());
}

template <typename T>
void
BD_Shape<T>::add_space_dimensions_and_project(const dimension_type m) {
  // Adding no dimensions is a no-op.
  if (m == 0)
    return;

  const dimension_type space_dim = space_dimension();

  // If `*this' was zero-dimensional, then we add `m' rows and columns.
  // If it also was non-empty, then we zero all the added elements
  // and set the flag for shortest-path closure.
  if (space_dim == 0) {
    dbm.grow(m + 1);
    if (!marked_empty()) {
      for (dimension_type i = m + 1; i-- > 0; ) {
	DB_Row<N>& dbm_i = dbm[i];
	for (dimension_type j = m + 1; j-- > 0; )
	  if (i != j)
	    assign_r(dbm_i[j], 0, ROUND_NOT_NEEDED);
      }
      status.set_shortest_path_closed();
    }
    assert(OK());
    return;
  }

  // To project an n-dimension space system of bounded differences
  // in a (n+m)-dimension space, we add `m' rows and columns.
  // In the first row and column of the matrix we add `zero' from
  // the (n+1)-th position to the end.
  const dimension_type new_space_dim = space_dim + m;
  dbm.grow(new_space_dim + 1);

  // Bottom of the matrix and first row.
  DB_Row<N>& dbm_0 = dbm[0];
  for (dimension_type i = space_dim + 1; i <= new_space_dim; ++i) {
    assign_r(dbm[i][0], 0, ROUND_NOT_NEEDED);
    assign_r(dbm_0[i], 0, ROUND_NOT_NEEDED);
  }

  if (marked_shortest_path_closed())
    status.reset_shortest_path_closed();
  assert(OK());
}

template <typename T>
void
BD_Shape<T>::remove_space_dimensions(const Variables_Set& to_be_removed) {
  // The removal of no dimensions from any BDS is a no-op.
  // Note that this case also captures the only legal removal of
  // space dimensions from a BDS in a 0-dim space.
  if (to_be_removed.empty()) {
    assert(OK());
    return;
  }

  // Dimension-compatibility check: the variable having
  // maximum cardinality is the one occurring last in the set.
  const dimension_type max_dim_to_be_removed = to_be_removed.rbegin()->id();
  const dimension_type old_space_dim = space_dimension();
  if (max_dim_to_be_removed >= old_space_dim)
    throw_dimension_incompatible("remove_space_dimensions(vs)",
				 max_dim_to_be_removed);

  // Shortest-path closure is necessary to keep precision.
  shortest_path_closure_assign();

  // When removing _all_ dimensions from a BDS,
  // we obtain the zero-dimensional BDS.
  const dimension_type new_space_dim = old_space_dim - to_be_removed.size();
  if (new_space_dim == 0) {
    dbm.resize_no_copy(1);
    if (!marked_empty())
      // We set the zero_dim_univ flag.
      set_zero_dim_univ();
    assert(OK());
    return;
  }

  // Shortest-path closure is maintained.
  // TODO: see whether reduction can be (efficiently!) maintained too.
  if (marked_shortest_path_reduced())
    status.reset_shortest_path_reduced();

  // For each variable to remove, we erase the corresponding column and
  // row by shifting the other columns and rows, than are not removed,
  // respectively left and above.
  Variables_Set::const_iterator tbr = to_be_removed.begin();
  Variables_Set::const_iterator tbr_end = to_be_removed.end();
  dimension_type dst = tbr->id() + 1;
  dimension_type src = dst + 1;
  for (++tbr; tbr != tbr_end; ++tbr) {
    const dimension_type tbr_next = tbr->id() + 1;
    // All other columns and rows are moved respectively to the left
    // and above.
    while (src < tbr_next) {
      dbm[dst] = dbm[src];
      for (dimension_type i = old_space_dim + 1; i-- > 0; ) {
	DB_Row<N>& dbm_i = dbm[i];
	dbm_i[dst] = dbm_i[src];
      }
      ++dst;
      ++src;
    }
    ++src;
  }

  // Moving the remaining rows and columns.
  while (src <= old_space_dim) {
    dbm[dst] = dbm[src];
    for (dimension_type i = old_space_dim + 1; i-- > 0; ) {
      DB_Row<N>& dbm_i = dbm[i];
      dbm_i[dst] = dbm_i[src];
    }
    ++src;
    ++dst;
  }

  // Update the space dimension.
  dbm.resize_no_copy(new_space_dim + 1);
  assert(OK());
}

template <typename T>
template <typename PartialFunction>
void
BD_Shape<T>::map_space_dimensions(const PartialFunction& pfunc) {
  const dimension_type space_dim = space_dimension();
  // TODO: this implementation is just an executable specification.
  if (space_dim == 0)
    return;

  if (pfunc.has_empty_codomain()) {
    // All dimensions vanish: the BDS becomes zero_dimensional.
    remove_higher_space_dimensions(0);
    assert(OK());
    return;
  }

  const dimension_type new_space_dim = pfunc.max_in_codomain() + 1;
  // If we are going to actually reduce the space dimension,
  // then shortest-path closure is required to keep precision.
  if (new_space_dim < space_dim)
    shortest_path_closure_assign();

  // If the BDS is empty, then it is sufficient to adjust the
  // space dimension of the system of bounded differences.
  if (marked_empty()) {
    remove_higher_space_dimensions(new_space_dim);
    return;
  }

  // Shortest-path closure is maintained (if it was holding).
  // TODO: see whether reduction can be (efficiently!) maintained too.
  if (marked_shortest_path_reduced())
    status.reset_shortest_path_reduced();

  // We create a new matrix with the new space dimension.
  DB_Matrix<N> x(new_space_dim+1);
  // First of all we must map the unary constraints, because
  // there is the fictitious variable `zero', that can't be mapped
  // at all.
  const DB_Row<N>& dbm_0 = dbm[0];
  DB_Row<N>& x_0 = x[0];
  for (dimension_type j = 1; j <= space_dim; ++j) {
    dimension_type new_j;
    if (pfunc.maps(j - 1, new_j)) {
      x_0[new_j + 1] = dbm_0[j];
      x[new_j + 1][0] = dbm[j][0];
    }
  }
  // Now we map the binary constraints, exchanging the indexes.
  for (dimension_type i = 1; i <= space_dim; ++i) {
    dimension_type new_i;
    if (pfunc.maps(i - 1, new_i)) {
      const DB_Row<N>& dbm_i = dbm[i];
      ++new_i;
      DB_Row<N>& x_new_i = x[new_i];
      for (dimension_type j = i+1; j <= space_dim; ++j) {
	dimension_type new_j;
	if (pfunc.maps(j - 1, new_j)) {
	  ++new_j;
	  x_new_i[new_j] = dbm_i[j];
	  x[new_j][new_i] = dbm[j][i];
	}
      }
    }
  }

  std::swap(dbm, x);
  assert(OK());
}

template <typename T>
void
BD_Shape<T>::intersection_assign(const BD_Shape& y) {
  const dimension_type space_dim = space_dimension();

  // Dimension-compatibility check.
  if (space_dim != y.space_dimension())
    throw_dimension_incompatible("intersection_assign(y)", y);

  // If one of the two systems of bounded differences is empty,
  // the intersection is empty.
  if (marked_empty())
    return;
  if (y.marked_empty()) {
    set_empty();
    return;
  }

  // If both systems of bounded differences are zero-dimensional,
  // then at this point they are necessarily non-empty,
  // so that their intersection is non-empty too.
  if (space_dim == 0)
    return;

  // To intersect two systems of bounded differences we compare
  // the constraints and we choose the less values.
  bool changed = false;
  for (dimension_type i = space_dim + 1; i-- > 0; ) {
    DB_Row<N>& dbm_i = dbm[i];
    const DB_Row<N>& y_dbm_i = y.dbm[i];
    for (dimension_type j = space_dim + 1; j-- > 0; ) {
      N& dbm_ij = dbm_i[j];
      const N& y_dbm_ij = y_dbm_i[j];
      if (dbm_ij > y_dbm_ij) {
	dbm_ij = y_dbm_ij;
	changed = true;
      }
    }
  }

  if (changed && marked_shortest_path_closed())
    status.reset_shortest_path_closed();
  assert(OK());
}

template <typename T>
template <typename Iterator>
void
BD_Shape<T>::CC76_extrapolation_assign(const BD_Shape& y,
				       Iterator first, Iterator last,
				       unsigned* tp) {
  const dimension_type space_dim = space_dimension();

  // Dimension-compatibility check.
  if (space_dim != y.space_dimension())
    throw_dimension_incompatible("CC76_extrapolation_assign(y)", y);

#ifndef NDEBUG
  {
    // We assume that `y' is contained in or equal to `*this'.
    const BD_Shape x_copy = *this;
    const BD_Shape y_copy = y;
    assert(x_copy.contains(y_copy));
  }
#endif

  // If both systems of bounded differences are zero-dimensional,
  // since `*this' contains `y', we simply return `*this'.
  if (space_dim == 0)
    return;

  shortest_path_closure_assign();
  // If `*this' is empty, since `*this' contains `y', `y' is empty too.
  if (marked_empty())
    return;
  y.shortest_path_closure_assign();
  // If `y' is empty, we return.
  if (y.marked_empty())
    return;

  // If there are tokens available, work on a temporary copy.
  if (tp != 0 && *tp > 0) {
    BD_Shape<T> x_tmp(*this);
    x_tmp.CC76_extrapolation_assign(y, first, last, 0);
    // If the widening was not precise, use one of the available tokens.
    if (!contains(x_tmp))
      --(*tp);
    return;
  }

  // Compare each constraint in `y' to the corresponding one in `*this'.
  // The constraint in `*this' is kept as is if it is stronger than or
  // equal to the constraint in `y'; otherwise, the inhomogeneous term
  // of the constraint in `*this' is further compared with elements taken
  // from a sorted container (the stop-points, provided by the user), and
  // is replaced by the first entry, if any, which is greater than or equal
  // to the inhomogeneous term. If no such entry exists, the constraint
  // is removed altogether.
  for (dimension_type i = space_dim + 1; i-- > 0; ) {
    DB_Row<N>& dbm_i = dbm[i];
    const DB_Row<N>& y_dbm_i = y.dbm[i];
    for (dimension_type j = space_dim + 1; j-- > 0; ) {
      N& dbm_ij = dbm_i[j];
      const N& y_dbm_ij = y_dbm_i[j];
      if (y_dbm_ij < dbm_ij) {
	Iterator k = std::lower_bound(first, last, dbm_ij);
	if (k != last) {
	  if (dbm_ij < *k)
	    assign_r(dbm_ij, *k, ROUND_UP);
	}
	else
	  dbm_ij = PLUS_INFINITY;
      }
    }
  }
  status.reset_shortest_path_closed();
  assert(OK());
}

template <typename T>
void
BD_Shape<T>::get_limiting_shape(const Constraint_System& cs,
				BD_Shape& limiting_shape) const {
  using Implementation::BD_Shapes::div_round_up;

  const dimension_type cs_space_dim = cs.space_dimension();
  // Private method: the caller has to ensure the following.
  assert(cs_space_dim <= space_dimension());

  bool changed = false;
  for (Constraint_System::const_iterator i = cs.begin(),
	 iend = cs.end(); i != iend; ++i) {
    const Constraint& c = *i;
    dimension_type num_vars = 0;
    dimension_type i = 0;
    dimension_type j = 0;
    TEMP_INTEGER(coeff);
    // Constraints that are not bounded differences are ignored.
    if (extract_bounded_difference(c, cs_space_dim, num_vars, i, j, coeff)) {
      // Select the cell to be modified for the "<=" part of the constraint,
      // and set `coeff' to the absolute value of itself.
      const N& x = (coeff < 0) ? dbm[i][j] : dbm[j][i];
      const N& y = (coeff < 0) ? dbm[j][i] : dbm[i][j];
      DB_Matrix<N>& ls_dbm = limiting_shape.dbm;
      N& ls_x = (coeff < 0) ? ls_dbm[i][j] : ls_dbm[j][i];
      N& ls_y = (coeff < 0) ? ls_dbm[j][i] : ls_dbm[i][j];
      if (coeff < 0)
	coeff = -coeff;
      // Compute the bound for `x', rounding towards plus infinity.
      N d;
      div_round_up(d, c.inhomogeneous_term(), coeff);
      if (x <= d)
	if (c.is_inequality())
	  if (ls_x > d) {
	    ls_x = d;
	    changed = true;
	  }
	else {
	  // Compute the bound for `y', rounding towards plus infinity.
	  div_round_up(d, -c.inhomogeneous_term(), coeff);
	  if (y <= d)
	    if (ls_y > d) {
	      ls_y = d;
	      changed = true;
	    }

	}
    }
  }

  // In general, adding a constraint does not preserve the shortest-path
  // closure of the system of bounded differences.
  if (changed && limiting_shape.marked_shortest_path_closed())
    limiting_shape.status.reset_shortest_path_closed();
}

template <typename T>
void
BD_Shape<T>::limited_CC76_extrapolation_assign(const BD_Shape& y,
					       const Constraint_System& cs,
					       unsigned* tp) {
  // Dimension-compatibility check.
  const dimension_type space_dim = space_dimension();
  if (space_dim != y.space_dimension())
    throw_dimension_incompatible("limited_CC76_extrapolation_assign(y, cs)",
				 y);

  // `cs' must be dimension-compatible with the two systems
  // of bounded differences.
  const dimension_type cs_space_dim = cs.space_dimension();
  if (space_dim < cs_space_dim)
    throw_constraint_incompatible("limited_CC76_extrapolation_assign(y, cs)");

  // Strict inequalities not allowed.
  if (cs.has_strict_inequalities())
    throw_constraint_incompatible("limited_CC76_extrapolation_assign(y, cs)");

  // The limited CC76-extrapolation between two systems of bounded
  // differences in a zero-dimensional space is a system of bounded
  // differences in a zero-dimensional space, too.
  if (space_dim == 0)
    return;

#ifndef NDEBUG
  {
    // We assume that `y' is contained in or equal to `*this'.
    const BD_Shape x_copy = *this;
    const BD_Shape y_copy = y;
    assert(x_copy.contains(y_copy));
  }
#endif

  // If `*this' is empty, since `*this' contains `y', `y' is empty too.
  if (marked_empty())
    return;
  // If `y' is empty, we return.
  if (y.marked_empty())
    return;

  BD_Shape<T> limiting_shape(space_dim, UNIVERSE);
  get_limiting_shape(cs, limiting_shape);
  CC76_extrapolation_assign(y, tp);
  intersection_assign(limiting_shape);
  assert(OK());
}

template <typename T>
void
BD_Shape<T>::BHMZ05_widening_assign(const BD_Shape& y, unsigned* tp) {
  const dimension_type space_dim = space_dimension();

  // Dimension-compatibility check.
  if (space_dim != y.space_dimension())
    throw_dimension_incompatible("BHMZ05_widening_assign(y)", y);

#ifndef NDEBUG
  {
    // We assume that `y' is contained in or equal to `*this'.
    const BD_Shape x_copy = *this;
    const BD_Shape y_copy = y;
    assert(x_copy.contains(y_copy));
  }
#endif

  // Compute the affine dimension of `y'.
  const dimension_type y_affine_dim = y.affine_dimension();
  // If the affine dimension of `y' is zero, then either `y' is
  // zero-dimensional, or it is empty, or it is a singleton.
  // In all cases, due to the inclusion hypothesis, the result is `*this'.
  if (y_affine_dim == 0)
    return;

  // If the affine dimension has changed, due to the inclusion hypothesis,
  // the result is `*this'.
  const dimension_type x_affine_dim = affine_dimension();
  assert(x_affine_dim >= y_affine_dim);
  if (x_affine_dim != y_affine_dim)
    return;

  // If there are tokens available, work on a temporary copy.
  if (tp != 0 && *tp > 0) {
    BD_Shape<T> x_tmp(*this);
    x_tmp.BHMZ05_widening_assign(y, 0);
    // If the widening was not precise, use one of the available tokens.
    if (!contains(x_tmp))
      --(*tp);
    return;
  }

  // Here no token is available.
  assert(marked_shortest_path_closed() && y.marked_shortest_path_closed());
  // Minimize `y'.
  y.shortest_path_reduction_assign();

  // Extrapolate unstable bounds, taking into account redundancy in `y'.
  for (dimension_type i = space_dim + 1; i-- > 0; ) {
    DB_Row<N>& dbm_i = dbm[i];
    const DB_Row<N>& y_dbm_i = y.dbm[i];
    const std::deque<bool>& y_redundancy_i = y.redundancy_dbm[i];
    for (dimension_type j = space_dim + 1; j-- > 0; ) {
      N& dbm_ij = dbm_i[j];
      // Note: in the following line the use of `!=' (as opposed to
      // the use of `<' that would seem -but is not- equivalent) is
      // intentional.
      if (y_redundancy_i[j] || y_dbm_i[j] != dbm_ij)
	dbm_ij = PLUS_INFINITY;
    }
  }
  // NOTE: this will also reset the shortest-path reduction flag,
  // even though the dbm is still in reduced form. However, the
  // current implementation invariant requires that any reduced dbm
  // is closed too.
  status.reset_shortest_path_closed();
  assert(OK());
}

template <typename T>
void
BD_Shape<T>::limited_BHMZ05_extrapolation_assign(const BD_Shape& y,
						 const Constraint_System& cs,
						 unsigned* tp) {
  // Dimension-compatibility check.
  const dimension_type space_dim = space_dimension();
  if (space_dim != y.space_dimension())
    throw_dimension_incompatible("limited_BHMZ05_extrapolation_assign(y, cs)",
				 y);
  // `cs' must be dimension-compatible with the two systems
  // of bounded differences.
  const dimension_type cs_space_dim = cs.space_dimension();
  if (space_dim < cs_space_dim)
    throw_constraint_incompatible("limited_BHMZ05_extrapolation_assign"
				  "(y, cs)");

  // Strict inequalities are not allowed.
  if (cs.has_strict_inequalities())
    throw_constraint_incompatible("limited_BHMZ05_extrapolation_assign"
				  "(y, cs)");

  // The limited BHMZ05-extrapolation between two systems of bounded
  // differences in a zero-dimensional space is a system of bounded
  // differences in a zero-dimensional space, too.
  if (space_dim == 0)
    return;

#ifndef NDEBUG
  {
    // We assume that `y' is contained in or equal to `*this'.
    const BD_Shape x_copy = *this;
    const BD_Shape y_copy = y;
    assert(x_copy.contains(y_copy));
  }
#endif

  // If `*this' is empty, since `*this' contains `y', `y' is empty too.
  if (marked_empty())
    return;
  // If `y' is empty, we return.
  if (y.marked_empty())
    return;

  BD_Shape<T> limiting_shape(space_dim, UNIVERSE);
  get_limiting_shape(cs, limiting_shape);
  BHMZ05_widening_assign(y, tp);
  intersection_assign(limiting_shape);
  assert(OK());
}

template <typename T>
void
BD_Shape<T>::CC76_narrowing_assign(const BD_Shape& y) {
  const dimension_type space_dim = space_dimension();

  // Dimension-compatibility check.
  if (space_dim != y.space_dimension())
    throw_dimension_incompatible("CC76_narrowing_assign(y)", y);

#ifndef NDEBUG
  {
    // We assume that `*this' is contained in or equal to `y'.
    const BD_Shape x_copy = *this;
    const BD_Shape y_copy = y;
    assert(y_copy.contains(x_copy));
  }
#endif

  // If both systems of bounded differences are zero-dimensional,
  // since `y' contains `*this', we simply return `*this'.
  if (space_dim == 0)
    return;

  y.shortest_path_closure_assign();
  // If `y' is empty, since `y' contains `this', `*this' is empty too.
  if (y.marked_empty())
    return;
  shortest_path_closure_assign();
  // If `*this' is empty, we return.
  if (marked_empty())
    return;

  // Replace each constraint in `*this' by the corresponding constraint
  // in `y' if the corresponding inhomogeneous terms are both finite.
  bool changed = false;
  for (dimension_type i = space_dim + 1; i-- > 0; ) {
    DB_Row<N>& dbm_i = dbm[i];
    const DB_Row<N>& y_dbm_i = y.dbm[i];
    for (dimension_type j = space_dim + 1; j-- > 0; ) {
      N& dbm_ij = dbm_i[j];
      const N& y_dbm_ij = y_dbm_i[j];
      if (!is_plus_infinity(dbm_ij)
	  && !is_plus_infinity(y_dbm_ij)
	  && dbm_ij != y_dbm_ij) {
	dbm_ij = y_dbm_ij;
	changed = true;
      }
    }
  }
  if (changed && marked_shortest_path_closed())
    status.reset_shortest_path_closed();
  assert(OK());
}

template <typename T>
void
BD_Shape<T>
::deduce_v_minus_u_bounds(const dimension_type v,
			  const dimension_type last_v,
			  const Linear_Expression& sc_expr,
			  Coefficient_traits::const_reference sc_den,
			  const N& pos_sum) {
  // Deduce constraints of the form `v - u', where `u != v'.
  // Note: the shortest-path closure is able to deduce the constraint
  // `v - u <= ub_v - lb_u'. We can be more precise if variable `u'
  // played an active role in the computation of the upper bound for `v',
  // i.e., if the corresponding coefficient `q == expr_u/den' is
  // greater than zero. In particular:
  // if `q >= 1',    then `v - u <= ub_v - ub_u';
  // if `0 < q < 1', then `v - u <= ub_v - (q*ub_u + (1-q)*lb_u)'.
  mpq_class mpq_sc_den;
  assign_r(mpq_sc_den, sc_den, ROUND_NOT_NEEDED);
  const DB_Row<N>& dbm_0 = dbm[0];
  // No need to consider indices greater than `last_v'.
  for (dimension_type u = last_v; u > 0; --u)
    if (u != v) {
      const Coefficient& expr_u = sc_expr.coefficient(Variable(u-1));
      if (expr_u > 0)
	if (expr_u >= sc_den)
	  // Deducing `v - u <= ub_v - ub_u'.
	  sub_assign_r(dbm[u][v], pos_sum, dbm_0[u], ROUND_UP);
	else {
	  DB_Row<N>& dbm_u = dbm[u];
	  const N& dbm_u0 = dbm_u[0];
	  if (!is_plus_infinity(dbm_u0)) {
	    // Let `ub_u' and `lb_u' be the known upper and lower bound
	    // for `u', respectively. Letting `q = expr_u/sc_den' be the
	    // rational coefficient of `u' in `sc_expr/sc_den',
	    // the upper bound for `v - u' is computed as
	    // `ub_v - (q * ub_u + (1-q) * lb_u)', i.e.,
	    // `pos_sum + (-lb_u) - q * (ub_u + (-lb_u))'.
	    mpq_class minus_lb_u;
	    assign_r(minus_lb_u, dbm_u0, ROUND_NOT_NEEDED);
	    mpq_class q;
	    assign_r(q, expr_u, ROUND_NOT_NEEDED);
	    div_assign_r(q, q, mpq_sc_den, ROUND_NOT_NEEDED);
	    mpq_class ub_u;
	    assign_r(ub_u, dbm_0[u], ROUND_NOT_NEEDED);
	    // Compute `ub_u - lb_u'.
	    add_assign_r(ub_u, ub_u, minus_lb_u, ROUND_NOT_NEEDED);
	    // Compute `(-lb_u) - q * (ub_u - lb_u)'.
	    sub_mul_assign_r(minus_lb_u, q, ub_u, ROUND_NOT_NEEDED);
	    N up_approx;
	    assign_r(up_approx, minus_lb_u, ROUND_UP);
	    // Deducing `v - u <= ub_v - (q * ub_u + (1-q) * lb_u)'.
	    add_assign_r(dbm_u[v], pos_sum, up_approx, ROUND_UP);
	  }
	}
    }
}

template <typename T>
void
BD_Shape<T>
::deduce_u_minus_v_bounds(const dimension_type v,
			  const dimension_type last_v,
			  const Linear_Expression& sc_expr,
			  Coefficient_traits::const_reference sc_den,
			  const N& neg_sum) {
  // Deduce constraints of the form `u - v', where `u != v'.
  // Note: the shortest-path closure is able to deduce the constraint
  // `u - v <= ub_u - lb_v'. We can be more precise if variable `u'
  // played an active role in the computation of the lower bound for `v',
  // i.e., if the corresponding coefficient `q == expr_u/den' is
  // greater than zero. In particular:
  // if `q >= 1',    then `u - v <= lb_u - lb_v';
  // if `0 < q < 1', then `u - v <= (q*lb_u + (1-q)*ub_u) - lb_v'.
  mpq_class mpq_sc_den;
  assign_r(mpq_sc_den, sc_den, ROUND_NOT_NEEDED);
  DB_Row<N>& dbm_0 = dbm[0];
  DB_Row<N>& dbm_v = dbm[v];
  // No need to consider indices greater than `last_v'.
  for (dimension_type u = last_v; u > 0; --u)
    if (u != v) {
      const Coefficient& expr_u = sc_expr.coefficient(Variable(u-1));
      if (expr_u > 0)
	if (expr_u >= sc_den)
	  // Deducing `u - v <= lb_u - lb_v',
	  // i.e., `u - v <= (-lb_v) - (-lb_u)'.
	  sub_assign_r(dbm_v[u], neg_sum, dbm[u][0], ROUND_UP);
	else {
	  const N& dbm_0u = dbm_0[u];
	  if (!is_plus_infinity(dbm_0u)) {
	    // Let `ub_u' and `lb_u' be the known upper and lower bound
	    // for `u', respectively. Letting `q = expr_u/sc_den' be the
	    // rational coefficient of `u' in `sc_expr/sc_den',
	    // the upper bound for `u - v' is computed as
	    // `(q * lb_u + (1-q) * ub_u) - lb_v', i.e.,
	    // `ub_u - q * (ub_u + (-lb_u)) + neg_sum'.
	    mpq_class ub_u;
	    assign_r(ub_u, dbm_0u, ROUND_NOT_NEEDED);
	    mpq_class q;
	    assign_r(q, expr_u, ROUND_NOT_NEEDED);
	    div_assign_r(q, q, mpq_sc_den, ROUND_NOT_NEEDED);
	    mpq_class minus_lb_u;
	    assign_r(minus_lb_u, dbm[u][0], ROUND_NOT_NEEDED);
	    // Compute `ub_u - lb_u'.
	    add_assign_r(minus_lb_u, minus_lb_u, ub_u, ROUND_NOT_NEEDED);
	    // Compute `ub_u - q * (ub_u - lb_u)'.
	    sub_mul_assign_r(ub_u, q, minus_lb_u, ROUND_NOT_NEEDED);
	    N up_approx;
	    assign_r(up_approx, ub_u, ROUND_UP);
	    // Deducing `u - v <= (q*lb_u + (1-q)*ub_u) - lb_v'.
	    add_assign_r(dbm_v[u], up_approx, neg_sum, ROUND_UP);
	  }
	}
    }
}

template <typename T>
void
BD_Shape<T>::affine_image(const Variable var,
			  const Linear_Expression& expr,
			  Coefficient_traits::const_reference denominator) {
  using Implementation::BD_Shapes::div_round_up;

  // The denominator cannot be zero.
  if (denominator == 0)
    throw_generic("affine_image(v, e, d)", "d == 0");

  // Dimension-compatibility checks.
  // The dimension of `expr' should not be greater than the dimension
  // of `*this'.
  const dimension_type space_dim = space_dimension();
  const dimension_type expr_space_dim = expr.space_dimension();
  if (space_dim < expr_space_dim)
    throw_dimension_incompatible("affine_image(v, e, d)", "e", expr);

  // `var' should be one of the dimensions of the shape.
  const dimension_type v = var.id() + 1;
  if (v > space_dim)
    throw_dimension_incompatible("affine_image(v, e, d)", var.id());

  // The image of an empty BDS is empty too.
  shortest_path_closure_assign();
  if (marked_empty())
    return;

  const Coefficient& b = expr.inhomogeneous_term();
  // Number of non-zero coefficients in `expr': will be set to
  // 0, 1, or 2, the latter value meaning any value greater than 1.
  dimension_type t = 0;
  // Index of the last non-zero coefficient in `expr', if any.
  dimension_type w = 0;
  // Get information about the number of non-zero coefficients in `expr'.
  for (dimension_type i = expr_space_dim; i-- > 0; )
    if (expr.coefficient(Variable(i)) != 0)
      if (t++ == 1)
	break;
      else
	w = i+1;

  // Now we know the form of `expr':
  // - If t == 0, then expr == b, with `b' a constant;
  // - If t == 1, then expr == a*w + b, where `w' can be `v' or another
  //   variable; in this second case we have to check whether `a' is
  //   equal to `denominator' or `-denominator', since otherwise we have
  //   to fall back on the general form;
  // - If t == 2, the `expr' is of the general form.
  TEMP_INTEGER(minus_den);
  neg_assign(minus_den, denominator);

  if (t == 0) {
    // Case 1: expr == b.
    // Remove all constraints on `var'.
    forget_all_dbm_constraints(v);
    // Shortest-path closure is preserved, but not reduction.
    if (marked_shortest_path_reduced())
      status.reset_shortest_path_reduced();
    // Add the constraint `var == b/denominator'.
    add_dbm_constraint(0, v, b, denominator);
    add_dbm_constraint(v, 0, b, minus_den);
    assert(OK());
    return;
  }

  if (t == 1) {
    // Value of the one and only non-zero coefficient in `expr'.
    const Coefficient& a = expr.coefficient(Variable(w-1));
    if (a == denominator || a == minus_den) {
      // Case 2: expr == a*w + b, with a == +/- denominator.
      if (w == v) {
	// `expr' is of the form: a*v + b.
	if (a == denominator) {
	  if (b == 0)
	    // The transformation is the identity function.
	    return;
	  else {
	    // Translate all the constraints on `var',
	    // adding or subtracting the value `b/denominator'.
	    N d;
	    div_round_up(d, b, denominator);
	    N c;
	    div_round_up(c, b, minus_den);
	    DB_Row<N>& dbm_v = dbm[v];
	    for (dimension_type i = space_dim + 1; i-- > 0; ) {
	      N& dbm_vi = dbm_v[i];
	      add_assign_r(dbm_vi, dbm_vi, c, ROUND_UP);
	      N& dbm_iv = dbm[i][v];
	      add_assign_r(dbm_iv, dbm_iv, d, ROUND_UP);
	    }
	    // Both shortest-path closure and reduction are preserved.
	  }
	}
	else {
	  // Here `a == -denominator'.
	  // Remove the binary constraints on `var'.
	  forget_binary_dbm_constraints(v);
	  // Swap the unary constraints on `var'.
	  std::swap(dbm[v][0], dbm[0][v]);
	  // Shortest-path closure is not preserved.
	  status.reset_shortest_path_closed();
	  if (b != 0) {
	    // Translate the unary constraints on `var',
	    // adding or subtracting the value `b/denominator'.
	    N c;
	    div_round_up(c, b, minus_den);
	    N& dbm_v0 = dbm[v][0];
	    add_assign_r(dbm_v0, dbm_v0, c, ROUND_UP);
	    N d;
	    div_round_up(d, b, denominator);
	    N& dbm_0v = dbm[0][v];
	    add_assign_r(dbm_0v, dbm_0v, d, ROUND_UP);
	  }
	}
      }
      else {
	// Here `w != v', so that `expr' is of the form
	// +/-denominator * w + b.
	// Remove all constraints on `var'.
	forget_all_dbm_constraints(v);
	// Shortest-path closure is preserved, but not reduction.
	if (marked_shortest_path_reduced())
	  status.reset_shortest_path_reduced();
	if (a == denominator) {
	  // Add the new constraint `v - w == b/denominator'.
	  add_dbm_constraint(w, v, b, denominator);
	  add_dbm_constraint(v, w, b, minus_den);
	}
	else {
	  // Here a == -denominator, so that we should be adding
	  // the constraint `v + w == b/denominator'.
	  // Approximate it by computing lower and upper bounds for `w'.
	  const N& dbm_w0 = dbm[w][0];
	  if (!is_plus_infinity(dbm_w0)) {
	    // Add the constraint `v <= b/denominator - lower_w'.
	    N d;
	    div_round_up(d, b, denominator);
	    add_assign_r(dbm[0][v], d, dbm_w0, ROUND_UP);
	    status.reset_shortest_path_closed();
	  }
	  const N& dbm_0w = dbm[0][w];
	  if (!is_plus_infinity(dbm_0w)) {
	    // Add the constraint `v >= b/denominator - upper_w'.
	    N c;
	    div_round_up(c, b, minus_den);
	    add_assign_r(dbm[v][0], dbm_0w, c, ROUND_UP);
	    status.reset_shortest_path_closed();
	  }
	}
      }
      assert(OK());
      return;
    }
  }

  // General case.
  // Either t == 2, so that
  // expr == a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2,
  // or t == 1, expr == a*w + b, but a <> +/- denominator.
  // We will remove all the constraints on `var' and add back
  // constraints providing upper and lower bounds for `var'.

  // Compute upper approximations for `expr' and `-expr'
  // into `pos_sum' and `neg_sum', respectively, taking into account
  // the sign of `denominator'.
  // Note: approximating `-expr' from above and then negating the
  // result is the same as approximating `expr' from below.
  const bool is_sc = (denominator > 0);
  TEMP_INTEGER(minus_b);
  neg_assign(minus_b, b);
  const Coefficient& sc_b = is_sc ? b : minus_b;
  const Coefficient& minus_sc_b = is_sc ? minus_b : b;
  const Coefficient& sc_den = is_sc ? denominator : minus_den;
  const Coefficient& minus_sc_den = is_sc ? minus_den : denominator;
  // NOTE: here, for optimization purposes, `minus_expr' is only assigned
  // when `denominator' is negative. Do not use it unless you are sure
  // it has been correctly assigned.
  Linear_Expression minus_expr;
  if (!is_sc)
    minus_expr = -expr;
  const Linear_Expression& sc_expr = is_sc ? expr : minus_expr;

  N pos_sum;
  N neg_sum;
  // Indices of the variables that are unbounded in `this->dbm'.
  // (The initializations are just to quiet a compiler warning.)
  dimension_type pos_pinf_index = 0;
  dimension_type neg_pinf_index = 0;
  // Number of unbounded variables found.
  dimension_type pos_pinf_count = 0;
  dimension_type neg_pinf_count = 0;

  // Approximate the inhomogeneous term.
  assign_r(pos_sum, sc_b, ROUND_UP);
  assign_r(neg_sum, minus_sc_b, ROUND_UP);

  // Approximate the homogeneous part of `sc_expr'.
  // Note: indices above `w' can be disregarded, as they all have
  // a zero coefficient in `sc_expr'.
  const DB_Row<N>& dbm_0 = dbm[0];
  for (dimension_type i = w; i > 0; --i) {
    const Coefficient& sc_i = sc_expr.coefficient(Variable(i-1));
    const int sign_i = sgn(sc_i);
    if (sign_i > 0) {
      N coeff_i;
      assign_r(coeff_i, sc_i, ROUND_UP);
      // Approximating `sc_expr'.
      if (pos_pinf_count <= 1) {
	const N& up_approx_i = dbm_0[i];
	if (!is_plus_infinity(up_approx_i))
	  add_mul_assign_r(pos_sum, coeff_i, up_approx_i, ROUND_UP);
	else {
	  ++pos_pinf_count;
	  pos_pinf_index = i;
	}
      }
      // Approximating `-sc_expr'.
      if (neg_pinf_count <= 1) {
	const N& up_approx_minus_i = dbm[i][0];
	if (!is_plus_infinity(up_approx_minus_i))
	  add_mul_assign_r(neg_sum, coeff_i, up_approx_minus_i, ROUND_UP);
	else {
	  ++neg_pinf_count;
	  neg_pinf_index = i;
	}
      }
    }
    else if (sign_i < 0) {
      TEMP_INTEGER(minus_sc_i);
      neg_assign(minus_sc_i, sc_i);
      N minus_coeff_i;
      assign_r(minus_coeff_i, minus_sc_i, ROUND_UP);
      // Approximating `sc_expr'.
      if (pos_pinf_count <= 1) {
	const N& up_approx_minus_i = dbm[i][0];
	if (!is_plus_infinity(up_approx_minus_i))
	  add_mul_assign_r(pos_sum,
			   minus_coeff_i, up_approx_minus_i, ROUND_UP);
	else {
	  ++pos_pinf_count;
	  pos_pinf_index = i;
	}
      }
      // Approximating `-sc_expr'.
      if (neg_pinf_count <= 1) {
	const N& up_approx_i = dbm_0[i];
	if (!is_plus_infinity(up_approx_i))
	  add_mul_assign_r(neg_sum, minus_coeff_i, up_approx_i, ROUND_UP);
	else {
	  ++neg_pinf_count;
	  neg_pinf_index = i;
	}
      }
    }
  }

  // Remove all constraints on 'v'.
  forget_all_dbm_constraints(v);
  // Shortest-path closure is maintained, but not reduction.
  if (marked_shortest_path_reduced())
    status.reset_shortest_path_reduced();
  // Return immediately if no approximation could be computed.
  if (pos_pinf_count > 1 && neg_pinf_count > 1) {
    assert(OK());
    return;
  }

  // In the following, shortest-path closure will be definitely lost.
  status.reset_shortest_path_closed();

  // Before computing quotients, the denominator should be approximated
  // towards zero. Since `sc_den' is known to be positive, this amounts to
  // rounding downwards, which is achieved as usual by rounding upwards
  // `minus_sc_den' and negating again the result.
  N down_sc_den;
  assign_r(down_sc_den, minus_sc_den, ROUND_UP);
  neg_assign_r(down_sc_den, down_sc_den, ROUND_UP);

  // Exploit the upper approximation, if possible.
  if (pos_pinf_count <= 1) {
    // Compute quotient (if needed).
    if (down_sc_den != 1)
      div_assign_r(pos_sum, pos_sum, down_sc_den, ROUND_UP);
    // Add the upper bound constraint, if meaningful.
    if (pos_pinf_count == 0) {
      // Add the constraint `v <= pos_sum'.
      DB_Row<N>& dbm_0 = dbm[0];
      assign_r(dbm_0[v], pos_sum, ROUND_UP);
      // Deduce constraints of the form `v - u', where `u != v'.
      deduce_v_minus_u_bounds(v, w, sc_expr, sc_den, pos_sum);
    }
    else
      // Here `pos_pinf_count == 1'.
      if (pos_pinf_index != v
	  && sc_expr.coefficient(Variable(pos_pinf_index-1)) == sc_den)
	// Add the constraint `v - pos_pinf_index <= pos_sum'.
	assign_r(dbm[pos_pinf_index][v], pos_sum, ROUND_UP);
  }

  // Exploit the lower approximation, if possible.
  if (neg_pinf_count <= 1) {
    // Compute quotient (if needed).
    if (down_sc_den != 1)
      div_assign_r(neg_sum, neg_sum, down_sc_den, ROUND_UP);
    // Add the lower bound constraint, if meaningful.
    if (neg_pinf_count == 0) {
      // Add the constraint `v >= -neg_sum', i.e., `-v <= neg_sum'.
      DB_Row<N>& dbm_v = dbm[v];
      assign_r(dbm_v[0], neg_sum, ROUND_UP);
      // Deduce constraints of the form `u - v', where `u != v'.
      deduce_u_minus_v_bounds(v, w, sc_expr, sc_den, neg_sum);
    }
    else
      // Here `neg_pinf_count == 1'.
      if (neg_pinf_index != v
	  && sc_expr.coefficient(Variable(neg_pinf_index-1)) == sc_den)
	// Add the constraint `v - neg_pinf_index >= -neg_sum',
	// i.e., `neg_pinf_index - v <= neg_sum'.
	assign_r(dbm[v][neg_pinf_index], neg_sum, ROUND_UP);
  }

  assert(OK());
}

template <typename T>
void
BD_Shape<T>::affine_preimage(const Variable var,
			     const Linear_Expression& expr,
			     Coefficient_traits::const_reference denominator) {
  // The denominator cannot be zero.
  if (denominator == 0)
    throw_generic("affine_preimage(v, e, d)", "d == 0");

  // Dimension-compatibility checks.
  // The dimension of `expr' should not be greater than the dimension
  // of `*this'.
  const dimension_type space_dim = space_dimension();
  const dimension_type expr_space_dim = expr.space_dimension();
  if (space_dim < expr_space_dim)
    throw_dimension_incompatible("affine_preimage(v, e, d)", "e", expr);

  // `var' should be one of the dimensions of
  // the systems of bounded differences.
  const dimension_type v = var.id() + 1;
  if (v > space_dim)
    throw_dimension_incompatible("affine_preimage(v, e, d)", var.id());

  // The image of an empty BDS is empty too.
  shortest_path_closure_assign();
  if (marked_empty())
    return;

  const Coefficient& b = expr.inhomogeneous_term();
  // Number of non-zero coefficients in `expr': will be set to
  // 0, 1, or 2, the latter value meaning any value greater than 1.
  dimension_type t = 0;
  // Index of the last non-zero coefficient in `expr', if any.
  dimension_type j = 0;
  // Get information about the number of non-zero coefficients in `expr'.
  for (dimension_type i = expr_space_dim; i-- > 0; )
    if (expr.coefficient(Variable(i)) != 0)
      if (t++ == 1)
	break;
      else
        j = i;

  // Now we know the form of `expr':
  // - If t == 0, then expr = b, with `b' a constant;
  // - If t == 1, then expr = a*w + b, where `w' can be `v' or another
  //   variable; in this second case we have to check whether `a' is
  //   equal to `denominator' or `-denominator', since otherwise we have
  //   to fall back on the general form;
  // - If t > 1, the `expr' is of the general form.
  if (t == 0) {
    // Case 1: expr = n; remove all constraints on `var'.
    forget_all_dbm_constraints(v);
    // Shortest-path closure is preserved, but not reduction.
    if (marked_shortest_path_reduced())
      status.reset_shortest_path_reduced();
    assert(OK());
    return;
  }

  if (t == 1) {
    // Value of the one and only non-zero coefficient in `expr'.
    const Coefficient& a = expr.coefficient(Variable(j));
    if (a == denominator || a == -denominator) {
      // Case 2: expr = a*w + b, with a = +/- denominator.
      if (j == var.id())
	// Apply affine_image() on the inverse of this transformation.
	affine_image(var, a*var - b, denominator);
      else {
	// `expr == a*w + b', where `w != v'.
	// Remove all constraints on `var'.
	forget_all_dbm_constraints(v);
	// Shortest-path closure is preserved, but not reduction.
	if (marked_shortest_path_reduced())
	  status.reset_shortest_path_reduced();
      }
      assert(OK());
      return;
    }
  }

  // General case.
  // Either t == 2, so that
  // expr = a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2,
  // or t = 1, expr = a*w + b, but a <> +/- denominator.
  const Coefficient& expr_v = expr.coefficient(var);
  if (expr_v != 0) {
    // The transformation is invertible.
    Linear_Expression inverse((expr_v + denominator)*var);
    inverse -= expr;
    affine_image(var, inverse, expr_v);
  }
  else {
    // Transformation not invertible: all constraints on `var' are lost.
    forget_all_dbm_constraints(v);
    // Shortest-path closure is preserved, but not reduction.
    if (marked_shortest_path_reduced())
      status.reset_shortest_path_reduced();
  }
  assert(OK());
}

template <typename T>
void
BD_Shape<T>::generalized_affine_image(const Variable var,
				      const Relation_Symbol relsym,
				      const Linear_Expression& expr,
				      Coefficient_traits::const_reference
				      denominator) {
  using Implementation::BD_Shapes::div_round_up;

  // The denominator cannot be zero.
  if (denominator == 0)
    throw_generic("generalized_affine_image(v, r, e, d)", "d == 0");

  // Dimension-compatibility checks.
  // The dimension of `expr' should not be greater than the dimension
  // of `*this'.
  const dimension_type space_dim = space_dimension();
  const dimension_type expr_space_dim = expr.space_dimension();
  if (space_dim < expr_space_dim)
    throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
				 "e", expr);

  // `var' should be one of the dimensions of the BDS.
  const dimension_type v = var.id() + 1;
  if (v > space_dim)
    throw_dimension_incompatible("generalized_affine_image(v, r, e, d)",
				 var.id());

  // The relation symbol cannot be a strict relation symbol.
  if (relsym == LESS_THAN || relsym == GREATER_THAN)
    throw_generic("generalized_affine_image(v, r, e, d)",
  		  "r is a strict relation symbol and "
  		  "*this is a BD_Shape");

  if (relsym == EQUAL) {
    // The relation symbol is "==":
    // this is just an affine image computation.
    affine_image(var, expr, denominator);
    assert(OK());
    return;
  }

  // The image of an empty BDS is empty too.
  shortest_path_closure_assign();
  if (marked_empty())
    return;

  const Coefficient& b = expr.inhomogeneous_term();
  // Number of non-zero coefficients in `expr': will be set to
  // 0, 1, or 2, the latter value meaning any value greater than 1.
  dimension_type t = 0;
  // Index of the last non-zero coefficient in `expr', if any.
  dimension_type w = 0;
  // Get information about the number of non-zero coefficients in `expr'.
  for (dimension_type i = expr_space_dim; i-- > 0; )
    if (expr.coefficient(Variable(i)) != 0)
      if (t++ == 1)
	break;
      else
	w = i+1;

  // Now we know the form of `expr':
  // - If t == 0, then expr == b, with `b' a constant;
  // - If t == 1, then expr == a*w + b, where `w' can be `v' or another
  //   variable; in this second case we have to check whether `a' is
  //   equal to `denominator' or `-denominator', since otherwise we have
  //   to fall back on the general form;
  // - If t == 2, the `expr' is of the general form.
  DB_Row<N>& dbm_0 = dbm[0];
  DB_Row<N>& dbm_v = dbm[v];
  TEMP_INTEGER(minus_den);
  neg_assign(minus_den, denominator);

  if (t == 0) {
    // Case 1: expr == b.
    // Remove all constraints on `var'.
    forget_all_dbm_constraints(v);
    // Both shortest-path closure and reduction are lost.
    status.reset_shortest_path_closed();
    switch (relsym) {
    case LESS_THAN_OR_EQUAL:
      // Add the constraint `var <= b/denominator'.
      add_dbm_constraint(0, v, b, denominator);
      break;
    case GREATER_THAN_OR_EQUAL:
      // Add the constraint `var >= b/denominator',
      // i.e., `-var <= -b/denominator',
      add_dbm_constraint(v, 0, b, minus_den);
      break;
    default:
      // We already dealt with the other cases.
      throw std::runtime_error("PPL internal error");
      break;
    }
    assert(OK());
    return;
  }

  if (t == 1) {
    // Value of the one and only non-zero coefficient in `expr'.
    const Coefficient& a = expr.coefficient(Variable(w-1));
    if (a == denominator || a == minus_den) {
      // Case 2: expr == a*w + b, with a == +/- denominator.
      N d;
      switch (relsym) {
      case LESS_THAN_OR_EQUAL:
	div_round_up(d, b, denominator);
	if (w == v) {
	  // `expr' is of the form: a*v + b.
	  // Shortest-path closure and reduction are not preserved.
	  status.reset_shortest_path_closed();
	  if (a == denominator) {
	    // Translate each constraint `v - w <= dbm_wv'
	    // into the constraint `v - w <= dbm_wv + b/denominator';
	    // forget each constraint `w - v <= dbm_vw'.
	    for (dimension_type i = space_dim + 1; i-- > 0; ) {
	      N& dbm_iv = dbm[i][v];
	      add_assign_r(dbm_iv, dbm_iv, d, ROUND_UP);
	      dbm_v[i] = PLUS_INFINITY;
	    }
	  }
	  else {
	    // Here `a == -denominator'.
	    // Translate the constraint `0 - v <= dbm_v0'
	    // into the constraint `0 - v <= dbm_v0 + b/denominator'.
	    N& dbm_v0 = dbm_v[0];
	    add_assign_r(dbm_0[v], dbm_v0, d, ROUND_UP);
	    // Forget all the other constraints on `v'.
	    dbm_v0 = PLUS_INFINITY;
	    forget_binary_dbm_constraints(v);
	  }
	}
	else {
	  // Here `w != v', so that `expr' is of the form
	  // +/-denominator * w + b, with `w != v'.
	  // Remove all constraints on `v'.
	  forget_all_dbm_constraints(v);
	  // Shortest-path closure is preserved, but not reduction.
	  if (marked_shortest_path_reduced())
	    status.reset_shortest_path_reduced();
	  if (a == denominator)
	    // Add the new constraint `v - w <= b/denominator'.
	    add_dbm_constraint(w, v, d);
	  else {
	    // Here a == -denominator, so that we should be adding
	    // the constraint `v <= b/denominator - w'.
	    // Approximate it by computing a lower bound for `w'.
	    const N& dbm_w0 = dbm[w][0];
	    if (!is_plus_infinity(dbm_w0)) {
	      // Add the constraint `v <= b/denominator - lb_w'.
	      add_assign_r(dbm_0[v], d, dbm_w0, ROUND_UP);
	      // Shortest-path closure is not preserved.
	      status.reset_shortest_path_closed();
	    }
	  }
	}
	break;

      case GREATER_THAN_OR_EQUAL:
	div_round_up(d, b, minus_den);
	if (w == v) {
	  // `expr' is of the form: a*w + b.
	  // Shortest-path closure and reduction are not preserved.
	  status.reset_shortest_path_closed();
	  if (a == denominator) {
	    // Translate each constraint `w - v <= dbm_vw'
	    // into the constraint `w - v <= dbm_vw - b/denominator';
	    // forget each constraint `v - w <= dbm_wv'.
	    for (dimension_type i = space_dim + 1; i-- > 0; ) {
	      N& dbm_vi = dbm_v[i];
	      add_assign_r(dbm_vi, dbm_vi, d, ROUND_UP);
	      dbm[i][v] = PLUS_INFINITY;
	    }
	  }
	  else {
	    // Here `a == -denominator'.
	    // Translate the constraint `0 - v <= dbm_v0'
	    // into the constraint `0 - v <= dbm_0v - b/denominator'.
	    N& dbm_0v = dbm_0[v];
	    add_assign_r(dbm_v[0], dbm_0v, d, ROUND_UP);
	    // Forget all the other constraints on `v'.
	    dbm_0v = PLUS_INFINITY;
	    forget_binary_dbm_constraints(v);
	  }
	}
	else {
	  // Here `w != v', so that `expr' is of the form
	  // +/-denominator * w + b, with `w != v'.
	  // Remove all constraints on `v'.
	  forget_all_dbm_constraints(v);
	  // Shortest-path closure is preserved, but not reduction.
	  if (marked_shortest_path_reduced())
	    status.reset_shortest_path_reduced();
	  if (a == denominator)
	    // Add the new constraint `v - w >= b/denominator',
	    // i.e., `w - v <= -b/denominator'.
	    add_dbm_constraint(v, w, d);
	  else {
	    // Here a == -denominator, so that we should be adding
	    // the constraint `v >= -w + b/denominator',
	    // i.e., `-v <= w - b/denominator'.
	    // Approximate it by computing an upper bound for `w'.
	    const N& dbm_0w = dbm_0[w];
	    if (!is_plus_infinity(dbm_0w)) {
	      // Add the constraint `-v <= ub_w - b/denominator'.
	      add_assign_r(dbm_v[0], dbm_0w, d, ROUND_UP);
	      // Shortest-path closure is not preserved.
	      status.reset_shortest_path_closed();
	    }
	  }
	}
	break;

      default:
	// We already dealt with the other cases.
	throw std::runtime_error("PPL internal error");
	break;
      }
      assert(OK());
      return;
    }
  }

  // General case.
  // Either t == 2, so that
  // expr == a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2,
  // or t == 1, expr == a*w + b, but a <> +/- denominator.
  // We will remove all the constraints on `v' and add back
  // a constraint providing an upper or a lower bound for `v'
  // (depending on `relsym').
  const bool is_sc = (denominator > 0);
  TEMP_INTEGER(minus_b);
  neg_assign(minus_b, b);
  const Coefficient& sc_b = is_sc ? b : minus_b;
  const Coefficient& minus_sc_b = is_sc ? minus_b : b;
  const Coefficient& sc_den = is_sc ? denominator : minus_den;
  const Coefficient& minus_sc_den = is_sc ? minus_den : denominator;
  // NOTE: here, for optimization purposes, `minus_expr' is only assigned
  // when `denominator' is negative. Do not use it unless you are sure
  // it has been correctly assigned.
  Linear_Expression minus_expr;
  if (!is_sc)
    minus_expr = -expr;
  const Linear_Expression& sc_expr = is_sc ? expr : minus_expr;

  N sum;
  // Index of variable that is unbounded in `this->dbm'.
  // (The initialization is just to quiet a compiler warning.)
  dimension_type pinf_index = 0;
  // Number of unbounded variables found.
  dimension_type pinf_count = 0;

  switch (relsym) {
  case LESS_THAN_OR_EQUAL:
    // Compute an upper approximation for `sc_expr' into `sum'.

    // Approximate the inhomogeneous term.
    assign_r(sum, sc_b, ROUND_UP);
    // Approximate the homogeneous part of `sc_expr'.
    // Note: indices above `w' can be disregarded, as they all have
    // a zero coefficient in `sc_expr'.
    for (dimension_type i = w; i > 0; --i) {
      const Coefficient& sc_i = sc_expr.coefficient(Variable(i-1));
      const int sign_i = sgn(sc_i);
      if (sign_i == 0)
	continue;
      // Choose carefully: we are approximating `sc_expr'.
      const N& approx_i = (sign_i > 0) ? dbm_0[i] : dbm[i][0];
      if (is_plus_infinity(approx_i)) {
	if (++pinf_count > 1)
	  break;
	pinf_index = i;
	continue;
      }
      N coeff_i;
      if (sign_i > 0)
	assign_r(coeff_i, sc_i, ROUND_UP);
      else {
	TEMP_INTEGER(minus_sc_i);
	neg_assign(minus_sc_i, sc_i);
	assign_r(coeff_i, minus_sc_i, ROUND_UP);
      }
      add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
    }

    // Remove all constraints on `v'.
    forget_all_dbm_constraints(v);
    // Shortest-path closure is preserved, but not reduction.
    if (marked_shortest_path_reduced())
      status.reset_shortest_path_reduced();
    // Return immediately if no approximation could be computed.
    if (pinf_count > 1) {
      assert(OK());
      return;
    }

    // Divide by the (sign corrected) denominator (if needed).
    if (sc_den != 1) {
      // Before computing the quotient, the denominator should be approximated
      // towards zero. Since `sc_den' is known to be positive, this amounts to
      // rounding downwards, which is achieved as usual by rounding upwards
      // `minus_sc_den' and negating again the result.
      N down_sc_den;
      assign_r(down_sc_den, minus_sc_den, ROUND_UP);
      neg_assign_r(down_sc_den, down_sc_den, ROUND_UP);
      div_assign_r(sum, sum, down_sc_den, ROUND_UP);
    }

    if (pinf_count == 0) {
      // Add the constraint `v <= sum'.
      add_dbm_constraint(0, v, sum);
      // Deduce constraints of the form `v - u', where `u != v'.
      deduce_v_minus_u_bounds(v, w, sc_expr, sc_den, sum);
    }
    else if (pinf_count == 1)
      if (pinf_index != v
	  && expr.coefficient(Variable(pinf_index-1)) == denominator)
	// Add the constraint `v - pinf_index <= sum'.
	add_dbm_constraint(pinf_index, v, sum);
    break;

  case GREATER_THAN_OR_EQUAL:
    // Compute an upper approximation for `-sc_expr' into `sum'.
    // Note: approximating `-sc_expr' from above and then negating the
    // result is the same as approximating `sc_expr' from below.

    // Approximate the inhomogeneous term.
    assign_r(sum, minus_sc_b, ROUND_UP);
    // Approximate the homogeneous part of `-sc_expr'.
    for (dimension_type i = expr_space_dim + 1; i > 0; --i) {
      const Coefficient& sc_i = sc_expr.coefficient(Variable(i-1));
      const int sign_i = sgn(sc_i);
      if (sign_i == 0)
	continue;
      // Choose carefully: we are approximating `-sc_expr'.
      const N& approx_i = (sign_i > 0) ? dbm[i][0] : dbm_0[i];
      if (is_plus_infinity(approx_i)) {
	if (++pinf_count > 1)
	  break;
	pinf_index = i;
	continue;
      }
      N coeff_i;
      if (sign_i > 0)
	assign_r(coeff_i, sc_i, ROUND_UP);
      else {
	TEMP_INTEGER(minus_sc_i);
	neg_assign(minus_sc_i, sc_i);
	assign_r(coeff_i, minus_sc_i, ROUND_UP);
      }
      add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
    }

    // Remove all constraints on `var'.
    forget_all_dbm_constraints(v);
    // Shortest-path closure is preserved, but not reduction.
    if (marked_shortest_path_reduced())
      status.reset_shortest_path_reduced();
    // Return immediately if no approximation could be computed.
    if (pinf_count > 1) {
      assert(OK());
      return;
    }

    // Divide by the (sign corrected) denominator (if needed).
    if (sc_den != 1) {
      // Before computing the quotient, the denominator should be approximated
      // towards zero. Since `sc_den' is known to be positive, this amounts to
      // rounding downwards, which is achieved as usual by rounding upwards
      // `minus_sc_den' and negating again the result.
      N down_sc_den;
      assign_r(down_sc_den, minus_sc_den, ROUND_UP);
      neg_assign_r(down_sc_den, down_sc_den, ROUND_UP);
      div_assign_r(sum, sum, down_sc_den, ROUND_UP);
    }

    if (pinf_count == 0) {
      // Add the constraint `v >= -sum', i.e., `-v <= sum'.
      add_dbm_constraint(v, 0, sum);
      // Deduce constraints of the form `u - v', where `u != v'.
      deduce_u_minus_v_bounds(v, w, sc_expr, sc_den, sum);
    }
    else if (pinf_count == 1)
      if (pinf_index != v
	  && expr.coefficient(Variable(pinf_index-1)) == denominator)
	// Add the constraint `v - pinf_index >= -sum',
	// i.e., `pinf_index - v <= sum'.
	add_dbm_constraint(v, pinf_index, sum);
    break;

  default:
    // We already dealt with the other cases.
    throw std::runtime_error("PPL internal error");
    break;
  }
  assert(OK());
}

template <typename T>
void
BD_Shape<T>::generalized_affine_image(const Linear_Expression& lhs,
				      const Relation_Symbol relsym,
				      const Linear_Expression& rhs) {
  // Dimension-compatibility checks.
  // The dimension of `lhs' should not be greater than the dimension
  // of `*this'.
  const dimension_type space_dim = space_dimension();
  const dimension_type lhs_space_dim = lhs.space_dimension();
  if (space_dim < lhs_space_dim)
    throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
				 "e1", lhs);

  // The dimension of `rhs' should not be greater than the dimension
  // of `*this'.
  const dimension_type rhs_space_dim = rhs.space_dimension();
  if (space_dim < rhs_space_dim)
    throw_dimension_incompatible("generalized_affine_image(e1, r, e2)",
				 "e2", rhs);

  // Strict relation symbols are not admitted for BDSs.
  if (relsym == LESS_THAN || relsym == GREATER_THAN)
    throw_generic("generalized_affine_image(e1, r, e2)",
		  "r is a strict relation symbol and "
		  "*this is a BD_Shape");

  // The image of an empty BDS is empty.
  shortest_path_closure_assign();
  if (marked_empty())
    return;

  // Number of non-zero coefficients in `lhs': will be set to
  // 0, 1, or 2, the latter value meaning any value greater than 1.
  dimension_type t_lhs = 0;
  // Index of the last non-zero coefficient in `lhs', if any.
  dimension_type j_lhs = 0;
  // Compute the number of the non-zero components of `lhs'.
  for (dimension_type i = lhs_space_dim; i-- > 0; )
    if (lhs.coefficient(Variable(i)) != 0)
      if (t_lhs++ == 1)
	break;
      else
	j_lhs = i;

  const Coefficient& b_lhs = lhs.inhomogeneous_term();

  if (t_lhs == 0) {
    // `lhs' is a constant.
    // In principle, it is sufficient to add the constraint `lhs relsym rhs'.
    // Note that this constraint is a bounded difference if `t_rhs <= 1'
    // or `t_rhs > 1' and `rhs == a*v - a*w + b_rhs'. If `rhs' is of a
    // more general form, it will be simply ignored.
    // TODO: if it is not a bounded difference, should we compute
    // approximations for this constraint?
    switch (relsym) {
    case LESS_THAN_OR_EQUAL:
      add_constraint(lhs <= rhs);
      break;
    case EQUAL:
      add_constraint(lhs == rhs);
      break;
    case GREATER_THAN_OR_EQUAL:
      add_constraint(lhs >= rhs);
      break;
    default:
      // We already dealt with the other cases.
      throw std::runtime_error("PPL internal error");
      break;
    }
  }
  else if (t_lhs == 1) {
    // Here `lhs == a_lhs * v + b_lhs'.
    // Independently from the form of `rhs', we can exploit the
    // method computing generalized affine images for a single variable.
    Variable v(j_lhs);
    // Compute a sign-corrected relation symbol.
    const Coefficient& den = lhs.coefficient(v);
    Relation_Symbol new_relsym = relsym;
    if (den < 0)
      if (relsym == LESS_THAN_OR_EQUAL)
	new_relsym = GREATER_THAN_OR_EQUAL;
      else if (relsym == GREATER_THAN_OR_EQUAL)
	new_relsym = LESS_THAN_OR_EQUAL;
    Linear_Expression expr = rhs - b_lhs;
    generalized_affine_image(v, new_relsym, expr, den);
  }
  else {
    // Here `lhs' is of the general form, having at least two variables.
    // Compute the set of variables occurring in `lhs'.
    bool lhs_vars_intersects_rhs_vars = false;
    std::vector<Variable> lhs_vars;
    for (dimension_type i = lhs_space_dim; i-- > 0; )
      if (lhs.coefficient(Variable(i)) != 0) {
	lhs_vars.push_back(Variable(i));
	if (rhs.coefficient(Variable(i)) != 0)
	  lhs_vars_intersects_rhs_vars = true;
      }

    if (!lhs_vars_intersects_rhs_vars) {
      // `lhs' and `rhs' variables are disjoint.
      // Cylindrificate on all variables in the lhs.
      for (dimension_type i = lhs_vars.size(); i-- > 0; )
	forget_all_dbm_constraints(lhs_vars[i].id() + 1);
      // Constrain the left hand side expression so that it is related to
      // the right hand side expression as dictated by `relsym'.
      // TODO: if the following constraint is NOT a bounded difference,
      // it will be simply ignored. Should we compute approximations for it?
      switch (relsym) {
      case LESS_THAN_OR_EQUAL:
	add_constraint(lhs <= rhs);
	break;
      case EQUAL:
	add_constraint(lhs == rhs);
	break;
      case GREATER_THAN_OR_EQUAL:
	add_constraint(lhs >= rhs);
	break;
      default:
	// We already dealt with the other cases.
	throw std::runtime_error("PPL internal error");
	break;
      }
    }
    else {
      // Some variables in `lhs' also occur in `rhs'.

#if 1 // Simplified computation (see the TODO note below).

      for (dimension_type i = lhs_vars.size(); i-- > 0; )
	forget_all_dbm_constraints(lhs_vars[i].id() + 1);

#else // Currently unnecessarily complex computation.

      // More accurate computation that is worth doing only if
      // the following TODO note is accurately dealt with.

      // To ease the computation, we add an additional dimension.
      const Variable new_var = Variable(space_dim);
      add_space_dimensions_and_embed(1);
      // Constrain the new dimension to be equal to `rhs'.
      // NOTE: calling affine_image() instead of add_constraint()
      // ensures some approximation is tried even when the constraint
      // is not a bounded difference.
      affine_image(new_var, rhs);
      // Cylindrificate on all variables in the lhs.
      // NOTE: enforce shortest-path closure for precision.
      shortest_path_closure_assign();
      assert(!marked_empty());
      for (dimension_type i = lhs_vars.size(); i-- > 0; )
	forget_all_dbm_constraints(lhs_vars[i].id() + 1);
      // Constrain the new dimension so that it is related to
      // the left hand side as dictated by `relsym'.
      // TODO: each one of the following constraints is definitely NOT
      // a bounded differences (since it has 3 variables at least).
      // Thus, the method add_constraint() will simply ignore it.
      // Should we compute approximations for this constraint?
      switch (relsym) {
      case LESS_THAN_OR_EQUAL:
	add_constraint(lhs <= new_var);
	break;
      case EQUAL:
	add_constraint(lhs == new_var);
	break;
      case GREATER_THAN_OR_EQUAL:
	add_constraint(lhs >= new_var);
	break;
      default:
	// We already dealt with the other cases.
	throw std::runtime_error("PPL internal error");
	break;
      }
      // Remove the temporarily added dimension.
      remove_higher_space_dimensions(space_dim-1);
#endif // Currently unnecessarily complex computation.
    }
  }

  assert(OK());
}

template <typename T>
void
BD_Shape<T>::generalized_affine_preimage(const Variable var,
					 const Relation_Symbol relsym,
					 const Linear_Expression& expr,
					 Coefficient_traits::const_reference
					 denominator) {
  using Implementation::BD_Shapes::div_round_up;

  // The denominator cannot be zero.
  if (denominator == 0)
    throw_generic("generalized_affine_preimage(v, r, e, d)", "d == 0");

  // Dimension-compatibility checks.
  // The dimension of `expr' should not be greater than the dimension
  // of `*this'.
  const dimension_type space_dim = space_dimension();
  const dimension_type expr_space_dim = expr.space_dimension();
  if (space_dim < expr_space_dim)
    throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
				 "e", expr);

  // `var' should be one of the dimensions of the BDS.
  const dimension_type v = var.id() + 1;
  if (v > space_dim)
    throw_dimension_incompatible("generalized_affine_preimage(v, r, e, d)",
				 var.id());

  // The relation symbol cannot be a strict relation symbol.
  if (relsym == LESS_THAN || relsym == GREATER_THAN)
    throw_generic("generalized_affine_preimage(v, r, e, d)",
  		  "r is a strict relation symbol and "
  		  "*this is a BD_Shape");

  if (relsym == EQUAL) {
    // The relation symbol is "==":
    // this is just an affine preimage computation.
    affine_preimage(var, expr, denominator);
    assert(OK());
    return;
  }

  // The image of an empty BDS is empty too.
  shortest_path_closure_assign();
  if (marked_empty())
    return;

  // Check whether the preimage of this affine relation can be easily
  // computed as the image of its inverse relation.
  const Coefficient& expr_v = expr.coefficient(var);
  if (expr_v != 0) {
    const Relation_Symbol reversed_relsym = (relsym == LESS_THAN_OR_EQUAL)
      ? GREATER_THAN_OR_EQUAL : LESS_THAN_OR_EQUAL;
    const Linear_Expression inverse
      = expr - (expr_v + denominator)*var;
    TEMP_INTEGER(inverse_den);
    neg_assign(inverse_den, expr_v);
    const Relation_Symbol inverse_relsym
      = (sgn(denominator) == sgn(inverse_den)) ? relsym : reversed_relsym;
    generalized_affine_image(var, inverse_relsym, inverse, inverse_den);
    return;
  }

  // Here `var_coefficient == 0', so that the preimage cannot
  // be easily computed by inverting the affine relation.
  // Shrink the BD shape by adding the constraint induced
  // by the affine relation.
  const Coefficient& b = expr.inhomogeneous_term();
  // Number of non-zero coefficients in `expr': will be set to
  // 0, 1, or 2, the latter value meaning any value greater than 1.
  dimension_type t = 0;
  // Index of the last non-zero coefficient in `expr', if any.
  dimension_type j = 0;
  // Get information about the number of non-zero coefficients in `expr'.
  for (dimension_type i = expr_space_dim; i-- > 0; )
    if (expr.coefficient(Variable(i)) != 0)
      if (t++ == 1)
	break;
      else
	j = i+1;

  // Now we know the form of `expr':
  // - If t == 0, then expr == b, with `b' a constant;
  // - If t == 1, then expr == a*j + b, where `j != v';
  // - If t == 2, the `expr' is of the general form.
  DB_Row<N>& dbm_0 = dbm[0];

  if (t == 0) {
    // Case 1: expr == b.
    switch (relsym) {
    case LESS_THAN_OR_EQUAL:
      // Add the constraint `var <= b/denominator'.
      add_dbm_constraint(0, v, b, denominator);
      break;
    case GREATER_THAN_OR_EQUAL:
      // Add the constraint `var >= b/denominator',
      // i.e., `-var <= -b/denominator',
      add_dbm_constraint(v, 0, -b, denominator);
      break;
    default:
      // We already dealt with the other cases.
      throw std::runtime_error("PPL internal error");
      break;
    }
  }
  else if (t == 1) {
    // Value of the one and only non-zero coefficient in `expr'.
    const Coefficient& expr_j = expr.coefficient(Variable(j-1));
    N d;
    switch (relsym) {
    case LESS_THAN_OR_EQUAL:
      div_round_up(d, b, denominator);
      // Note that: `j != v', so that `expr' is of the form
      // expr_j * j + b, with `j != v'.
      if (expr_j == denominator)
	// Add the new constraint `v - j <= b/denominator'.
	add_dbm_constraint(j, v, d);
      else {
	// Here expr_j != denominator, so that we should be adding
	// the constraint `v <= b/denominator - j'.
	N sum;
	// Approximate the homogeneous part of `expr'.
	const int sign_j = sgn(expr_j);
	const N& approx_j = (sign_j > 0) ? dbm_0[j] : dbm[j][0];
	if (!is_plus_infinity(approx_j)) {
	  N coeff_j;
	  if (sign_j > 0)
	    assign_r(coeff_j, expr_j, ROUND_UP);
	  else {
	    TEMP_INTEGER(minus_expr_j);
	    neg_assign(minus_expr_j, expr_j);
	    assign_r(coeff_j, minus_expr_j, ROUND_UP);
	  }
	  add_mul_assign_r(sum, coeff_j, approx_j, ROUND_UP);
	  add_dbm_constraint(0, v, sum);
	}
      }
      break;

    case GREATER_THAN_OR_EQUAL:
      div_round_up(d, -b, denominator);
      // Note that: `j != v', so that `expr' is of the form
      // expr_j * j + b, with `j != v'.
      if (expr_j == denominator)
	// Add the new constraint `v - j >= b/denominator'.
	add_dbm_constraint(j, v, d);
      else {
	// Here expr_j != denominator, so that we should be adding
	// the constraint `v <= b/denominator - j'.
	N sum;
	// Approximate the homogeneous part of `expr_j'.
	const int sign_j = sgn(expr_j);
	const N& approx_j = (sign_j > 0) ? dbm_0[j] : dbm[j][0];
	if (!is_plus_infinity(approx_j)) {
	  N coeff_j;
	  if (sign_j > 0)
	    assign_r(coeff_j, expr_j, ROUND_UP);
	  else {
	    TEMP_INTEGER(minus_expr_j);
	    neg_assign(minus_expr_j, expr_j);
	    assign_r(coeff_j, minus_expr_j, ROUND_UP);
	  }
	  add_mul_assign_r(sum, coeff_j, approx_j, ROUND_UP);
	  add_dbm_constraint(0, v, sum);
	}
      }
      break;

    default:
      // We already dealt with the other cases.
      throw std::runtime_error("PPL internal error");
      break;
    }
  }
  else {
    // Here t == 2, so that
    // expr == a_1*x_1 + a_2*x_2 + ... + a_n*x_n + b, where n >= 2.
    const bool is_sc = (denominator > 0);
    TEMP_INTEGER(minus_b);
    neg_assign(minus_b, b);
    const Coefficient& sc_b = is_sc ? b : minus_b;
    const Coefficient& minus_sc_b = is_sc ? minus_b : b;
    TEMP_INTEGER(minus_den);
    neg_assign(minus_den, denominator);
    const Coefficient& sc_den = is_sc ? denominator : minus_den;
    const Coefficient& minus_sc_den = is_sc ? minus_den : denominator;
    // NOTE: here, for optimization purposes, `minus_expr' is only assigned
    // when `denominator' is negative. Do not use it unless you are sure
    // it has been correctly assigned.
    Linear_Expression minus_expr;
    if (!is_sc)
      minus_expr = -expr;
    const Linear_Expression& sc_expr = is_sc ? expr : minus_expr;

    N sum;
    // Index of variable that is unbounded in `this->dbm'.
    // (The initialization is just to quiet a compiler warning.)
    dimension_type pinf_index = 0;
    // Number of unbounded variables found.
    dimension_type pinf_count = 0;

    switch (relsym) {
    case LESS_THAN_OR_EQUAL:
      // Compute an upper approximation for `expr' into `sum',
      // taking into account the sign of `denominator'.

      // Approximate the inhomogeneous term.
      assign_r(sum, sc_b, ROUND_UP);

      // Approximate the homogeneous part of `sc_expr'.
      // Note: indices above `w' can be disregarded, as they all have
      // a zero coefficient in `expr'.
      for (dimension_type i = j; i > 0; --i) {
	const Coefficient& sc_i = sc_expr.coefficient(Variable(i-1));
	const int sign_i = sgn(sc_i);
	if (sign_i == 0)
	  continue;
	// Choose carefully: we are approximating `sc_expr'.
	const N& approx_i = (sign_i > 0) ? dbm_0[i] : dbm[i][0];
	if (is_plus_infinity(approx_i)) {
	  if (++pinf_count > 1)
	    break;
	  pinf_index = i;
	  continue;
	}
	N coeff_i;
	if (sign_i > 0)
	  assign_r(coeff_i, sc_i, ROUND_UP);
	else {
	  TEMP_INTEGER(minus_sc_i);
	  neg_assign(minus_sc_i, sc_i);
	  assign_r(coeff_i, minus_sc_i, ROUND_UP);
	}
	add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
      }

      // Divide by the (sign corrected) denominator (if needed).
      if (sc_den != 1) {
	// Before computing the quotient, the denominator should be
	// approximated towards zero. Since `sc_den' is known to be
	// positive, this amounts to rounding downwards, which is achieved
	// by rounding upwards `minus_sc-den' and negating again the result.
	N down_sc_den;
	assign_r(down_sc_den, minus_sc_den, ROUND_UP);
	neg_assign_r(down_sc_den, down_sc_den, ROUND_UP);
	div_assign_r(sum, sum, down_sc_den, ROUND_UP);
      }

      if (pinf_count == 0) {
	// Add the constraint `v <= sum'.
	add_dbm_constraint(0, v, sum);
	// Deduce constraints of the form `v - u', where `u != v'.
	deduce_v_minus_u_bounds(v, j, sc_expr, sc_den, sum);
      }
      else if (pinf_count == 1)
	if (expr.coefficient(Variable(pinf_index-1)) == denominator)
	  // Add the constraint `v - pinf_index <= sum'.
	  add_dbm_constraint(pinf_index, v, sum);
      break;

    case GREATER_THAN_OR_EQUAL:
      // Compute an upper approximation for `-sc_expr' into `sum'.
      // Note: approximating `-sc_expr' from above and then negating the
      // result is the same as approximating `sc_expr' from below.

      // Approximate the inhomogeneous term.
      assign_r(sum, minus_sc_b, ROUND_UP);

      // Approximate the homogeneous part of `-sc_expr'.
      for (dimension_type i = j; i > 0; --i) {
	const Coefficient& sc_i = sc_expr.coefficient(Variable(i-1));
	const int sign_i = sgn(sc_i);
	if (sign_i == 0)
	  continue;
	// Choose carefully: we are approximating `-sc_expr'.
	const N& approx_i = (sign_i > 0) ? dbm[i][0] : dbm_0[i];
	if (is_plus_infinity(approx_i)) {
	  if (++pinf_count > 1)
	    break;
	  pinf_index = i;
	  continue;
	}
	N coeff_i;
	if (sign_i > 0)
	  assign_r(coeff_i, sc_i, ROUND_UP);
	else {
	  TEMP_INTEGER(minus_sc_i);
	  neg_assign(minus_sc_i, sc_i);
	  assign_r(coeff_i, minus_sc_i, ROUND_UP);
	}
	add_mul_assign_r(sum, coeff_i, approx_i, ROUND_UP);
      }

      // Divide by the (sign corrected) denominator (if needed).
      if (sc_den != 1) {
	// Before computing the quotient, the denominator should be
	// approximated towards zero. Since `sc_den' is known to be positive,
	// this amounts to rounding downwards, which is achieved by rounding
	// upwards `minus_sc_den' and negating again the result.
	N down_sc_den;
	assign_r(down_sc_den, minus_sc_den, ROUND_UP);
	neg_assign_r(down_sc_den, down_sc_den, ROUND_UP);
	div_assign_r(sum, sum, down_sc_den, ROUND_UP);
      }

      if (pinf_count == 0) {
	// Add the constraint `v >= -sum', i.e., `-v <= sum'.
	add_dbm_constraint(v, 0, sum);
	// Deduce constraints of the form `u - v', where `u != v'.
	deduce_u_minus_v_bounds(v, j, sc_expr, sc_den, sum);
      }
      else if (pinf_count == 1)
	if (pinf_index != v
	    && expr.coefficient(Variable(pinf_index-1)) == denominator)
	  // Add the constraint `v - pinf_index >= -sum',
	  // i.e., `pinf_index - v <= sum'.
	  add_dbm_constraint(v, pinf_index, sum);
      break;

    default:
      // We already dealt with the other cases.
      throw std::runtime_error("PPL internal error");
      break;
    }
  }

  // If the shrunk BD_Shape is empty, its preimage is empty too.
  if (is_empty())
    return;
  forget_all_dbm_constraints(v);
  // Shortest-path closure is preserved, but not reduction.
  if (marked_shortest_path_reduced())
    status.reset_shortest_path_reduced();
  assert(OK());
}

template <typename T>
Constraint_System
BD_Shape<T>::constraints() const {
  using Implementation::BD_Shapes::numer_denom;

  Constraint_System cs;
  const dimension_type space_dim = space_dimension();
  if (space_dim == 0) {
    if (marked_empty())
      cs = Constraint_System::zero_dim_empty();
  }
  else if (marked_empty())
    cs.insert(0*Variable(space_dim-1) <= -1);
  else if (marked_shortest_path_reduced())
    // Disregard redundant constraints.
    cs = minimized_constraints();
  else {
    // KLUDGE: in the future `cs' will be constructed of the right dimension.
    // For the time being, we force the dimension with the following line.
    cs.insert(0*Variable(space_dim-1) <= 0);

    TEMP_INTEGER(a);
    TEMP_INTEGER(b);
    // Go through all the unary constraints in `dbm'.
    const DB_Row<N>& dbm_0 = dbm[0];
    for (dimension_type j = 1; j <= space_dim; ++j) {
      const Variable x(j-1);
      const N& dbm_0j = dbm_0[j];
      const N& dbm_j0 = dbm[j][0];
      N negated_dbm_j0;
      if (neg_assign_r(negated_dbm_j0, dbm_j0, ROUND_NOT_NEEDED) == V_EQ
	  && negated_dbm_j0 == dbm_0j) {
	// We have a unary equality constraint.
	numer_denom(dbm_0j, b, a);
	cs.insert(a*x == b);
      }
      else {
	// We have 0, 1 or 2 unary inequality constraints.
	if (!is_plus_infinity(dbm_0j)) {
	  numer_denom(dbm_0j, b, a);
	  cs.insert(a*x <= b);
	}
	if (!is_plus_infinity(dbm_j0)) {
	  numer_denom(dbm_j0, b, a);
	  cs.insert(-a*x <= b);
	}
      }
    }

    // Go through all the binary constraints in `dbm'.
    for (dimension_type i = 1; i <= space_dim; ++i) {
      const Variable y(i-1);
      const DB_Row<N>& dbm_i = dbm[i];
      for (dimension_type j = i + 1; j <= space_dim; ++j) {
	const Variable x(j-1);
	const N& dbm_ij = dbm_i[j];
	const N& dbm_ji = dbm[j][i];
	N negated_dbm_ji;
	if (neg_assign_r(negated_dbm_ji, dbm_ji, ROUND_NOT_NEEDED) == V_EQ
	    && negated_dbm_ji == dbm_ij) {
	  // We have a binary equality constraint.
	  numer_denom(dbm_ij, b, a);
	  cs.insert(a*x - a*y == b);
	}
	else {
	  // We have 0, 1 or 2 binary inequality constraints.
	  if (!is_plus_infinity(dbm_ij)) {
	    numer_denom(dbm_ij, b, a);
	    cs.insert(a*x - a*y <= b);
	  }
	  if (!is_plus_infinity(dbm_ji)) {
	    numer_denom(dbm_ji, b, a);
	    cs.insert(a*y - a*x <= b);
	  }
	}
      }
    }
  }
  return cs;
}

template <typename T>
Constraint_System
BD_Shape<T>::minimized_constraints() const {
  using Implementation::BD_Shapes::numer_denom;

  shortest_path_reduction_assign();
  Constraint_System cs;
  const dimension_type space_dim = space_dimension();
  if (space_dim == 0) {
    if (marked_empty())
      cs = Constraint_System::zero_dim_empty();
  }
  else if (marked_empty())
    cs.insert(0*Variable(space_dim-1) <= -1);
  else {
    // KLUDGE: in the future `cs' will be constructed of the right dimension.
    // For the time being, we force the dimension with the following line.
    cs.insert(0*Variable(space_dim-1) <= 0);

    TEMP_INTEGER(num);
    TEMP_INTEGER(den);

    // Compute leader information.
    std::vector<dimension_type> leaders;
    compute_leaders(leaders);
    std::vector<dimension_type> leader_indices;
    compute_leader_indices(leaders, leader_indices);
    const dimension_type num_leaders = leader_indices.size();

    // Go through the non-leaders to generate equality constraints.
    const DB_Row<N>& dbm_0 = dbm[0];
    for (dimension_type i = 1; i <= space_dim; ++i) {
      const dimension_type leader = leaders[i];
      if (i != leader)
	// Generate the constraint relating `i' and its leader.
	if (leader == 0) {
	  // A unary equality has to be generated.
	  assert(!is_plus_infinity(dbm_0[i]));
	  numer_denom(dbm_0[i], num, den);
	  cs.insert(den*Variable(i-1) == num);
	}
	else {
	  // A binary equality has to be generated.
	  assert(!is_plus_infinity(dbm[i][leader]));
	  numer_denom(dbm[i][leader], num, den);
	  cs.insert(den*Variable(leader-1) - den*Variable(i-1) == num);
	}
    }

    // Go through the leaders to generate inequality constraints.
    // First generate all the unary inequalities.
    const std::deque<bool>& red_0 = redundancy_dbm[0];
    for (dimension_type l_i = 1; l_i < num_leaders; ++l_i) {
      const dimension_type i = leader_indices[l_i];
      if (!red_0[i]) {
	numer_denom(dbm_0[i], num, den);
	cs.insert(den*Variable(i-1) <= num);
      }
      if (!redundancy_dbm[i][0]) {
	numer_denom(dbm[i][0], num, den);
	cs.insert(-den*Variable(i-1) <= num);
      }
    }
    // Then generate all the binary inequalities.
    for (dimension_type l_i = 1; l_i < num_leaders; ++l_i) {
      const dimension_type i = leader_indices[l_i];
      const DB_Row<N>& dbm_i = dbm[i];
      const std::deque<bool>& red_i = redundancy_dbm[i];
      for (dimension_type l_j = l_i + 1; l_j < num_leaders; ++l_j) {
	const dimension_type j = leader_indices[l_j];
	if (!red_i[j]) {
	  numer_denom(dbm_i[j], num, den);
	  cs.insert(den*Variable(j-1) - den*Variable(i-1) <= num);
	}
	if (!redundancy_dbm[j][i]) {
	  numer_denom(dbm[j][i], num, den);
	  cs.insert(den*Variable(i-1) - den*Variable(j-1) <= num);
	}
      }
    }
  }
  return cs;
}

/*! \relates Parma_Polyhedra_Library::BD_Shape */
template <typename T>
std::ostream&
IO_Operators::operator<<(std::ostream& s, const BD_Shape<T>& c) {
  typedef typename BD_Shape<T>::coefficient_type N;
  if (c.is_universe())
    s << "true";
  else {
    // We control empty system of bounded differences.
    dimension_type n = c.space_dimension();
    if (c.marked_empty())
      s << "false";
    else {
      bool first = true;
      for (dimension_type i = 0; i <= n; ++i)
	for (dimension_type j = i + 1; j <= n; ++j) {
	  const N& c_i_j = c.dbm[i][j];
	  const N& c_j_i = c.dbm[j][i];
	  N negated_c_ji;
	  if (neg_assign_r(negated_c_ji, c_j_i, ROUND_NOT_NEEDED) == V_EQ
	      && negated_c_ji == c_i_j) {
	    // We will print an equality.
	    if (first)
	      first = false;
	    else
	      s << ", ";
	    if (i == 0) {
	      // We have got a equality constraint with one Variable.
	      s << Variable(j - 1);
	      s << " == " << c_i_j;
	    }
	    else {
	      // We have got a equality constraint with two Variables.
	      if (c_i_j >= 0) {
		s << Variable(j - 1);
		s << " - ";
		s << Variable(i - 1);
		s << " == " << c_i_j;
	      }
	      else {
		s << Variable(i - 1);
		s << " - ";
		s << Variable(j - 1);
		s << " == " << c_j_i;
	      }
	    }
	  }
	  else {
	    // We will print a non-strict inequality.
	    if (!is_plus_infinity(c_j_i)) {
	      if (first)
		first = false;
	      else
		s << ", ";
	      if (i == 0) {
		// We have got a constraint with an only Variable.
		s << Variable(j - 1);
		N v;
		neg_assign_r(v, c_j_i, ROUND_DOWN);
		s << " >= " << v;
	      }
	      else {
		// We have got a constraint with two Variables.
		if (c_j_i >= 0) {
		  s << Variable(i - 1);
		  s << " - ";
		  s << Variable(j - 1);
		  s << " <= " << c_j_i;
		}
		else {
		  s << Variable(j - 1);
		  s << " - ";
		  s << Variable(i - 1);
		  N v;
		  neg_assign_r(v, c_j_i, ROUND_DOWN);
		  s << " >= " << v;
		}
	      }
	    }
	    if (!is_plus_infinity(c_i_j)) {
	      if (first)
		first = false;
	      else
		s << ", ";
	      if (i == 0) {
		// We have got a constraint with an only Variable.
		s << Variable(j - 1);
		s << " <= " << c_i_j;
	      }
	      else {
		// We have got a constraint with two Variables.
		if (c_i_j >= 0) {
		  s << Variable(j - 1);
		  s << " - ";
		  s << Variable(i - 1);
		  s << " <= " << c_i_j;
		}
		else {
		  s << Variable(i - 1);
		  s << " - ";
		  s << Variable(j - 1);
		  N v;
		  neg_assign_r(v, c_i_j, ROUND_DOWN);
		  s << " >= " << v;
		}
	      }
	    }
	  }
	}
    }
  }
  return s;
}

template <typename T>
void
BD_Shape<T>::ascii_dump(std::ostream& s) const {
  status.ascii_dump(s);
  s << "\n";
  dbm.ascii_dump(s);
  // Redundancy info.
  s << "\n";
  const char separator = ' ';
  const dimension_type nrows = redundancy_dbm.size();
  s << nrows << separator << "\n";
  for (dimension_type i = 0; i < nrows;  ++i) {
    for (dimension_type j = 0; j < nrows; ++j)
      s << redundancy_dbm[i][j] << separator;
    s << "\n";
  }
}

PPL_OUTPUT_TEMPLATE_DEFINITIONS(T, BD_Shape<T>);

template <typename T>
bool
BD_Shape<T>::ascii_load(std::istream& s) {
  if (!status.ascii_load(s))
    return false;
  if (!dbm.ascii_load(s))
    return false;
  // Load redundancy info.
  dimension_type nrows;
   if (!(s >> nrows))
    return false;
  redundancy_dbm.clear();
  redundancy_dbm.reserve(nrows);
  std::deque<bool> redundancy_row(nrows, false);
  for (dimension_type i = 0; i < nrows;  ++i) {
    for (dimension_type j = 0; j < nrows; ++j)
      if (!(s >> redundancy_row[j]))
	return false;
    redundancy_dbm.push_back(redundancy_row);
  }
  return true;
}

template <typename T>
bool
BD_Shape<T>::OK() const {
  // Check whether the difference-bound matrix is well-formed.
  if (!dbm.OK())
    return false;

  // Check whether the status information is legal.
  if (!status.OK())
    return false;

  // An empty BDS is OK.
  if (marked_empty())
    return true;

  // MINUS_INFINITY cannot occur at all.
  for (dimension_type i = dbm.num_rows(); i-- > 0; )
    for (dimension_type j = dbm.num_rows(); j-- > 0; )
    if (is_minus_infinity(dbm[i][j])) {
#ifndef NDEBUG
      using namespace Parma_Polyhedra_Library::IO_Operators;
      std::cerr << "BD_Shape::dbm[" << i << "][" << i << "] = "
		<< dbm[i][i] << "!"
		<< std::endl;
#endif
      return false;
    }

  // On the main diagonal only PLUS_INFINITY can occur.
  for (dimension_type i = dbm.num_rows(); i-- > 0; )
    if (!is_plus_infinity(dbm[i][i])) {
#ifndef NDEBUG
      using namespace Parma_Polyhedra_Library::IO_Operators;
      std::cerr << "BD_Shape::dbm[" << i << "][" << i << "] = "
		<< dbm[i][i] << "!  (+inf was expected.)"
		<< std::endl;
#endif
      return false;
    }

  // Check whether the shortest-path closure information is legal.
  if (marked_shortest_path_closed()) {
    BD_Shape x = *this;
    x.status.reset_shortest_path_closed();
    x.shortest_path_closure_assign();
    if (x.dbm != dbm) {
#ifndef NDEBUG
      std::cerr << "BD_Shape is marked as closed but it is not!"
		<< std::endl;
#endif
      return false;
    }
  }

  // Check whether the shortest-path reduction information is legal.
  if (marked_shortest_path_reduced()) {
    // A non-redundant constraint cannot be equal to PLUS_INFINITY.
    for (dimension_type i = dbm.num_rows(); i-- > 0; )
      for (dimension_type j = dbm.num_rows(); j-- > 0; )
	if (!redundancy_dbm[i][j] && is_plus_infinity(dbm[i][j])) {
#ifndef NDEBUG
	  using namespace Parma_Polyhedra_Library::IO_Operators;
	  std::cerr << "BD_Shape::dbm[" << i << "][" << i << "] = "
		    << dbm[i][i] << " is marked as non-redundant!"
		    << std::endl;
#endif
	  return false;
	}

    BD_Shape x = *this;
    x.status.reset_shortest_path_reduced();
    x.shortest_path_reduction_assign();
    if (x.redundancy_dbm != redundancy_dbm) {
#ifndef NDEBUG
      std::cerr << "BD_Shape is marked as reduced but it is not!"
		<< std::endl;
#endif
      return false;
    }
  }

  // All checks passed.
  return true;
}

template <typename T>
void
BD_Shape<T>::throw_dimension_incompatible(const char* method,
					  const BD_Shape& y) const {
  std::ostringstream s;
  s << "PPL::";
  s << "BD_Shape::" << method << ":" << std::endl
    << "this->space_dimension() == " << space_dimension()
    << ", y->space_dimension() == " << y.space_dimension() << ".";
  throw std::invalid_argument(s.str());
}

template <typename T>
void
BD_Shape<T>::throw_dimension_incompatible(const char* method,
					  dimension_type required_dim) const {
  std::ostringstream s;
  s << "PPL::";
  s << "BD_Shape::" << method << ":" << std::endl
    << "this->space_dimension() == " << space_dimension()
    << ", required dimension == " << required_dim << ".";
  throw std::invalid_argument(s.str());
}

template <typename T>
void
BD_Shape<T>::throw_dimension_incompatible(const char* method,
					  const Constraint& c) const {
  std::ostringstream s;
  s << "PPL::";
  s << "BD_Shape::" << method << ":" << std::endl
    << "this->space_dimension() == " << space_dimension()
    << ", c->space_dimension == " << c.space_dimension() << ".";
  throw std::invalid_argument(s.str());
}

template <typename T>
void
BD_Shape<T>::throw_dimension_incompatible(const char* method,
					  const Generator& g) const {
  std::ostringstream s;
  s << "PPL::";
  s << "BD_Shape::" << method << ":" << std::endl
    << "this->space_dimension() == " << space_dimension()
    << ", g->space_dimension == " << g.space_dimension() << ".";
  throw std::invalid_argument(s.str());
}

template <typename T>
void
BD_Shape<T>::throw_constraint_incompatible(const char* method) {
  std::ostringstream s;
  s << "PPL::BD_Shape::" << method << ":" << std::endl
    << "the constraint is incompatible.";
  throw std::invalid_argument(s.str());
}

template <typename T>
void
BD_Shape<T>::throw_expression_too_complex(const char* method,
					  const Linear_Expression& e) {
  using namespace IO_Operators;
  std::ostringstream s;
  s << "PPL::BD_Shape::" << method << ":" << std::endl
    << e << " is too complex.";
  throw std::invalid_argument(s.str());
}


template <typename T>
void
BD_Shape<T>::throw_dimension_incompatible(const char* method,
					  const char* name_row,
					  const Linear_Expression& y) const {
  std::ostringstream s;
  s << "PPL::";
  s << "BD_Shape::" << method << ":" << std::endl
    << "this->space_dimension() == " << space_dimension()
    << ", " << name_row << "->space_dimension() == "
    << y.space_dimension() << ".";
  throw std::invalid_argument(s.str());
}


template <typename T>
void
BD_Shape<T>::throw_generic(const char* method, const char* reason) {
  std::ostringstream s;
  s << "PPL::";
  s << "BD_Shape::" << method << ":" << std::endl
    << reason;
  throw std::invalid_argument(s.str());
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/BD_Shape.defs.hh line 1341

// Automatically generated from PPL source file ../src/Determinate.types.hh line 1


namespace Parma_Polyhedra_Library {

template <typename PH>
class Determinate;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Determinate.defs.hh line 1
/* Determinate class declaration.
*/


// Automatically generated from PPL source file ../src/Determinate.defs.hh line 31
#include <iosfwd>
#include <cassert>

namespace Parma_Polyhedra_Library {

/*! \brief
  Returns <CODE>true</CODE> if and only if
  \p x and \p y are the same domain element.

  \relates Determinate
*/
template <typename PH>
bool operator==(const Determinate<PH>& x, const Determinate<PH>& y);

/*! \brief
  Returns <CODE>true</CODE> if and only if
  \p x and \p y are different domain elements.

  \relates Determinate
*/
template <typename PH>
bool operator!=(const Determinate<PH>& x, const Determinate<PH>& y);

namespace IO_Operators {

//! Output operator.
/*! \relates Parma_Polyhedra_Library::Determinate */
template <typename PH>
std::ostream&
operator<<(std::ostream&, const Determinate<PH>&);

} // namespace IO_Operators

} // namespace Parma_Polyhedra_Library

//! Wraps a PPL class into a determinate constraint system interface.
/*! \ingroup PPL_CXX_interface */
template <typename PH>
class Parma_Polyhedra_Library::Determinate {
public:
  //! \name Constructors and Destructor
  //@{

  /*! \brief
    Injection operator: builds the determinate constraint system element
    corresponding to the base-level element \p p.
  */
  Determinate(const PH& p);

  /*! \brief
    Injection operator: builds the determinate constraint system element
    corresponding to the base-level element represented by \p cs.
  */
  Determinate(const Constraint_System& cs);

  //! \brief
  //! Injection operator: builds the determinate constraint system element
  //! corresponding to the base-level element represented by \p cgs.
  Determinate(const Congruence_System& cgs);

  //! Copy constructor.
  Determinate(const Determinate& y);

  //! Destructor.
  ~Determinate();

  //@} // Constructors and Destructor

  //! \name Member Functions that Do Not Modify the Domain Element
  //@{

  //! Returns a const reference to the embedded element.
  const PH& element() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is the top of the
    determinate constraint system (i.e., the whole vector space).
  */
  bool is_top() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is the bottom
    of the determinate constraint system.
  */
  bool is_bottom() const;

  //! Returns <CODE>true</CODE> if and only if \p *this entails \p y.
  bool definitely_entails(const Determinate& y) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this and \p y
    are equivalent.
  */
  bool is_definitely_equivalent_to(const Determinate& y) const;

  /*! \brief
    Returns a lower bound to the total size in bytes of the memory
    occupied by \p *this.
  */
  memory_size_type total_memory_in_bytes() const;

  /*! \brief
    Returns a lower bound to the size in bytes of the memory
    managed by \p *this.
  */
  memory_size_type external_memory_in_bytes() const;

  //! Checks if all the invariants are satisfied.
  bool OK() const;

  //@} // Member Functions that Do Not Modify the Domain Element


  //! \name Member Functions that May Modify the Domain Element
  //@{

  //! Assigns to \p *this the upper bound of \p *this and \p y.
  void upper_bound_assign(const Determinate& y);

  //! Assigns to \p *this the meet of \p *this and \p y.
  void meet_assign(const Determinate& y);

  /*! \brief
    Assigns to \p *this the \ref Concatenating_Polyhedra "concatenation"
    of \p *this and \p y, taken in this order.
  */
  void concatenate_assign(const Determinate& y);

  //! Returns a reference to the embedded element.
  PH& element();

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    On return from this method, the representation of \p *this
    is not shared by different Determinate objects.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  void mutate();

  //! Assignment operator.
  Determinate& operator=(const Determinate& y);

  //! Swaps \p *this with \p y.
  void swap(Determinate& y);

  //@} // Member Functions that May Modify the Domain Element

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  //! A function adapter for the Determinate class.
  /*! \ingroup PPL_CXX_interface
    It lifts a Binary_Operator_Assign function object, taking arguments
    of type PH, producing the corresponding function object taking
    arguments of type Determinate<PH>.

    The template parameter Binary_Operator_Assign is supposed to
    implement an <EM>apply and assign</EM> function, i.e., a function
    having signature <CODE>void foo(PH& x, const PH& y)</CODE> that
    applies an operator to \c x and \c y and assigns the result to \c x.
    For instance, such a function object is obtained by
    <CODE>std::mem_fun_ref(&C_Polyhedron::intersection_assign)</CODE>.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  template <typename Binary_Operator_Assign>
  class Binary_Operator_Assign_Lifter {
  public:
    //! Explicit unary constructor.
    explicit
    Binary_Operator_Assign_Lifter(Binary_Operator_Assign op_assign);

    //! Function-application operator.
    void operator()(Determinate& x, const Determinate& y) const;

  private:
    //! The function object to be lifted.
    Binary_Operator_Assign op_assign_;
  };

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Helper function returning a Binary_Operator_Assign_Lifter object,
    also allowing for the deduction of template arguments.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  template <typename Binary_Operator_Assign>
  static Binary_Operator_Assign_Lifter<Binary_Operator_Assign>
  lift_op_assign(Binary_Operator_Assign op_assign);

private:
  //! The possibly shared representation of a Determinate object.
  /*! \ingroup PPL_CXX_interface
    By adopting the <EM>copy-on-write</EM> technique, a single
    representation of the base-level object may be shared by more than
    one object of the class Determinate.
  */
  class Rep {
  private:
    /*! \brief
      Count the number of references:
      -   0: leaked, \p ph is non-const;
      -   1: one reference, \p ph is non-const;
      - > 1: more than one reference, \p ph is const.
    */
    mutable unsigned long references;

    //! Private and unimplemented: assignment not allowed.
    Rep& operator=(const Rep& y);

    //! Private and unimplemented: copies not allowed.
    Rep(const Rep& y);

    //! Private and unimplemented: default construction not allowed.
    Rep();

  public:
    //! A possibly shared base-level domain element.
    PH ph;

    /*! \brief
      Builds a new representation by creating a domain element
      of the specified kind, in the specified vector space.
    */
    Rep(dimension_type num_dimensions, Degenerate_Element kind);

    //! Builds a new representation by copying base-level element \p p.
    Rep(const PH& p);

    //! Builds a new representation by copying the constraints in \p cs.
    Rep(const Constraint_System& cs);

    //! Builds a new representation by copying the constraints in \p cgs.
    Rep(const Congruence_System& cgs);

    //! Destructor.
    ~Rep();

    //! Registers a new reference.
    void new_reference() const;

    /*! \brief
      Unregisters one reference; returns <CODE>true</CODE> if and only if
      the representation has become unreferenced.
    */
    bool del_reference() const;

    //! True if and only if this representation is currently shared.
    bool is_shared() const;

    /*! \brief
      Returns a lower bound to the total size in bytes of the memory
      occupied by \p *this.
    */
    memory_size_type total_memory_in_bytes() const;

    /*! \brief
      Returns a lower bound to the size in bytes of the memory
      managed by \p *this.
    */
    memory_size_type external_memory_in_bytes() const;
  };

  /*! \brief
    A pointer to the possibly shared representation of
    the base-level domain element.
  */
  Rep* prep;

  friend bool
  operator==<PH>(const Determinate<PH>& x, const Determinate<PH>& y);
  friend bool
  operator!=<PH>(const Determinate<PH>& x, const Determinate<PH>& y);
};


namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Determinate */
template <typename PH>
void swap(Parma_Polyhedra_Library::Determinate<PH>& x,
	  Parma_Polyhedra_Library::Determinate<PH>& y);

} // namespace std

// Automatically generated from PPL source file ../src/Determinate.inlines.hh line 1
/* Determinate class implementation: inline functions.
*/


#include <cassert>

namespace Parma_Polyhedra_Library {

template <typename PH>
inline
Determinate<PH>::Rep::Rep(dimension_type num_dimensions,
			  Degenerate_Element kind)
  : references(0), ph(num_dimensions, kind) {
}

template <typename PH>
inline
Determinate<PH>::Rep::Rep(const PH& p)
  : references(0), ph(p) {
}

template <typename PH>
inline
Determinate<PH>::Rep::Rep(const Constraint_System& cs)
  : references(0), ph(cs) {
}

template <typename PH>
inline
Determinate<PH>::Rep::Rep(const Congruence_System& cgs)
  : references(0), ph(cgs) {
}

template <typename PH>
inline
Determinate<PH>::Rep::~Rep() {
  assert(references == 0);
}

template <typename PH>
inline void
Determinate<PH>::Rep::new_reference() const {
  ++references;
}

template <typename PH>
inline bool
Determinate<PH>::Rep::del_reference() const {
  return --references == 0;
}

template <typename PH>
inline bool
Determinate<PH>::Rep::is_shared() const {
  return references > 1;
}

template <typename PH>
inline memory_size_type
Determinate<PH>::Rep::external_memory_in_bytes() const {
  return ph.external_memory_in_bytes();
}

template <typename PH>
inline memory_size_type
Determinate<PH>::Rep::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

template <typename PH>
inline
Determinate<PH>::Determinate(const PH& ph)
  : prep(new Rep(ph)) {
  prep->new_reference();
}

template <typename PH>
inline
Determinate<PH>::Determinate(const Constraint_System& cs)
  : prep(new Rep(cs)) {
  prep->new_reference();
}

template <typename PH>
inline
Determinate<PH>::Determinate(const Congruence_System& cgs)
  : prep(new Rep(cgs)) {
  prep->new_reference();
}

template <typename PH>
inline
Determinate<PH>::Determinate(const Determinate& y)
  : prep(y.prep) {
  prep->new_reference();
}

template <typename PH>
inline
Determinate<PH>::~Determinate() {
  if (prep->del_reference())
    delete prep;
}

template <typename PH>
inline Determinate<PH>&
Determinate<PH>::operator=(const Determinate& y) {
  y.prep->new_reference();
  if (prep->del_reference())
    delete prep;
  prep = y.prep;
  return *this;
}

template <typename PH>
inline void
Determinate<PH>::swap(Determinate& y) {
  std::swap(prep, y.prep);
}

template <typename PH>
inline void
Determinate<PH>::mutate() {
  if (prep->is_shared()) {
    Rep* new_prep = new Rep(prep->ph);
    (void) prep->del_reference();
    new_prep->new_reference();
    prep = new_prep;
  }
}

template <typename PH>
inline const PH&
Determinate<PH>::element() const {
  return prep->ph;
}

template <typename PH>
inline PH&
Determinate<PH>::element() {
  mutate();
  return prep->ph;
}

template <typename PH>
inline void
Determinate<PH>::upper_bound_assign(const Determinate& y) {
  element().upper_bound_assign(y.element());
}

template <typename PH>
inline void
Determinate<PH>::meet_assign(const Determinate& y) {
  element().intersection_assign(y.element());
}

template <typename PH>
inline void
Determinate<PH>::concatenate_assign(const Determinate& y) {
  element().concatenate_assign(y.element());
}

template <typename PH>
inline bool
Determinate<PH>::definitely_entails(const Determinate& y) const {
  return prep == y.prep || y.prep->ph.contains(prep->ph);
}

template <typename PH>
inline bool
Determinate<PH>::is_definitely_equivalent_to(const Determinate& y) const {
  return prep == y.prep || prep->ph == y.prep->ph;
}

template <typename PH>
inline bool
Determinate<PH>::is_top() const {
  return prep->ph.is_universe();
}

template <typename PH>
inline bool
Determinate<PH>::is_bottom() const {
  return prep->ph.is_empty();
}

template <typename PH>
inline memory_size_type
Determinate<PH>::external_memory_in_bytes() const {
  return prep->total_memory_in_bytes();
}

template <typename PH>
inline memory_size_type
Determinate<PH>::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

template <typename PH>
inline bool
Determinate<PH>::OK() const {
  return prep->ph.OK();
}

namespace IO_Operators {

/*! \relates Parma_Polyhedra_Library::Determinate */
template <typename PH>
inline std::ostream&
operator<<(std::ostream& s, const Determinate<PH>& x) {
  s << x.element();
  return s;
}

} // namespace IO_Operators

/*! \relates Determinate */
template <typename PH>
inline bool
operator==(const Determinate<PH>& x, const Determinate<PH>& y) {
  return x.prep == y.prep || x.prep->ph == y.prep->ph;
}

/*! \relates Determinate */
template <typename PH>
inline bool
operator!=(const Determinate<PH>& x, const Determinate<PH>& y) {
  return x.prep != y.prep && x.prep->ph != y.prep->ph;
}

template <typename PH>
template <typename Binary_Operator_Assign>
inline
Determinate<PH>::Binary_Operator_Assign_Lifter<Binary_Operator_Assign>::
Binary_Operator_Assign_Lifter(Binary_Operator_Assign op_assign)
  : op_assign_(op_assign) {
}

template <typename PH>
template <typename Binary_Operator_Assign>
inline void
Determinate<PH>::Binary_Operator_Assign_Lifter<Binary_Operator_Assign>::
operator()(Determinate& x, const Determinate& y) const {
  op_assign_(x.element(), y.element());
}

template <typename PH>
template <typename Binary_Operator_Assign>
inline
Determinate<PH>::Binary_Operator_Assign_Lifter<Binary_Operator_Assign>
Determinate<PH>::lift_op_assign(Binary_Operator_Assign op_assign) {
  return Binary_Operator_Assign_Lifter<Binary_Operator_Assign>(op_assign);
}

} // namespace Parma_Polyhedra_Library


namespace std {

/*! \relates Parma_Polyhedra_Library::Determinate */
template <typename PH>
inline void
swap(Parma_Polyhedra_Library::Determinate<PH>& x,
     Parma_Polyhedra_Library::Determinate<PH>& y) {
  x.swap(y);
}

} // namespace std

// Automatically generated from PPL source file ../src/Determinate.defs.hh line 315

// Automatically generated from PPL source file ../src/Powerset.types.hh line 1


namespace Parma_Polyhedra_Library {

template <typename D>
class Powerset;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Powerset.defs.hh line 1
/* Powerset class declaration.
*/


// Automatically generated from PPL source file ../src/Powerset.defs.hh line 27
#include <iosfwd>
#include <iterator>
#include <list>

namespace Parma_Polyhedra_Library {

//! Returns <CODE>true</CODE> if and only if \p x and \p y are equivalent.
/*! \relates Powerset */
template <typename D>
bool
operator==(const Powerset<D>& x, const Powerset<D>& y);

//! Returns <CODE>true</CODE> if and only if \p x and \p y are not equivalent.
/*! \relates Powerset */
template <typename D>
bool
operator!=(const Powerset<D>& x, const Powerset<D>& y);

namespace IO_Operators {

//! Output operator.
/*! \relates Parma_Polyhedra_Library::Powerset */
template <typename D>
std::ostream&
operator<<(std::ostream& s, const Powerset<D>& x);

} // namespace IO_Operators

} // namespace Parma_Polyhedra_Library


//! The powerset construction on a base-level domain.
/*! \ingroup PPL_CXX_interface
  This class offers a generic implementation of a
  <EM>powerset</EM> domain as defined in Section \ref powerset.

  Besides invoking the available methods on the disjuncts of a Powerset,
  this class also provides bidirectional iterators that allow for a
  direct inspection of these disjuncts. For a consistent handling of
  Omega-reduction, all the iterators are <EM>read-only</EM>, meaning
  that the disjuncts cannot be overwritten. Rather, by using the class
  <CODE>iterator</CODE>, it is possible to drop one or more disjuncts
  (possibly so as to later add back modified versions).  As an example
  of iterator usage, the following templatic function drops from
  powerset \p ps all the disjuncts that would have become redundant by
  the addition of an external element \p d.

  \code
template <typename D>
void
drop_subsumed(Powerset<D>& ps, const D& d) {
  for (typename Powerset<D>::iterator i = ps.begin(),
         ps_end = ps.end(), i != ps_end; )
    if (i->definitely_entails(d))
      i = ps.drop_disjunct(i);
    else
      ++i;
}
  \endcode

  The template class D must provide the following methods.
  \code
    memory_size_type total_memory_in_bytes() const
  \endcode
  Returns a lower bound on the total size in bytes of the memory
  occupied by the instance of D.
  \code
    bool is_top() const
  \endcode
  Returns <CODE>true</CODE> if and only if the instance of D is the top
  element of the domain.
  \code
    bool is_bottom() const
  \endcode
  Returns <CODE>true</CODE> if and only if the instance of D is the
  bottom element of the domain.
  \code
    bool definitely_entails(const D& y) const
  \endcode
  Returns <CODE>true</CODE> if the instance of D definitely entails
  <CODE>y</CODE>.  Returns <CODE>false</CODE> if the instance may not
  entail <CODE>y</CODE> (i.e., if the instance does not entail
  <CODE>y</CODE> or if entailment could not be decided).
  \code
    void upper_bound_assign(const D& y)
  \endcode
  Assigns to the instance of D an upper bound of the instance and
  <CODE>y</CODE>.
  \code
    void meet_assign(const D& y)
  \endcode
  Assigns to the instance of D the meet of the instance and
  <CODE>y</CODE>.
  \code
    bool OK() const
  \endcode
  Returns <CODE>true</CODE> if the instance of D is in a consistent
  state, else returns <CODE>false</CODE>.

  The following operators on the template class D must be defined.
  \code
    operator<<(std::ostream& s, const D& x)
  \endcode
  Writes a textual representation of the instance of D on
  <CODE>s</CODE>.
  \code
    operator==(const D& x, const D& y)
  \endcode
  Returns <CODE>true</CODE> if and only if <CODE>x</CODE> and
  <CODE>y</CODE> are equivalent D's.
  \code
    operator!=(const D& x, const D& y)
  \endcode
  Returns <CODE>true</CODE> if and only if <CODE>x</CODE> and
  <CODE>y</CODE> are different D's.
*/
template <typename D>
class Parma_Polyhedra_Library::Powerset {
public:
  //! \name Constructors and Destructor
  //@{

  /*! \brief
    Default constructor: builds the bottom of the powerset constraint
    system (i.e., the empty powerset).
  */
  Powerset();

  //! Copy constructor.
  Powerset(const Powerset& y);

  /*! \brief
    If \p d is not bottom, builds a powerset containing only \p d.
    Builds the empty powerset otherwise.
  */
  explicit Powerset(const D& d);

  //! Destructor.
  ~Powerset();

  //@} // Constructors and Destructor

  //! \name Member Functions that Do Not Modify the Powerset Element
  //@{

  /*! \brief
    Returns <CODE>true</CODE> if \p *this definitely entails \p y.
    Returns <CODE>false</CODE> if \p *this may not entail \p y
    (i.e., if \p *this does not entail \p y or if entailment could
    not be decided).
  */
  bool definitely_entails(const Powerset& y) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is the top
    element of the powerset constraint system (i.e., it represents
    the universe).
  */
  bool is_top() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is the bottom
    element of the powerset constraint system (i.e., it represents
    the empty set).
  */
  bool is_bottom() const;

  /*! \brief
    Returns a lower bound to the total size in bytes of the memory
    occupied by \p *this.
  */
  memory_size_type total_memory_in_bytes() const;

  /*! \brief
    Returns a lower bound to the size in bytes of the memory
    managed by \p *this.
  */
  memory_size_type external_memory_in_bytes() const;

  //! Checks if all the invariants are satisfied.
  // FIXME: document and perhaps use an enum instead of a bool.
  bool OK(bool disallow_bottom = false) const;

  //@} // Member Functions that Do Not Modify the Powerset Element

protected:
  //! A powerset is implemented as a sequence of elements.
  /*!
    The particular sequence employed must support efficient deletion
    in any position and efficient back insertion.
  */
  typedef std::list<D> Sequence;

  //! Alias for the low-level iterator on the disjuncts.
  typedef typename Sequence::iterator Sequence_iterator;

  //! Alias for the low-level %const_iterator on the disjuncts.
  typedef typename Sequence::const_iterator Sequence_const_iterator;

  //! The sequence container holding powerset's elements.
  Sequence sequence;

  //! If <CODE>true</CODE>, \p *this is Omega-reduced.
  mutable bool reduced;

public:
  // Sequence manipulation types, accessors and modifiers
  typedef typename Sequence::size_type size_type;
  typedef typename Sequence::value_type value_type;

  class omega_iterator;
  class omega_const_iterator;

  /*! \brief
    Alias for a <EM>read-only</EM> bidirectional %iterator on the
    disjuncts of a Powerset element.

    By using this iterator type, the disjuncts cannot be overwritten,
    but they can be removed using methods
    <CODE>drop_disjunct(iterator position)</CODE> and
    <CODE>drop_disjuncts(iterator first, iterator last)</CODE>,
    while still ensuring a correct handling of Omega-reduction.
  */
  typedef omega_iterator iterator;
  //! A bidirectional %const_iterator on the disjuncts of a Powerset element.
  typedef omega_const_iterator const_iterator;

  //! The reverse iterator type built from Powerset::iterator.
  typedef std::reverse_iterator<iterator> reverse_iterator;
  //! The reverse iterator type built from Powerset::const_iterator.
  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

  //! \name Member Functions for the Direct Manipulation of Disjuncts
  //@{

  /*! \brief
    Drops from the sequence of disjuncts in \p *this all the
    non-maximal elements so that \p *this is non-redundant.

    This method is declared <CODE>const</CODE> because, even though
    Omega-reduction may change the syntactic representation of \p *this,
    its semantics will be unchanged.
  */
  void omega_reduce() const;

  //! Returns the number of disjuncts.
  size_type size() const;

  //! Returns <CODE>true</CODE> if and only if there are no disjuncts.
  bool empty() const;

  /*! \brief
    Returns an iterator pointing to the first disjunct, if \p *this
    is not empty; otherwise, returns the past-the-end iterator.
  */
  iterator begin();

  //! Returns the past-the-end iterator.
  iterator end();

  /*! \brief
    Returns a const_iterator pointing to the first disjunct, if \p *this
    is not empty; otherwise, returns the past-the-end const_iterator.
  */
  const_iterator begin() const;

  //! Returns the past-the-end const_iterator.
  const_iterator end() const;

  /*! \brief
    Returns a reverse_iterator pointing to the last disjunct, if \p *this
    is not empty; otherwise, returns the before-the-start reverse_iterator.
  */
  reverse_iterator rbegin();
  //! Returns the before-the-start reverse_iterator.
  reverse_iterator rend();
  /*! \brief
    Returns a const_reverse_iterator pointing to the last disjunct,
    if \p *this is not empty; otherwise, returns the before-the-start
    const_reverse_iterator.
  */
  const_reverse_iterator rbegin() const;
  //! Returns the before-the-start const_reverse_iterator.
  const_reverse_iterator rend() const;

  //! Adds to \p *this the disjunct \p d.
  void add_disjunct(const D& d);

  /*! \brief
    Drops the disjunct in \p *this pointed to by \p position, returning
    an iterator to the disjunct following \p position.
  */
  iterator drop_disjunct(iterator position);

  //! Drops all the disjuncts from \p first to \p last (excluded).
  void drop_disjuncts(iterator first, iterator last);

  //! Drops all the disjuncts, making \p *this an empty powerset.
  void clear();

  //@} // Member Functions for the Direct Manipulation of Disjuncts

  //! \name Member Functions that May Modify the Powerset Element
  //@{

  //! The assignment operator.
  Powerset& operator=(const Powerset& y);

  //! Swaps \p *this with \p y.
  void swap(Powerset& y);

  //! Assigns to \p *this the least upper bound of \p *this and \p y.
  void least_upper_bound_assign(const Powerset& y);

  //! Assigns to \p *this an upper bound of \p *this and \p y.
  /*!
    The result will be the least upper bound of \p *this and \p y.
  */
  void upper_bound_assign(const Powerset& y);

  //! Assigns to \p *this the meet of \p *this and \p y.
  void meet_assign(const Powerset& y);

  /*! \brief
    If \p *this is not empty (i.e., it is not the bottom element),
    it is reduced to a singleton obtained by computing an upper-bound
    of all the disjuncts.
  */
  void collapse();

  //@} // Member Functions that May Modify the Powerset element

protected:
  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this does not contain
    non-maximal elements.
  */
  bool is_omega_reduced() const;

  /*! \brief Upon return, \p *this will contain at most \p
    max_disjuncts elements; the set of disjuncts in positions greater
    than or equal to \p max_disjuncts, will be replaced at that
    position by their upper-bound.
  */
  void collapse(unsigned max_disjuncts);

  /*! \brief
    Adds to \p *this the disjunct \p d,
    assuming \p d is not the bottom element and ensuring
    partial Omega-reduction.

    If \p d is not the bottom element and is not Omega-redundant with
    respect to elements in positions between \p first and \p last, all
    elements in these positions that would be made Omega-redundant by the
    addition of \p d are dropped and \p d is added to the reduced
    sequence.
  */
  iterator add_non_bottom_disjunct(const D& d,
				   iterator first,
				   iterator last);

  /*! \brief
    Adds to \p *this the disjunct \p d,
    assuming \p d is not the bottom element.
  */
  void add_non_bottom_disjunct(const D& d);

  /*! \brief
    Assigns to \p *this the result of applying \p op_assign pairwise
    to the elements in \p *this and \p y.

    The elements of the powerset result are obtained by applying
    \p op_assign to each pair of elements whose components are drawn
    from \p *this and \p y, respectively.
  */
  template <typename Binary_Operator_Assign>
  void pairwise_apply_assign(const Powerset& y,
			     Binary_Operator_Assign op_assign);

private:
  /*! \brief
    Does the hard work of checking whether \p *this contains non-maximal
    elements and returns <CODE>true</CODE> if and only if it does not.
  */
  bool check_omega_reduced() const;

  /*! \brief
    Replaces the disjunct \p *sink by an upper bound of itself and
    all the disjuncts following it.
  */
  void collapse(Sequence_iterator sink);
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! A %const_iterator on the disjuncts of a Powerset element.
/*! \ingroup PPL_CXX_interface
  This class implements a read-only bidirectional iterator
  on the sequence of disjuncts.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename D>
class Parma_Polyhedra_Library::Powerset<D>::omega_const_iterator {
protected:
  //! The type of the underlying %const_iterator.
  typedef typename Powerset::Sequence::const_iterator Base;

  //! A shortcut for naming traits.
  typedef typename std::iterator_traits<Base> Traits;

  //! A %const_iterator on the sequence of elements.
  Base base;

  //! Constructs from the lower-level const_iterator.
  omega_const_iterator(const Base& b);

  friend class Powerset;

public:
  // Same traits of the underlying const_iterator.
  typedef typename Traits::iterator_category iterator_category;
  typedef typename Traits::value_type value_type;
  typedef typename Traits::difference_type difference_type;
  typedef typename Traits::pointer pointer;
  typedef typename Traits::reference reference;

  //! Default constructor.
  omega_const_iterator();

  //! Copy constructor.
  omega_const_iterator(const omega_const_iterator& y);

  //! Constructs from the corresponding non-const iterator.
  omega_const_iterator(const omega_iterator& y);

  //! Dereference operator.
  reference operator*() const;

  //! Indirect member selector.
  pointer operator->() const;

  //! Prefix increment operator.
  omega_const_iterator& operator++();

  //! Postfix increment operator.
  omega_const_iterator operator++(int);

  //! Prefix decrement operator.
  omega_const_iterator& operator--();

  //! Postfix decrement operator.
  omega_const_iterator operator--(int);

  /*! \brief
    Returns <CODE>true</CODE> if and only if
    \p *this and \p y are identical.
  */
  bool operator==(const omega_const_iterator& y) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if
    \p *this and \p y are different.
  */
  bool operator!=(const omega_const_iterator& y) const;
};

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! An iterator on the disjuncts of a Powerset element.
/*! \ingroup PPL_CXX_interface
  This class implements a <EM>read-only</EM> bidirectional iterator
  on the sequence of disjuncts. That is, by using an instance of
  this iterator class it is not possible to overwrite the disjuncts
  contained in a Powerset element. However, using such an instance
  allows for the removal of disjuncts by using methods
  <CODE>Powerset::drop_disjunct(iterator position)</CODE> and
  <CODE>Powerset::drop_disjuncts(iterator first, iterator last)</CODE>.
  Such a policy is needed to allow for a reliable use of the Boolean
  flag <CODE>Powerset::reduced</CODE>.

  \note
  For any developers' need, (low-level) iterators on the sequence of
  disjuncts are still available by accessing the protected member
  <CODE>Powerset::sequence</CODE>.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename D>
class Parma_Polyhedra_Library::Powerset<D>::omega_iterator {
protected:
  //! The type of the underlying mutable iterator.
  typedef typename Powerset::Sequence::iterator Base;

  //! A shortcut for naming the const_iterator traits.
  typedef typename
  std::iterator_traits<typename Powerset::Sequence::const_iterator> Traits;

  //! A (mutable) iterator on the sequence of elements.
  Base base;

  //! Constructs from the lower-level iterator.
  omega_iterator(const Base& b);

  friend class Powerset;
  friend Powerset<D>::omega_const_iterator
  ::omega_const_iterator(const omega_iterator& y);

public:
  // Same traits of the const_iterator, therefore
  // forbidding the direct modification of sequence elements.
  typedef typename Traits::iterator_category iterator_category;
  typedef typename Traits::value_type value_type;
  typedef typename Traits::difference_type difference_type;
  typedef typename Traits::pointer pointer;
  typedef typename Traits::reference reference;

  //! Default constructor.
  omega_iterator();

  //! Copy constructor.
  omega_iterator(const omega_iterator& y);

  //! Dereference operator.
  reference operator*() const;

  //! Indirect access operator.
  pointer operator->() const;

  //! Prefix increment operator.
  omega_iterator& operator++();

  //! Postfix increment operator.
  omega_iterator operator++(int);

  //! Prefix decrement operator.
  omega_iterator& operator--();

  //! Postfix decrement operator.
  omega_iterator operator--(int);

  /*! \brief
    Returns <CODE>true</CODE> if and only if
    \p *this and \p y are identical.
  */
  bool operator==(const omega_iterator& y) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if
    \p *this and \p y are different.
  */
  bool operator!=(const omega_iterator& y) const;
};

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  Mixed comparison operator: returns <CODE>true</CODE> if and only
  if (the const version of) \p x is identical to \p y.

  \relates Powerset::omega_const_iterator
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename D>
bool
operator==(const typename Powerset<D>::omega_iterator& x,
	   const typename Powerset<D>::omega_const_iterator& y);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  Mixed comparison operator: returns <CODE>true</CODE> if and only
  if (the const version of) \p x is different from \p y.

  \relates Powerset::omega_const_iterator
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename D>
bool
operator!=(const typename Powerset<D>::omega_iterator& x,
	   const typename Powerset<D>::omega_const_iterator& y);

} // namespace Parma_Polyhedra_Library

namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Powerset */
template <typename D>
void swap(Parma_Polyhedra_Library::Powerset<D>& x,
	  Parma_Polyhedra_Library::Powerset<D>& y);

} // namespace std

// Automatically generated from PPL source file ../src/Powerset.inlines.hh line 1
/* Powerset class implementation: inline functions.
*/


#include <algorithm>
#include <cassert>

namespace Parma_Polyhedra_Library {

template <typename D>
inline
Powerset<D>::omega_iterator::omega_iterator()
  : base() {
}

template <typename D>
inline
Powerset<D>::omega_iterator::omega_iterator(const omega_iterator& y)
  : base(y.base) {
}

template <typename D>
inline
Powerset<D>::omega_iterator::omega_iterator(const Base& b)
  : base(b) {
}

template <typename D>
inline typename Powerset<D>::omega_iterator::reference
Powerset<D>::omega_iterator::operator*() const {
  return *base;
}

template <typename D>
inline typename Powerset<D>::omega_iterator::pointer
Powerset<D>::omega_iterator::operator->() const {
  return &*base;
}

template <typename D>
inline typename Powerset<D>::omega_iterator&
Powerset<D>::omega_iterator::operator++() {
  ++base;
  return *this;
}

template <typename D>
inline typename Powerset<D>::omega_iterator
Powerset<D>::omega_iterator::operator++(int) {
  omega_iterator tmp = *this;
  operator++();
  return tmp;
}

template <typename D>
inline typename Powerset<D>::omega_iterator&
Powerset<D>::omega_iterator::operator--() {
  --base;
  return *this;
}

template <typename D>
inline typename Powerset<D>::omega_iterator
Powerset<D>::omega_iterator::operator--(int) {
  omega_iterator tmp = *this;
  operator--();
  return tmp;
}

template <typename D>
inline bool
Powerset<D>::omega_iterator::operator==(const omega_iterator& y) const {
  return base == y.base;
}

template <typename D>
inline bool
Powerset<D>::omega_iterator::operator!=(const omega_iterator& y) const {
  return !operator==(y);
}

template <typename D>
inline
Powerset<D>::omega_const_iterator::omega_const_iterator()
  : base() {
}

template <typename D>
inline
Powerset<D>
::omega_const_iterator::omega_const_iterator(const omega_const_iterator& y)
  : base(y.base) {
}

template <typename D>
inline
Powerset<D>::omega_const_iterator::omega_const_iterator(const Base& b)
  : base(b) {
}

template <typename D>
inline typename Powerset<D>::omega_const_iterator::reference
Powerset<D>::omega_const_iterator::operator*() const {
  return *base;
}

template <typename D>
inline typename Powerset<D>::omega_const_iterator::pointer
Powerset<D>::omega_const_iterator::operator->() const {
  return &*base;
}

template <typename D>
inline typename Powerset<D>::omega_const_iterator&
Powerset<D>::omega_const_iterator::operator++() {
  ++base;
  return *this;
}

template <typename D>
inline typename Powerset<D>::omega_const_iterator
Powerset<D>::omega_const_iterator::operator++(int) {
  omega_const_iterator tmp = *this;
  operator++();
  return tmp;
}

template <typename D>
inline typename Powerset<D>::omega_const_iterator&
Powerset<D>::omega_const_iterator::operator--() {
  --base;
  return *this;
}

template <typename D>
inline typename Powerset<D>::omega_const_iterator
Powerset<D>::omega_const_iterator::operator--(int) {
  omega_const_iterator tmp = *this;
  operator--();
  return tmp;
}

template <typename D>
inline bool
Powerset<D>
::omega_const_iterator::operator==(const omega_const_iterator& y) const {
  return base == y.base;
}

template <typename D>
inline bool
Powerset<D>
::omega_const_iterator::operator!=(const omega_const_iterator& y) const {
  return !operator==(y);
}

template <typename D>
inline
Powerset<D>
::omega_const_iterator::omega_const_iterator(const omega_iterator& y)
  : base(y.base) {
}

/*! \relates Powerset::omega_const_iterator */
template <typename D>
inline bool
operator==(const typename Powerset<D>::omega_iterator& x,
	   const typename Powerset<D>::omega_const_iterator& y) {
  return Powerset<D>::omega_const_iterator(x).operator==(y);
}

/*! \relates Powerset::omega_const_iterator */
template <typename D>
inline bool
operator!=(const typename Powerset<D>::omega_iterator& x,
	   const typename Powerset<D>::omega_const_iterator& y) {
  return !(x == y);
}

template <typename D>
inline typename Powerset<D>::iterator
Powerset<D>::begin() {
  return sequence.begin();
}

template <typename D>
inline typename Powerset<D>::iterator
Powerset<D>::end() {
  return sequence.end();
}

template <typename D>
inline typename Powerset<D>::const_iterator
Powerset<D>::begin() const {
  return sequence.begin();
}

template <typename D>
inline typename Powerset<D>::const_iterator
Powerset<D>::end() const {
  return sequence.end();
}

template <typename D>
inline typename Powerset<D>::reverse_iterator
Powerset<D>::rbegin() {
  return reverse_iterator(end());
}

template <typename D>
inline typename Powerset<D>::reverse_iterator
Powerset<D>::rend() {
  return reverse_iterator(begin());
}

template <typename D>
inline typename Powerset<D>::const_reverse_iterator
Powerset<D>::rbegin() const {
  return const_reverse_iterator(end());
}

template <typename D>
inline typename Powerset<D>::const_reverse_iterator
Powerset<D>::rend() const {
  return const_reverse_iterator(begin());
}

template <typename D>
inline typename Powerset<D>::size_type
Powerset<D>::size() const {
  return sequence.size();
}

template <typename D>
inline bool
Powerset<D>::empty() const {
  return sequence.empty();
}

template <typename D>
inline typename Powerset<D>::iterator
Powerset<D>::drop_disjunct(iterator position) {
  return sequence.erase(position.base);
}

template <typename D>
inline void
Powerset<D>::drop_disjuncts(iterator first, iterator last) {
  sequence.erase(first.base, last.base);
}

template <typename D>
inline void
Powerset<D>::clear() {
  sequence.clear();
}

template <typename D>
inline
Powerset<D>::Powerset(const Powerset& y)
  : sequence(y.sequence), reduced(y.reduced) {
}

template <typename D>
inline Powerset<D>&
Powerset<D>::operator=(const Powerset& y) {
  sequence = y.sequence;
  reduced = y.reduced;
  return *this;
}

template <typename D>
inline void
Powerset<D>::swap(Powerset& y) {
  std::swap(sequence, y.sequence);
  std::swap(reduced, y.reduced);
}

template <typename D>
inline
Powerset<D>::Powerset()
  : sequence(), reduced(true) {
}

template <typename D>
inline
Powerset<D>::Powerset(const D& d)
  : sequence(), reduced(true) {
  if (!d.is_bottom())
    sequence.push_back(d);
  assert(OK());
}

template <typename D>
inline
Powerset<D>::~Powerset() {
}

template <typename D>
inline void
Powerset<D>::add_non_bottom_disjunct(const D& d) {
  assert(!d.is_bottom());
  add_non_bottom_disjunct(d, begin(), end());
}

template <typename D>
inline void
Powerset<D>::add_disjunct(const D& d) {
  if (!d.is_bottom())
    add_non_bottom_disjunct(d);
}

/*! \relates Powerset */
template <typename D>
inline
bool operator!=(const Powerset<D>& x, const Powerset<D>& y) {
  return !(x == y);
}

template <typename D>
inline bool
Powerset<D>::is_top() const {
  // Must perform omega-reduction for correctness.
  omega_reduce();
  const_iterator xi = begin();
  const_iterator x_end = end();
  return xi != x_end && xi->is_top() && ++xi == x_end;
}

template <typename D>
inline bool
Powerset<D>::is_bottom() const {
  // Must perform omega-reduction for correctness.
  omega_reduce();
  return empty();
}

template <typename D>
inline void
Powerset<D>::collapse() {
  if (!empty())
    collapse(sequence.begin());
}

template <typename D>
inline void
Powerset<D>::meet_assign(const Powerset& y) {
  pairwise_apply_assign(y, std::mem_fun_ref(&D::meet_assign));
}

template <typename D>
inline void
Powerset<D>::upper_bound_assign(const Powerset& y) {
  least_upper_bound_assign(y);
}

template <typename D>
inline memory_size_type
Powerset<D>::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

} // namespace Parma_Polyhedra_Library


namespace std {

/*! \relates Parma_Polyhedra_Library::Powerset */
template <typename D>
inline void
swap(Parma_Polyhedra_Library::Powerset<D>& x,
     Parma_Polyhedra_Library::Powerset<D>& y) {
  x.swap(y);
}

} // namespace std

// Automatically generated from PPL source file ../src/Powerset.templates.hh line 1
/* Powerset class implementation: non-inline template functions.
*/


#include <algorithm>
#include <cassert>
#include <iostream>

namespace Parma_Polyhedra_Library {

template <typename D>
void
Powerset<D>::collapse(const Sequence_iterator sink) {
  assert(sink != sequence.end());
  D& d = *sink;
  iterator x_sink = sink;
  iterator next_x_sink = x_sink;
  ++next_x_sink;
  iterator x_end = end();
  for (const_iterator xi = next_x_sink; xi != x_end; ++xi)
    d.upper_bound_assign(*xi);
  // Drop the surplus disjuncts.
  drop_disjuncts(next_x_sink, x_end);

  // Ensure omega-reduction.
  for (iterator xi = begin(); xi != x_sink; )
    if (xi->definitely_entails(d))
      xi = drop_disjunct(xi);
    else
      ++xi;

  assert(OK());
}

template <typename D>
void
Powerset<D>::omega_reduce() const {
  if (reduced)
    return;

  Powerset& x = const_cast<Powerset&>(*this);
  // First remove all bottom elements.
  for (iterator xi = x.begin(), x_end = x.end(); xi != x_end; )
    if (xi->is_bottom())
      xi = x.drop_disjunct(xi);
    else
      ++xi;
  // Then remove non-maximal elements.
  for (iterator xi = x.begin(); xi != x.end(); ) {
    const D& xv = *xi;
    bool dropping_xi = false;
    for (iterator yi = x.begin(); yi != x.end(); )
      if (xi == yi)
	++yi;
      else {
	const D& yv = *yi;
	if (yv.definitely_entails(xv))
	  yi = x.drop_disjunct(yi);
	else if (xv.definitely_entails(yv)) {
	  dropping_xi = true;
	  break;
	}
	else
	  ++yi;
      }
    if (dropping_xi)
      xi = x.drop_disjunct(xi);
    else
      ++xi;
    if (abandon_expensive_computations && xi != x.end()) {
      // Hurry up!
      x.collapse(xi.base);
      break;
    }
  }
  reduced = true;
  assert(OK());
}

template <typename D>
void
Powerset<D>::collapse(const unsigned max_disjuncts) {
  assert(max_disjuncts > 0);
  // Omega-reduce before counting the number of disjuncts.
  omega_reduce();
  size_type n = size();
  if (n > max_disjuncts) {
    // Let `i' point to the last disjunct that will survive.
    iterator i = begin();
    std::advance(i, max_disjuncts-1);
    // This disjunct will be assigned an upper-bound of itself and of
    // all the disjuncts that follow.
    collapse(i.base);
  }
  assert(OK());
  assert(is_omega_reduced());
}

template <typename D>
bool
Powerset<D>::check_omega_reduced() const {
  for (const_iterator x_begin = begin(), x_end = end(),
	 xi = x_begin; xi != x_end; ++xi) {
    const D& xv = *xi;
    if (xv.is_bottom())
      return false;
    for (const_iterator yi = x_begin; yi != x_end; ++yi) {
      if (xi == yi)
	continue;
      const D& yv = *yi;
      if (xv.definitely_entails(yv) || yv.definitely_entails(xv))
	return false;
    }
  }
  return true;
}

template <typename D>
bool
Powerset<D>::is_omega_reduced() const {
  if (!reduced && check_omega_reduced())
    reduced = true;
  return reduced;
}

template <typename D>
typename Powerset<D>::iterator
Powerset<D>::add_non_bottom_disjunct(const D& d,
				      iterator first,
				      iterator last) {
  for (iterator xi = first; xi != last; ) {
    const D& xv = *xi;
    if (d.definitely_entails(xv))
      return first;
    else if (xv.definitely_entails(d)) {
      if (xi == first)
	++first;
      xi = drop_disjunct(xi);
    }
    else
      ++xi;
  }
  sequence.push_back(d);
  return first;
}

template <typename D>
bool
Powerset<D>::definitely_entails(const Powerset& y) const {
  const Powerset<D>& x = *this;
  bool found = true;
  for (const_iterator xi = x.begin(),
	 x_end = x.end(); found && xi != x_end; ++xi) {
    found = false;
    for (const_iterator yi = y.begin(),
	   y_end = y.end(); !found && yi != y_end; ++yi)
      found = (*xi).definitely_entails(*yi);
  }
  return found;
}

/*! \relates Powerset */
template <typename D>
bool
operator==(const Powerset<D>& x, const Powerset<D>& y) {
  x.omega_reduce();
  y.omega_reduce();
  if (x.size() != y.size())
    return false;
  // Take a copy of `y' and work with it.
  Powerset<D> yy = y;
  for (typename Powerset<D>::const_iterator xi = x.begin(),
	 x_end = x.end(); xi != x_end; ++xi) {
    typename Powerset<D>::iterator yyi = yy.begin();
    typename Powerset<D>::iterator yy_end = yy.end();
    yyi = std::find(yyi, yy_end, *xi);
    if (yyi == yy_end)
      return false;
    else
      yy.drop_disjunct(yyi);
  }
  return true;
}

template <typename D>
template <typename Binary_Operator_Assign>
void
Powerset<D>::pairwise_apply_assign(const Powerset& y,
				    Binary_Operator_Assign op_assign) {
  // Ensure omega-reduction here, since what follows has quadratic complexity.
  omega_reduce();
  y.omega_reduce();
  Sequence new_sequence;
  for (const_iterator xi = begin(), x_end = end(),
	 y_begin = y.begin(), y_end = y.end(); xi != x_end; ++xi)
    for (const_iterator yi = y_begin; yi != y_end; ++yi) {
      D zi = *xi;
      op_assign(zi, *yi);
      if (!zi.is_bottom())
	new_sequence.push_back(zi);
    }
  // Put the new sequence in place.
  std::swap(sequence, new_sequence);
  reduced = false;
}

template <typename D>
void
Powerset<D>::least_upper_bound_assign(const Powerset& y) {
  // Ensure omega-reduction here, since what follows has quadratic complexity.
  omega_reduce();
  y.omega_reduce();
  iterator old_begin = begin();
  iterator old_end = end();
  for (const_iterator i = y.begin(), y_end = y.end(); i != y_end; ++i)
    old_begin = add_non_bottom_disjunct(*i, old_begin, old_end);
}

namespace IO_Operators {

/*! \relates Parma_Polyhedra_Library::Powerset */
template <typename D>
std::ostream&
operator<<(std::ostream& s, const Powerset<D>& x) {
  if (x.is_bottom())
    s << "false";
  else if (x.is_top())
    s << "true";
  else
    for (typename Powerset<D>::const_iterator i = x.begin(),
	   x_end = x.end(); i != x_end; ) {
      s << "{ " << *i++ << " }";
      if (i != x_end)
	s << ", ";
    }
  return s;
}

} // namespace IO_Operators

template <typename D>
memory_size_type
Powerset<D>::external_memory_in_bytes() const {
  memory_size_type bytes = 0;
  for (const_iterator xi = begin(), x_end = end(); xi != x_end; ++xi) {
    bytes += xi->total_memory_in_bytes();
    // We assume there is at least a forward and a backward link, and
    // that the pointers implementing them are at least the size of
    // pointers to `D'.
    bytes += 2*sizeof(D*);
  }
  return bytes;
}

template <typename D>
bool
Powerset<D>::OK(const bool disallow_bottom) const {
  for (const_iterator xi = begin(), x_end = end(); xi != x_end; ++xi) {
    if (!xi->OK())
      return false;
    if (disallow_bottom && xi->is_bottom()) {
#ifndef NDEBUG
      std::cerr << "Bottom element in powerset!"
		<< std::endl;
#endif
      return false;
    }
  }
  if (reduced && !check_omega_reduced()) {
#ifndef NDEBUG
    std::cerr << "Powerset claims to be reduced, but it is not!"
	      << std::endl;
#endif
    return false;
  }
  return true;
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Powerset.defs.hh line 619

// Automatically generated from PPL source file ../src/Polyhedra_Powerset.types.hh line 1


namespace Parma_Polyhedra_Library {

template <typename PH>
class Polyhedra_Powerset;

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Polyhedra_Powerset.defs.hh line 1
/* Polyhedra_Powerset class declaration.
*/


// Automatically generated from PPL source file ../src/Polyhedra_Powerset.defs.hh line 39
#include <iosfwd>
#include <list>
#include <map>

//! The powerset construction instantiated on PPL polyhedra.
/*! \ingroup PPL_CXX_interface */
template <typename PH>
class Parma_Polyhedra_Library::Polyhedra_Powerset
  : public Parma_Polyhedra_Library::Powerset
<Parma_Polyhedra_Library::Determinate<PH> > {
public:
  typedef PH element_type;

private:
  typedef Determinate<PH> CS;
  typedef Powerset<CS> Base;

public:
  //! Returns the maximum space dimension a Polyhedra_Powerset<PH> can handle.
  static dimension_type max_space_dimension();

  //! \name Constructors
  //@{

  //! Builds a universe (top) or empty (bottom) Polyhedra_Powerset.
  /*!
    \param num_dimensions
    The number of dimensions of the vector space enclosing the powerset;

    \param kind
    Specifies whether the universe or the empty powerset has to be built.
  */
  explicit
  Polyhedra_Powerset(dimension_type num_dimensions = 0,
		     Degenerate_Element kind = UNIVERSE);

  //! Ordinary copy-constructor.
  Polyhedra_Powerset(const Polyhedra_Powerset& y);

  /*! \brief
    If \p ph is nonempty, builds a powerset containing only \p ph.
    Builds the empty powerset otherwise.
  */
  explicit Polyhedra_Powerset(const PH& ph);

  /*! \brief
    Copy-constructor allowing a source powerset with elements of a
    different polyhedron kind.
  */
  template <typename QH>
  explicit Polyhedra_Powerset(const Polyhedra_Powerset<QH>& y);

  /*! \brief
    Creates a Polyhedra_Powerset with a single polyhedron
    with the same information contents as \p cs.
  */
  explicit Polyhedra_Powerset(const Constraint_System& cs);

  //! Creates a Polyhedra_Powerset with a single polyhedron
  //! with the same information contents as \p cgs.
  explicit Polyhedra_Powerset(const Congruence_System& cgs);

  //@} // Constructors and Destructor

  //! \name Member Functions that Do Not Modify the Powerset of Polyhedra
  //@{

  //! Returns the dimension of the vector space enclosing \p *this.
  dimension_type space_dimension() const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this geometrically
    covers \p y, i.e., if any point (in some element) of \p y is also
    a point (of some element) of \p *this.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.

    \warning
    This may be <EM>really</EM> expensive!
  */
  bool geometrically_covers(const Polyhedra_Powerset& y) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if \p *this is geometrically
    equal to \p y, i.e., if (the elements of) \p *this and \p y
    contain the same set of points.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.

    \warning
    This may be <EM>really</EM> expensive!
  */
  bool geometrically_equals(const Polyhedra_Powerset& y) const;

  /*! \brief
    Returns a lower bound to the total size in bytes of the memory
    occupied by \p *this.
  */
  memory_size_type total_memory_in_bytes() const;

  /*! \brief
    Returns a lower bound to the size in bytes of the memory
    managed by \p *this.
  */
  memory_size_type external_memory_in_bytes() const;

  //! Checks if all the invariants are satisfied.
  bool OK() const;

  //@} // Member Functions that Do Not Modify the Powerset

  //! \name Space Dimension Preserving Member Functions that May Modify the Powerset of Polyhedra
  //@{

  //! Adds to \p *this the disjunct \p ph.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this and \p ph are dimension-incompatible.
  */
  void add_disjunct(const PH& ph);

  //! Intersects \p *this with constraint \p c.
  /*!
    \exception std::invalid_argument
    Thrown if \p *this and constraint \p c are topology-incompatible
    or dimension-incompatible.
  */
  void add_constraint(const Constraint& c);

  //! Intersects \p *this with the constraint \p c, minimizing the result.
  /*!
    \return
    <CODE>false</CODE> if and only if the result is empty.

    \exception std::invalid_argument
    Thrown if \p *this and \p c are topology-incompatible or
    dimension-incompatible.
  */
  bool add_constraint_and_minimize(const Constraint& c);

  //! Intersects \p *this with the constraints in \p cs.
  /*!
    \param cs
    The constraints to intersect with.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are topology-incompatible or
    dimension-incompatible.
  */
  void add_constraints(const Constraint_System& cs);

  /*! \brief
    Intersects \p *this with the constraints in \p cs,
    minimizing the result.

    \return
    <CODE>false</CODE> if and only if the result is empty.

    \param cs
    The constraints to intersect with.

    \exception std::invalid_argument
    Thrown if \p *this and \p cs are topology-incompatible or
    dimension-incompatible.
  */
  bool add_constraints_and_minimize(const Constraint_System& cs);

  /*! \brief
    Assign to \p *this the result of (recursively) merging together
    the pairs of polyhedra whose poly-hull is the same as their
    set-theoretical union.

    On exit, for all the pairs \f$\cP\f$, \f$\cQ\f$ of different polyhedra
    in \p *this, we have \f$\cP \uplus \cQ \neq \cP \union \cQ\f$.
  */
  void pairwise_reduce();

  /*! \brief
    Assigns to \p *this the result of applying the
    \ref pps_bgp99_extrapolation "BGP99 extrapolation operator"
    to \p *this and \p y, using the widening function \p wf
    and the cardinality threshold \p max_disjuncts.

    \param y
    A finite powerset of polyhedra.
    It <EM>must</EM> definitely entail \p *this;

    \param wf
    The widening function to be used on polyhedra objects. It is obtained
    from the corresponding widening method by using the helper function
    Parma_Polyhedra_Library::widen_fun_ref. Legal values are, e.g.,
    <CODE>widen_fun_ref(&Polyhedron::H79_widening_assign)</CODE> and
    <CODE>widen_fun_ref(&Polyhedron::limited_H79_extrapolation_assign, cs)</CODE>;

    \param max_disjuncts
    The maximum number of disjuncts occurring in the powerset \p *this
    <EM>before</EM> starting the computation. If this number is exceeded,
    some of the disjuncts in \p *this are collapsed (i.e., joined together).

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.

    For a description of the extrapolation operator,
    see \ref BGP99 "[BGP99]" and \ref BHZ03b "[BHZ03b]".
  */
  template <typename Widening>
  void BGP99_extrapolation_assign(const Polyhedra_Powerset& y,
				  Widening wf,
				  unsigned max_disjuncts);

  /*! \brief
    Assigns to \p *this the result of computing the
    \ref pps_certificate_widening "BHZ03-widening"
    between \p *this and \p y, using the widening function \p wf
    certified by the convergence certificate \p Cert.

    \param y
    The finite powerset of polyhedra computed in the previous iteration step.
    It <EM>must</EM> definitely entail \p *this;

    \param wf
    The widening function to be used on polyhedra objects.
    It is obtained from the corresponding widening method by using
    the helper function widen_fun_ref. Legal values are, e.g.,
    <CODE>widen_fun_ref(&Polyhedron::H79_widening_assign)</CODE> and
    <CODE>widen_fun_ref(&Polyhedron::limited_H79_extrapolation_assign, cs)</CODE>.

    \exception std::invalid_argument
    Thrown if \p *this and \p y are topology-incompatible or
    dimension-incompatible.

    \warning
    In order to obtain a proper widening operator, the template parameter
    \p Cert should be a finite convergence certificate for the base-level
    widening function \p wf; otherwise, an extrapolation operator is
    obtained.
    For a description of the methods that should be provided
    by \p Cert, see BHRZ03_Certificate or H79_Certificate.
  */
  template <typename Cert, typename Widening>
  void BHZ03_widening_assign(const Polyhedra_Powerset& y, Widening wf);

  //@} // Space Dimension Preserving Member Functions that May Modify [...]

  //! \name Member Functions that May Modify the Dimension of the Vector Space
  //@{

  /*! \brief
    The assignment operator
    (\p *this and \p y can be dimension-incompatible).
  */
  Polyhedra_Powerset& operator=(const Polyhedra_Powerset& y);

  /*! \brief
    Assignment operator allowing a source powerset with elements of a
    different polyhedron kind
    (\p *this and \p y can be dimension-incompatible).
  */
  template <typename QH>
  Polyhedra_Powerset& operator=(const Polyhedra_Powerset<QH>& y);

  //! Swaps \p *this with \p y.
  void swap(Polyhedra_Powerset& y);

  /*! \brief
    Adds \p m new dimensions to the vector space containing \p *this
    and embeds each polyhedron in \p *this in the new space.
  */
  void add_space_dimensions_and_embed(dimension_type m);

  /*! \brief
    Adds \p m new dimensions to the vector space containing \p *this
    without embedding the polyhedra in \p *this in the new space.
  */
  void add_space_dimensions_and_project(dimension_type m);

  //! Assigns to \p *this the intersection of \p *this and \p y.
  /*!
    The result is obtained by intersecting each polyhedron in \p *this
    with each polyhedron in \p y and collecting all these intersections.
  */
  void intersection_assign(const Polyhedra_Powerset& y);

  //! Assigns to \p *this the difference of \p *this and \p y.
  /*!
    The result is obtained by computing the
    \ref Convex_Polyhedral_Difference "poly-difference" of each polyhedron
    in \p *this with each polyhedron in \p y and collecting all these
    differences.
  */
  void poly_difference_assign(const Polyhedra_Powerset& y);

  //! Assigns to \p *this the concatenation of \p *this and \p y.
  /*!
    The result is obtained by computing the pairwise
    \ref Concatenating_Polyhedra "concatenation" of each polyhedron
    in \p *this with each polyhedron in \p y.
  */
  void concatenate_assign(const Polyhedra_Powerset& y);

  /*! \brief
    Assigns to \p *this the result of computing the
    \ref Time_Elapse_Operator "time-elapse" between \p *this and \p y.

    The result is obtained by computing the pairwise
    \ref Time_Elapse_Operator "time elapse" of each polyhedron
    in \p *this with each polyhedron in \p y.
  */
  void time_elapse_assign(const Polyhedra_Powerset& y);

  //! Removes all the specified space dimensions.
  /*!
    \param to_be_removed
    The set of Variable objects corresponding to the space dimensions
    to be removed.

    \exception std::invalid_argument
    Thrown if \p *this is dimension-incompatible with one of the
    Variable objects contained in \p to_be_removed.
  */
  void remove_space_dimensions(const Variables_Set& to_be_removed);

  /*! \brief
    Removes the higher space dimensions so that the resulting space
    will have dimension \p new_dimension.

    \exception std::invalid_argument
    Thrown if \p new_dimensions is greater than the space dimension
    of \p *this.
  */
  void remove_higher_space_dimensions(dimension_type new_dimension);

  /*! \brief
    Remaps the dimensions of the vector space according to
    a partial function.

    See also Polyhedron::map_space_dimensions.
  */
  template <typename Partial_Function>
  void map_space_dimensions(const Partial_Function& pfunc);

  //@} // Member Functions that May Modify the Dimension of the Vector Space

public:
  typedef typename Base::size_type size_type;
  typedef typename Base::value_type value_type;
  typedef typename Base::iterator iterator;
  typedef typename Base::const_iterator const_iterator;
  typedef typename Base::reverse_iterator reverse_iterator;
  typedef typename Base::const_reverse_iterator const_reverse_iterator;

  PPL_OUTPUT_DECLARATIONS;

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  /*! \brief
    Loads from \p s an ASCII representation (as produced by \ref
    ascii_dump) and sets \p *this accordingly.  Returns <CODE>true</CODE>
    if successful, <CODE>false</CODE> otherwise.
  */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
  bool ascii_load(std::istream& s);

private:
  typedef typename Base::Sequence Sequence;
  typedef typename Base::Sequence_iterator Sequence_iterator;
  typedef typename Base::Sequence_const_iterator Sequence_const_iterator;

  //! The number of dimensions of the enclosing vector space.
  dimension_type space_dim;

  /*! \brief
    Assigns to \p *this the result of applying the BGP99 heuristics
    to \p *this and \p y, using the widening function \p wf.
  */
  template <typename Widening>
  void BGP99_heuristics_assign(const Polyhedra_Powerset& y, Widening wf);

  //! Records in \p cert_ms the certificates for this set of polyhedra.
  template <typename Cert>
  void collect_certificates(std::map<Cert, size_type,
		                     typename Cert::Compare>& cert_ms) const;

  /*! \brief
    Returns <CODE>true</CODE> if and only if the current set of polyhedra
    is stabilizing with respect to the multiset of certificates \p y_cert_ms.
  */
  template <typename Cert>
  bool is_cert_multiset_stabilizing(const std::map<Cert, size_type,
                                                   typename Cert::Compare>&
				    y_cert_ms) const;

  // FIXME: here it should be enough to befriend the templatic constructor
  //   template <typename QH>
  //   Polyhedra_Powerset(const Polyhedra_Powerset<QH>&)
  // but, apparently, this cannot be done.
  // As a workaround, we could use
  //   friend class Polyhedra_Powerset<NNC_Polyhedron>
  // but GCC 3.3.3 has a bug that causes its rejection.
  // So, temporarily, we make all Polyhedra_Powerset's friends of each other.
  template <typename QH> friend class Polyhedra_Powerset;
};


namespace Parma_Polyhedra_Library {

//! Partitions \p q with respect to \p p.
/*! \relates Polyhedra_Powerset
  Let \p p and \p q be two polyhedra.
  The function returns an object <CODE>r</CODE> of type
  <CODE>std::pair\<PH, Polyhedra_Powerset\<NNC_Polyhedron\> \></CODE>
  such that
  - <CODE>r.first</CODE> is the intersection of \p p and \p q;
  - <CODE>r.second</CODE> has the property that all its elements are
    pairwise disjoint and disjoint from \p p;
  - the union of <CODE>r.first</CODE> with all the elements of
    <CODE>r.second</CODE> gives \p q (i.e., <CODE>r</CODE> is the
    representation of a partition of \p q).

  \if Include_Implementation_Details

  See
  <A HREF="http://www.cs.unipr.it/ppl/Documentation/bibliography#Srivastava93">
  this paper</A> for more information about the implementation.
  \endif
*/
template <typename PH>
std::pair<PH, Polyhedra_Powerset<NNC_Polyhedron> >
linear_partition(const PH& p, const PH& q);

/*! \brief
  Returns <CODE>true</CODE> if and only if the union of
  the NNC polyhedra in \p ps contains the NNC polyhedron \p ph.

  \relates Polyhedra_Powerset
*/
bool
check_containment(const NNC_Polyhedron& ph,
		  const Polyhedra_Powerset<NNC_Polyhedron>& ps);

/*! \brief
  Returns <CODE>true</CODE> if and only if the union of
  the objects in \p ps contains \p ph.

  \relates Polyhedra_Powerset
  \note
  It is assumed that the template parameter PH can be converted
  without precision loss into an NNC_Polyhedron; otherwise,
  an incorrect result might be obtained.
*/
template <typename PH>
bool
check_containment(const PH& ph, const Polyhedra_Powerset<PH>& ps);

// CHECK ME: according to the Intel compiler, the declaration of the
// following specialization (of the class template parameter) should come
// before the declaration of the corresponding full specialization
// (where the member template parameter is specialized too).
template <>
template <typename QH>
Polyhedra_Powerset<NNC_Polyhedron>
::Polyhedra_Powerset(const Polyhedra_Powerset<QH>& y);

// CHECK ME: according to the Intel compiler, the declaration of the
// following specialization (of the class template parameter) should come
// before the declaration of the corresponding full specialization
// (where the member template parameter is specialized too).
template <>
template <typename QH>
Polyhedra_Powerset<C_Polyhedron>
::Polyhedra_Powerset(const Polyhedra_Powerset<QH>& y);

// Non-inline full specializations should be declared here
// so as to inhibit multiple instantiations of the generic template.
template <>
template <>
Polyhedra_Powerset<NNC_Polyhedron>
::Polyhedra_Powerset(const Polyhedra_Powerset<C_Polyhedron>& y);

template <>
template <>
Polyhedra_Powerset<C_Polyhedron>
::Polyhedra_Powerset(const Polyhedra_Powerset<NNC_Polyhedron>& y);

template <>
void
Polyhedra_Powerset<NNC_Polyhedron>
::poly_difference_assign(const Polyhedra_Powerset& y);

template <>
bool
Polyhedra_Powerset<NNC_Polyhedron>
::geometrically_covers(const Polyhedra_Powerset& y) const;

} // namespace Parma_Polyhedra_Library


namespace std {

//! Specializes <CODE>std::swap</CODE>.
/*! \relates Parma_Polyhedra_Library::Polyhedra_Powerset */
template <typename PH>
void swap(Parma_Polyhedra_Library::Polyhedra_Powerset<PH>& x,
	  Parma_Polyhedra_Library::Polyhedra_Powerset<PH>& y);

} // namespace std

// Automatically generated from PPL source file ../src/Polyhedra_Powerset.inlines.hh line 1
/* Polyhedra_Powerset class implementation: inline functions.
*/


// Automatically generated from PPL source file ../src/Polyhedra_Powerset.inlines.hh line 34
#include <algorithm>
#include <deque>

namespace Parma_Polyhedra_Library {

template <typename PH>
inline dimension_type
Polyhedra_Powerset<PH>::space_dimension() const {
  return space_dim;
}

template <typename PH>
inline dimension_type
Polyhedra_Powerset<PH>::max_space_dimension() {
  return PH::max_space_dimension();
}

template <typename PH>
inline
Polyhedra_Powerset<PH>::Polyhedra_Powerset(dimension_type num_dimensions,
					   Degenerate_Element kind)
  : Base(), space_dim(num_dimensions) {
  Polyhedra_Powerset& x = *this;
  if (kind == UNIVERSE)
    x.sequence.push_back(Determinate<PH>(PH(num_dimensions, kind)));
  assert(x.OK());
}

template <typename PH>
inline
Polyhedra_Powerset<PH>::Polyhedra_Powerset(const Polyhedra_Powerset& y)
  : Base(y), space_dim(y.space_dim) {
}

template <typename PH>
inline
Polyhedra_Powerset<PH>::Polyhedra_Powerset(const PH& ph)
  : Base(ph), space_dim(ph.space_dimension()) {
}

// FIXME: This full specialization is declared inline and placed here
// just as a workaround to a bug in GCC 3.3.3. In principle, it should
// not be declared inline and moved in Polyhedra_Powerset.cc.
// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13635.
template <>
template <>
inline
Polyhedra_Powerset<NNC_Polyhedron>
::Polyhedra_Powerset(const Polyhedra_Powerset<C_Polyhedron>& y)
  : Base(), space_dim(y.space_dimension()) {
  Polyhedra_Powerset& x = *this;
  for (Polyhedra_Powerset<C_Polyhedron>::const_iterator i = y.begin(),
	 y_end = y.end(); i != y_end; ++i)
    x.sequence.push_back(Determinate<NNC_Polyhedron>(
                           NNC_Polyhedron(i->element()))
			 );
  x.reduced = y.reduced;
  assert(x.OK());
}

// FIXME: This full specialization is declared inline and placed here
// just as a workaround to a bug in GCC 3.3.3. In principle, it should
// not be declared inline and moved in Polyhedra_Powerset.cc.
// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13635.
template <>
template <>
inline
Polyhedra_Powerset<C_Polyhedron>
::Polyhedra_Powerset(const Polyhedra_Powerset<NNC_Polyhedron>& y)
  : Base(), space_dim(y.space_dimension()) {
  Polyhedra_Powerset& x = *this;
  for (Polyhedra_Powerset<NNC_Polyhedron>::const_iterator i = y.begin(),
	 y_end = y.end(); i != y_end; ++i)
    x.sequence.push_back(Determinate<C_Polyhedron>(
                           C_Polyhedron(i->element()))
			 );
  // Note: this might be non-reduced even when `y' is known to be
  // omega-reduced, because the constructor of C_Polyhedron, by
  // enforcing topological closure, may have made different elements
  // comparable.
  x.reduced = false;
  assert(x.OK());
}

template <typename PH>
inline
Polyhedra_Powerset<PH>::Polyhedra_Powerset(const Constraint_System& cs)
  // FIXME: calling Base(Determinate<PH>(cs)) will automatically handle
  // the flag `reduced', but it will also force a non-emptiness test
  // on the constraint system `cs'.
  : Base(), space_dim(cs.space_dimension()) {
  Polyhedra_Powerset& x = *this;
  x.sequence.push_back(Determinate<PH>(cs));
  x.reduced = false;
  assert(x.OK());
}

template <typename PH>
inline
Polyhedra_Powerset<PH>::Polyhedra_Powerset(const Congruence_System& cgs)
  // FIXME: calling Base(Determinate<PH>(cgs)) will automatically handle
  // the flag `reduced', but it will also force a non-emptiness test
  // on the congruence system `cgs'.
  : Base(), space_dim(cgs.space_dimension()) {
  Polyhedra_Powerset& x = *this;
  x.sequence.push_back(Determinate<PH>(cgs));
  x.reduced = false;
  assert(OK());
}

template <typename PH>
inline Polyhedra_Powerset<PH>&
Polyhedra_Powerset<PH>::operator=(const Polyhedra_Powerset& y) {
  Polyhedra_Powerset& x = *this;
  x.Base::operator=(y);
  x.space_dim = y.space_dim;
  return x;
}

template <typename PH>
inline void
Polyhedra_Powerset<PH>::swap(Polyhedra_Powerset& y) {
  Polyhedra_Powerset& x = *this;
  x.Base::swap(y);
  std::swap(x.space_dim, y.space_dim);
}

template <typename PH>
template <typename QH>
inline Polyhedra_Powerset<PH>&
Polyhedra_Powerset<PH>::operator=(const Polyhedra_Powerset<QH>& y) {
  Polyhedra_Powerset& x = *this;
  Polyhedra_Powerset<PH> pps(y);
  x.swap(pps);
  return x;
}

template <typename PH>
inline void
Polyhedra_Powerset<PH>::intersection_assign(const Polyhedra_Powerset& y) {
  Polyhedra_Powerset& x = *this;
  x.pairwise_apply_assign
    (y, CS::lift_op_assign(std::mem_fun_ref(&PH::intersection_assign)));
}

template <typename PH>
inline void
Polyhedra_Powerset<PH>::time_elapse_assign(const Polyhedra_Powerset& y) {
  Polyhedra_Powerset& x = *this;
  x.pairwise_apply_assign
    (y, CS::lift_op_assign(std::mem_fun_ref(&PH::time_elapse_assign)));
}

template <typename PH>
inline bool
Polyhedra_Powerset<PH>
::geometrically_covers(const Polyhedra_Powerset& y) const {
  const Polyhedra_Powerset<NNC_Polyhedron> xx(*this);
  const Polyhedra_Powerset<NNC_Polyhedron> yy(y);
  return xx.geometrically_covers(yy);
}

template <typename PH>
inline bool
Polyhedra_Powerset<PH>
::geometrically_equals(const Polyhedra_Powerset& y) const {
  const Polyhedra_Powerset<NNC_Polyhedron> xx(*this);
  const Polyhedra_Powerset<NNC_Polyhedron> yy(y);
  return xx.geometrically_covers(yy) && yy.geometrically_covers(xx);
}

template <>
inline bool
Polyhedra_Powerset<NNC_Polyhedron>
::geometrically_equals(const Polyhedra_Powerset& y) const {
  const Polyhedra_Powerset& x = *this;
  return x.geometrically_covers(y) && y.geometrically_covers(x);
}

template <typename PH>
inline memory_size_type
Polyhedra_Powerset<PH>::external_memory_in_bytes() const {
  return Base::external_memory_in_bytes();
}

template <typename PH>
inline memory_size_type
Polyhedra_Powerset<PH>::total_memory_in_bytes() const {
  return sizeof(*this) + external_memory_in_bytes();
}

template <>
inline void
Polyhedra_Powerset<C_Polyhedron>
::poly_difference_assign(const Polyhedra_Powerset& y) {
  Polyhedra_Powerset<NNC_Polyhedron> nnc_this(*this);
  Polyhedra_Powerset<NNC_Polyhedron> nnc_y(y);
  nnc_this.poly_difference_assign(nnc_y);
  *this = nnc_this;
}

/*! \relates Polyhedra_Powerset */
template <typename PH>
inline bool
check_containment(const PH& ph, const Polyhedra_Powerset<PH>& ps) {
  const NNC_Polyhedron pph = NNC_Polyhedron(ph.constraints());
  const Polyhedra_Powerset<NNC_Polyhedron> pps(ps);
  return check_containment(pph, pps);
}

/*! \relates Polyhedra_Powerset */
template <>
inline bool
check_containment(const C_Polyhedron& ph,
		  const Polyhedra_Powerset<C_Polyhedron>& ps) {
  return check_containment(NNC_Polyhedron(ph),
			   Polyhedra_Powerset<NNC_Polyhedron>(ps));
}

} // namespace Parma_Polyhedra_Library


namespace std {

/*! \relates Parma_Polyhedra_Library::Polyhedra_Powerset */
template <typename PH>
inline void
swap(Parma_Polyhedra_Library::Polyhedra_Powerset<PH>& x,
     Parma_Polyhedra_Library::Polyhedra_Powerset<PH>& y) {
  x.swap(y);
}

} // namespace std

// Automatically generated from PPL source file ../src/Polyhedra_Powerset.templates.hh line 1
/* Polyhedra_Powerset class implementation: non-inline template functions.
*/


// Automatically generated from PPL source file ../src/Polyhedra_Powerset.templates.hh line 31
#include <algorithm>
#include <deque>
#include <string>
#include <iostream>
#include <sstream>
#include <stdexcept>

namespace Parma_Polyhedra_Library {

template <typename PH>
void
Polyhedra_Powerset<PH>::add_disjunct(const PH& ph) {
  Polyhedra_Powerset& x = *this;
  if (x.space_dimension() != ph.space_dimension()) {
    std::ostringstream s;
    s << "PPL::Polyhedra_Powerset<PH>::add_disjunct(ph):\n"
      << "this->space_dimension() == " << x.space_dimension() << ", "
      << "ph.space_dimension() == " << ph.space_dimension() << ".";
    throw std::invalid_argument(s.str());
  }
  x.sequence.push_back(Determinate<PH>(ph));
  x.reduced = false;
  assert(x.OK());
}

template <>
template <typename QH>
Polyhedra_Powerset<NNC_Polyhedron>
::Polyhedra_Powerset(const Polyhedra_Powerset<QH>& y)
  : Base(), space_dim(y.space_dimension()) {
  Polyhedra_Powerset& x = *this;
  for (typename Polyhedra_Powerset<QH>::const_iterator i = y.begin(),
	 y_end = y.end(); i != y_end; ++i)
    x.sequence.push_back(Determinate<NNC_Polyhedron>(
                           NNC_Polyhedron(i->element().constraints()))
			 );
  x.reduced = y.reduced;
  assert(x.OK());
}

template <>
template <typename QH>
Polyhedra_Powerset<C_Polyhedron>
::Polyhedra_Powerset(const Polyhedra_Powerset<QH>& y)
  : Base(), space_dim(y.space_dimension()) {
  Polyhedra_Powerset& x = *this;
  for (typename Polyhedra_Powerset<QH>::const_iterator i = y.begin(),
	 y_end = y.end(); i != y_end; ++i)
    x.sequence.push_back(Determinate<C_Polyhedron>(
                           C_Polyhedron(i->element().constraints()))
			 );
  // Note: this might be non-reduced even when `y' is known to be
  // omega-reduced, because the constructor of C_Polyhedron, by
  // enforcing topological closure, may have made different elements
  // comparable.
  x.reduced = false;
  assert(x.OK());
}

template <typename PH>
void
Polyhedra_Powerset<PH>::concatenate_assign(const Polyhedra_Powerset& y) {
  Polyhedra_Powerset& x = *this;
  // Ensure omega-reduction here, since what follows has quadratic complexity.
  x.omega_reduce();
  y.omega_reduce();
  Polyhedra_Powerset<PH> new_x(x.space_dim + y.space_dim, EMPTY);
  for (const_iterator xi = x.begin(), x_end = x.end(),
	 y_begin = y.begin(), y_end = y.end(); xi != x_end; ) {
    for (const_iterator yi = y_begin; yi != y_end; ++yi) {
      CS zi = *xi;
      zi.concatenate_assign(*yi);
      assert(!zi.is_bottom());
      new_x.sequence.push_back(zi);
    }
    ++xi;
    if (abandon_expensive_computations && xi != x_end && y_begin != y_end) {
      // Hurry up!
      PH xph = xi->element();
      for (++xi; xi != x_end; ++xi)
	xph.upper_bound_assign(xi->element());
      const_iterator yi = y_begin;
      PH yph = yi->element();
      for (++yi; yi != y_end; ++yi)
	yph.upper_bound_assign(yi->element());
      xph.concatenate_assign(yph);
      x.swap(new_x);
      x.add_disjunct(xph);
      assert(x.OK());
      return;
    }
  }
  x.swap(new_x);
  assert(x.OK());
}

template <typename PH>
void
Polyhedra_Powerset<PH>::add_constraint(const Constraint& c) {
  Polyhedra_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
	 s_end = x.sequence.end(); si != s_end; ++si)
    si->element().add_constraint(c);
  x.reduced = false;
  assert(x.OK());
}

template <typename PH>
bool
Polyhedra_Powerset<PH>::add_constraint_and_minimize(const Constraint& c) {
  Polyhedra_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
	 s_end = x.sequence.end(); si != s_end; )
    if (!si->element().add_constraint_and_minimize(c))
      si = x.sequence.erase(si);
    else {
      x.reduced = false;
      ++si;
    }
  assert(x.OK());
  return !x.empty();
}

template <typename PH>
void
Polyhedra_Powerset<PH>::add_constraints(const Constraint_System& cs) {
  Polyhedra_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
	 s_end = x.sequence.end(); si != s_end; ++si)
    si->element().add_constraints(cs);
  x.reduced = false;
  assert(x.OK());
}

template <typename PH>
bool
Polyhedra_Powerset<PH>::
add_constraints_and_minimize(const Constraint_System& cs) {
  Polyhedra_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
	 s_end = x.sequence.end(); si != s_end; )
    if (!si->element().add_constraints_and_minimize(cs))
      si = x.sequence.erase(si);
    else {
      x.reduced = false;
      ++si;
    }
  assert(x.OK());
  return !x.empty();
}

template <typename PH>
void
Polyhedra_Powerset<PH>::add_space_dimensions_and_embed(dimension_type m) {
  Polyhedra_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
	 s_end = x.sequence.end(); si != s_end; ++si)
    si->element().add_space_dimensions_and_embed(m);
  x.space_dim += m;
  assert(x.OK());
}

template <typename PH>
void
Polyhedra_Powerset<PH>::add_space_dimensions_and_project(dimension_type m) {
  Polyhedra_Powerset& x = *this;
  for (Sequence_iterator si = x.sequence.begin(),
	 s_end = x.sequence.end(); si != s_end; ++si)
    si->element().add_space_dimensions_and_project(m);
  x.space_dim += m;
  assert(x.OK());
}

template <typename PH>
void
Polyhedra_Powerset<PH>::
remove_space_dimensions(const Variables_Set& to_be_removed) {
  Polyhedra_Powerset& x = *this;
  Variables_Set::size_type num_removed = to_be_removed.size();
  if (num_removed > 0) {
    for (Sequence_iterator si = x.sequence.begin(),
	   s_end = x.sequence.end(); si != s_end; ++si) {
      si->element().remove_space_dimensions(to_be_removed);
      x.reduced = false;
    }
    x.space_dim -= num_removed;
    assert(x.OK());
  }
}

template <typename PH>
void
Polyhedra_Powerset<PH>::remove_higher_space_dimensions(dimension_type
						       new_dimension) {
  Polyhedra_Powerset& x = *this;
  if (new_dimension < x.space_dim) {
    for (Sequence_iterator si = x.sequence.begin(),
	   s_end = x.sequence.end(); si != s_end; ++si) {
      si->element().remove_higher_space_dimensions(new_dimension);
      x.reduced = false;
    }
    x.space_dim = new_dimension;
    assert(x.OK());
  }
}

template <typename PH>
template <typename Partial_Function>
void
Polyhedra_Powerset<PH>::map_space_dimensions(const Partial_Function& pfunc) {
  Polyhedra_Powerset& x = *this;
  if (x.is_bottom()) {
    dimension_type n = 0;
    for (dimension_type i = x.space_dim; i-- > 0; ) {
      dimension_type new_i;
      if (pfunc.maps(i, new_i))
	++n;
    }
    x.space_dim = n;
  }
  else {
    Sequence_iterator s_begin = x.sequence.begin();
    for (Sequence_iterator si = s_begin,
	   s_end = x.sequence.end(); si != s_end; ++si)
      si->element().map_space_dimensions(pfunc);
    x.space_dim = s_begin->element().space_dimension();
    x.reduced = false;
  }
  assert(x.OK());
}

template <typename PH>
void
Polyhedra_Powerset<PH>::pairwise_reduce() {
  Polyhedra_Powerset& x = *this;
  // It is wise to omega-reduce before pairwise-reducing.
  x.omega_reduce();

  size_type n = x.size();
  size_type deleted;
  do {
    Polyhedra_Powerset new_x(x.space_dim, EMPTY);
    std::deque<bool> marked(n, false);
    deleted = 0;
    Sequence_iterator s_begin = x.sequence.begin();
    Sequence_iterator s_end = x.sequence.end();
    unsigned si_index = 0;
    for (Sequence_iterator si = s_begin; si != s_end; ++si, ++si_index) {
      if (marked[si_index])
	continue;
      PH& pi = si->element();
      Sequence_const_iterator sj = si;
      unsigned sj_index = si_index;
      for (++sj, ++sj_index; sj != s_end; ++sj, ++sj_index) {
	if (marked[sj_index])
	  continue;
	const PH& pj = sj->element();
	if (pi.upper_bound_assign_if_exact(pj)) {
	  marked[si_index] = marked[sj_index] = true;
	  new_x.add_non_bottom_disjunct(pi);
	  ++deleted;
	  goto next;
	}
      }
    next:
      ;
    }
    iterator nx_begin = new_x.begin();
    iterator nx_end = new_x.end();
    unsigned xi_index = 0;
    for (const_iterator xi = x.begin(),
	   x_end = x.end(); xi != x_end; ++xi, ++xi_index)
      if (!marked[xi_index])
	nx_begin = new_x.add_non_bottom_disjunct(*xi, nx_begin, nx_end);
    std::swap(x.sequence, new_x.sequence);
    n -= deleted;
  } while (deleted > 0);
  assert(x.OK());
}

template <typename PH>
template <typename Widening>
void
Polyhedra_Powerset<PH>::
BGP99_heuristics_assign(const Polyhedra_Powerset& y, Widening wf) {
  // `x' is the current iteration value.
  Polyhedra_Powerset& x = *this;

#ifndef NDEBUG
  {
    // We assume that `y' entails `x'.
    const Polyhedra_Powerset<PH> x_copy = x;
    const Polyhedra_Powerset<PH> y_copy = y;
    assert(y_copy.definitely_entails(x_copy));
  }
#endif

  size_type n = x.size();
  Polyhedra_Powerset new_x(x.space_dim, EMPTY);
  std::deque<bool> marked(n, false);
  const_iterator x_begin = x.begin();
  const_iterator x_end = x.end();
  unsigned i_index = 0;
  for (const_iterator i = x_begin,
	 y_begin = y.begin(), y_end = y.end(); i != x_end; ++i, ++i_index)
    for (const_iterator j = y_begin; j != y_end; ++j) {
      const PH& pi = i->element();
      const PH& pj = j->element();
      if (pi.contains(pj)) {
	PH pi_copy = pi;
	wf(pi_copy, pj);
	new_x.add_non_bottom_disjunct(pi_copy);
	marked[i_index] = true;
      }
    }
  iterator nx_begin = new_x.begin();
  iterator nx_end = new_x.end();
  i_index = 0;
  for (const_iterator i = x_begin; i != x_end; ++i, ++i_index)
    if (!marked[i_index])
      nx_begin = new_x.add_non_bottom_disjunct(*i, nx_begin, nx_end);
  std::swap(x.sequence, new_x.sequence);
  assert(x.OK());
  assert(x.is_omega_reduced());
}

template <typename PH>
template <typename Widening>
void
Polyhedra_Powerset<PH>::
BGP99_extrapolation_assign(const Polyhedra_Powerset& y,
			   Widening wf,
			   unsigned max_disjuncts) {
  // `x' is the current iteration value.
  Polyhedra_Powerset& x = *this;

#ifndef NDEBUG
  {
    // We assume that `y' entails `x'.
    const Polyhedra_Powerset<PH> x_copy = x;
    const Polyhedra_Powerset<PH> y_copy = y;
    assert(y_copy.definitely_entails(x_copy));
  }
#endif

  x.pairwise_reduce();
  if (max_disjuncts != 0)
    x.collapse(max_disjuncts);
  x.BGP99_heuristics_assign(y, wf);
}

template <typename PH>
template <typename Cert>
void
Polyhedra_Powerset<PH>::
collect_certificates(std::map<Cert, size_type,
		              typename Cert::Compare>& cert_ms) const {
  const Polyhedra_Powerset& x = *this;
  assert(x.is_omega_reduced());
  assert(cert_ms.size() == 0);
  for (const_iterator i = x.begin(), end = x.end(); i != end; i++) {
    Cert ph_cert(i->element());
    ++cert_ms[ph_cert];
  }
}

template <typename PH>
template <typename Cert>
bool
Polyhedra_Powerset<PH>::
is_cert_multiset_stabilizing(const std::map<Cert, size_type,
			                    typename Cert::Compare>& y_cert_ms
			     ) const {
  typedef std::map<Cert, size_type, typename Cert::Compare> Cert_Multiset;
  Cert_Multiset x_cert_ms;
  collect_certificates(x_cert_ms);
  typename Cert_Multiset::const_iterator
    xi = x_cert_ms.begin(),
    xend = x_cert_ms.end(),
    yi = y_cert_ms.begin(),
    yend = y_cert_ms.end();
  while (xi != xend && yi != yend) {
    const Cert& xi_cert = xi->first;
    const Cert& yi_cert = yi->first;
    switch (xi_cert.compare(yi_cert)) {
    case 0:
      // xi_cert == yi_cert: check the number of multiset occurrences.
      {
	const size_type& xi_count = xi->second;
	const size_type& yi_count = yi->second;
	if (xi_count == yi_count) {
	  // Same number of occurrences: compare the next pair.
	  ++xi;
	  ++yi;
	}
	else
	  // Different number of occurrences: can decide ordering.
	  return xi_count < yi_count;
	break;
      }
    case 1:
      // xi_cert > yi_cert: it is not stabilizing.
      return false;

    case -1:
      // xi_cert < yi_cert: it is stabilizing.
      return true;
    }
  }
  // Here xi == xend or yi == yend.
  // Stabilization is achieved if `y_cert_ms' still has other elements.
  return yi != yend;
}

template <typename PH>
template <typename Cert, typename Widening>
void
Polyhedra_Powerset<PH>::BHZ03_widening_assign(const Polyhedra_Powerset& y,
					      Widening wf) {
  // `x' is the current iteration value.
  Polyhedra_Powerset& x = *this;

#ifndef NDEBUG
  {
    // We assume that `y' entails `x'.
    const Polyhedra_Powerset<PH> x_copy = x;
    const Polyhedra_Powerset<PH> y_copy = y;
    assert(y_copy.definitely_entails(x_copy));
  }
#endif

  // First widening technique: do nothing.

  // If `y' is the empty collection, do nothing.
  assert(x.size() > 0);
  if (y.size() == 0)
    return;

  // Compute the poly-hull of `x'.
  PH x_hull(x.space_dim, EMPTY);
  for (const_iterator i = x.begin(), x_end = x.end(); i != x_end; ++i)
    x_hull.upper_bound_assign(i->element());

  // Compute the poly-hull of `y'.
  PH y_hull(y.space_dim, EMPTY);
  for (const_iterator i = y.begin(), y_end = y.end(); i != y_end; ++i)
    y_hull.upper_bound_assign(i->element());
  // Compute the certificate for `y_hull'.
  const Cert y_hull_cert(y_hull);

  // If the hull is stabilizing, do nothing.
  int hull_stabilization = y_hull_cert.compare(x_hull);
  if (hull_stabilization == 1)
    return;

  // Multiset ordering is only useful when `y' is not a singleton.
  const bool y_is_not_a_singleton = y.size() > 1;

  // The multiset certificate for `y':
  // we want to be lazy about its computation.
  typedef std::map<Cert, size_type, typename Cert::Compare> Cert_Multiset;
  Cert_Multiset y_cert_ms;
  bool y_cert_ms_computed = false;

  if (hull_stabilization == 0 && y_is_not_a_singleton) {
    // Collect the multiset certificate for `y'.
    y.collect_certificates(y_cert_ms);
    y_cert_ms_computed = true;
    // If multiset ordering is stabilizing, do nothing.
    if (x.is_cert_multiset_stabilizing(y_cert_ms))
      return;
  }

  // Second widening technique: try the BGP99 powerset heuristics.
  Polyhedra_Powerset<PH> bgp99_heuristics = x;
  bgp99_heuristics.BGP99_heuristics_assign(y, wf);

  // Compute the poly-hull of `bgp99_heuristics'.
  PH bgp99_heuristics_hull(x.space_dim, EMPTY);
  for (const_iterator i = bgp99_heuristics.begin(),
	 bh_end = bgp99_heuristics.end(); i != bh_end; ++i)
    bgp99_heuristics_hull.upper_bound_assign(i->element());

  // Check for stabilization and, if successful,
  // commit to the result of the extrapolation.
  hull_stabilization = y_hull_cert.compare(bgp99_heuristics_hull);
  if (hull_stabilization == 1) {
    // The poly-hull is stabilizing.
    std::swap(x, bgp99_heuristics);
    return;
  }
  else if (hull_stabilization == 0 && y_is_not_a_singleton) {
    // If not already done, compute multiset certificate for `y'.
    if (!y_cert_ms_computed) {
      y.collect_certificates(y_cert_ms);
      y_cert_ms_computed = true;
    }
    if (bgp99_heuristics.is_cert_multiset_stabilizing(y_cert_ms)) {
      std::swap(x, bgp99_heuristics);
      return;
    }
    // Third widening technique: pairwise-reduction on `bgp99_heuristics'.
    // Note that pairwise-reduction does not affect the computation
    // of the poly-hulls, so that we only have to check the multiset
    // certificate relation.
    Polyhedra_Powerset<PH> reduced_bgp99_heuristics(bgp99_heuristics);
    reduced_bgp99_heuristics.pairwise_reduce();
    if (reduced_bgp99_heuristics.is_cert_multiset_stabilizing(y_cert_ms)) {
      std::swap(x, reduced_bgp99_heuristics);
      return;
    }
  }

  // Fourth widening technique: this is applicable only when
  // `y_hull' is a proper subset of `bgp99_heuristics_hull'.
  if (bgp99_heuristics_hull.strictly_contains(y_hull)) {
    // Compute (y_hull \widen bgp99_heuristics_hull).
    PH ph = bgp99_heuristics_hull;
    wf(ph, y_hull);
    // Compute the difference between `ph' and `bgp99_heuristics_hull'.
    ph.difference_assign(bgp99_heuristics_hull);
    x.add_disjunct(ph);
    return;
  }

  // Fall back to the computation of the poly-hull.
  Polyhedra_Powerset<PH> x_hull_singleton(x.space_dim, EMPTY);
  x_hull_singleton.add_disjunct(x_hull);
  std::swap(x, x_hull_singleton);
}

template <typename PH>
void
Polyhedra_Powerset<PH>::ascii_dump(std::ostream& s) const {
  const Polyhedra_Powerset& x = *this;
  s << "size " << x.size()
    << "\nspace_dim " << x.space_dim
    << "\n";
  for (const_iterator xi = x.begin(), x_end = x.end(); xi != x_end; ++xi)
    xi->element().ascii_dump(s);
}

PPL_OUTPUT_TEMPLATE_DEFINITIONS(PH, Polyhedra_Powerset<PH>);

template <typename PH>
bool
Polyhedra_Powerset<PH>::ascii_load(std::istream& s) {
  Polyhedra_Powerset& x = *this;
  std::string str;

  if (!(s >> str) || str != "size")
    return false;

  size_type sz;

  if (!(s >> sz))
    return false;

  if (!(s >> str) || str != "space_dim")
    return false;

  if (!(s >> x.space_dim))
    return false;

  Polyhedra_Powerset new_x(x.space_dim, EMPTY);
  while (sz-- > 0) {
    PH ph;
    if (!ph.ascii_load(s))
      return false;
    new_x.add_disjunct(ph);
  }
  x.swap(new_x);

  // Check for well-formedness.
  assert(x.OK());
  return true;
}

template <typename PH>
bool
Polyhedra_Powerset<PH>::OK() const {
  const Polyhedra_Powerset& x = *this;
  for (const_iterator xi = x.begin(), x_end = x.end(); xi != x_end; ++xi) {
    const PH& pi = xi->element();
    if (pi.space_dimension() != x.space_dim) {
#ifndef NDEBUG
      std::cerr << "Space dimension mismatch: is " << pi.space_dimension()
		<< " in an element of the sequence,\nshould be "
		<< x.space_dim << "."
		<< std::endl;
#endif
      return false;
    }
  }
  return x.Base::OK();
}


namespace Implementation {

namespace Polyhedra_Powersets {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
//! Partitions polyhedron \p qq according to constraint \p c.
/*! \relates Parma_Polyhedra_Library::Polyhedra_Powerset
  On exit, the intersection of \p qq and constraint \p c is stored
  in \p qq, whereas the intersection of \p qq with the negation of \p c
  is added as a new disjunct of the powerset \p r.
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename PH>
void
linear_partition_aux(const Constraint& c,
		     PH& qq,
		     Polyhedra_Powerset<NNC_Polyhedron>& r) {
  Linear_Expression le(c);
  Constraint neg_c = c.is_strict_inequality() ? (le <= 0) : (le < 0);
  NNC_Polyhedron qqq(qq);
  if (qqq.add_constraint_and_minimize(neg_c))
    r.add_disjunct(qqq);
  qq.add_constraint(c);
}

} // namespace Polyhedra_Powersets

} // namespace Implementation


/*! \relates Polyhedra_Powerset */
template <typename PH>
std::pair<PH, Polyhedra_Powerset<NNC_Polyhedron> >
linear_partition(const PH& p, const PH& q) {
  using Implementation::Polyhedra_Powersets::linear_partition_aux;

  Polyhedra_Powerset<NNC_Polyhedron> r(p.space_dimension(), EMPTY);
  PH qq = q;
  const Constraint_System& pcs = p.constraints();
  for (Constraint_System::const_iterator i = pcs.begin(),
	 pcs_end = pcs.end(); i != pcs_end; ++i) {
    const Constraint c = *i;
    if (c.is_equality()) {
      Linear_Expression le(c);
      linear_partition_aux(le <= 0, qq, r);
      linear_partition_aux(le >= 0, qq, r);
    }
    else
      linear_partition_aux(c, qq, r);
  }
  return std::pair<PH, Polyhedra_Powerset<NNC_Polyhedron> >(qq, r);
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/Polyhedra_Powerset.defs.hh line 552

// Automatically generated from PPL source file ../src/max_space_dimension.hh line 1
/* Definition of functions yielding maximal space dimensions.
*/


// Automatically generated from PPL source file ../src/max_space_dimension.hh line 30
#include <algorithm>

namespace Parma_Polyhedra_Library {

//! Returns the maximum space dimension this library can handle.
inline dimension_type
max_space_dimension() {
  using std::min;
  return
    min(Polyhedron::max_space_dimension(),
	min(Polyhedra_Powerset<C_Polyhedron>::max_space_dimension(),
	    Polyhedra_Powerset<NNC_Polyhedron>::max_space_dimension()
	    )
	);
}

} // namespace Parma_Polyhedra_Library

// Automatically generated from PPL source file ../src/algorithms.hh line 1
/* A collection of useful convex polyhedra algorithms: inline functions.
*/


// Automatically generated from PPL source file ../src/algorithms.hh line 28
#include <utility>
#include <cassert>

namespace Parma_Polyhedra_Library {

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \brief
  If the poly-hull of \p p and \p q is exact it is assigned
  to \p p and <CODE>true</CODE> is returned,
  otherwise <CODE>false</CODE> is returned.

  \relates Polyhedron
*/
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename PH>
bool
poly_hull_assign_if_exact(PH& p, const PH& q);

#ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
/*! \relates Polyhedron */
#endif // PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS
template <typename PH>
bool
poly_hull_assign_if_exact(PH& p, const PH& q) {
  PH phull = p;
  NNC_Polyhedron nnc_p(p);
  phull.poly_hull_assign(q);
  std::pair<PH, Polyhedra_Powerset<NNC_Polyhedron> >
    partition = linear_partition(q, phull);
  const Polyhedra_Powerset<NNC_Polyhedron>& s = partition.second;
  typedef Polyhedra_Powerset<NNC_Polyhedron>::const_iterator iter;
  for (iter i = s.begin(), s_end = s.end(); i != s_end; ++i)
    // The polyhedral hull is exact if and only if all the elements
    // of the partition of the polyhedral hull of `p' and `q' with
    // respect to `q' are included in `p'
    if (!nnc_p.contains(i->element()))
      return false;
  p = phull;
  return true;
}

} // namespace Parma_Polyhedra_Library


#ifdef PPL_SAVE_NDEBUG
# define NDEBUG 1
# undef PPL_SAVE_NDEBUG
#else
# undef NDEBUG
#endif
#include <cassert>

#undef PACKAGE
#undef PACKAGE_BUGREPORT
#undef PACKAGE_NAME
#undef PACKAGE_STRING
#undef PACKAGE_TARNAME
#undef PACKAGE_VERSION
#undef VERSION

#endif
